【发布时间】:2011-09-02 17:38:19
【问题描述】:
我正在尝试使用 Qt 创建一个图像保存应用程序。现在是存根
class ImageSaver:public QObject
{
int index;
QWebPage * main_Page;
QNetworkAccessManager * manager;
QNetworkReply * reply;
QString file_Name;
QSet<QString> image_Addresses;
QString web_Address;
Q_OBJECT
signals:
void image_Saved();
public slots:
void request_Image();
void on_Finished(bool status);
void got_Reply(QNetworkReply * reply);
public:
ImageSaver();
void start();
};
ImageSaver::ImageSaver()
{
index = 0;
manager = new QNetworkAccessManager;
reply = NULL;
connect(main_Page,SIGNAL(loadFinished(bool)),this,SLOT(on_Finished(bool)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(got_Reply(QNetworkReply*)));
connect(this,SIGNAL(image_Saved()),this,SLOT(request_Image()));
}
void ImageSaver::start()
{
//loads the url
// In the end of the loading it will emit load_Finished(bool)
// So that signal will execute on_Finished(bool)
}
void ImageSaver::request_Image()
{
QString temp_Address = *(image_Addresses.begin()+index);
//makes a request to the server to give the image "temp_Address"
//When the server gives the reply signal finished(QNetworkReply*) will be emitted
// this in turn will call the got_Reply(QNetworkReply*)
}
void ImageSaver::on_Finished(bool status)
{
//collects all the images's url addresses, and pushes them in the list
//"image_Addresses"
//Then emits image_Saved();
//This signal will wake up the function request_Image()
}
void ImageSaver::got_Reply(QNetworkReply * reply)
{
//Image is extracted from the reply and got saved in the same name as in the page
//index got increased;
//emits the signal image_Saved();
//This signal will activate the function request_Image()
}
int main(int argc,char * argv[])
{
QApplication app(argc,argv);
ImageSaver a;
a.start();
return app.exec();
}
#include "main.moc"
简而言之,第一次调用是“开始”。那调用“on_Finished”,直到这个没有问题。因此,所有图像文件的地址都被推送到列表中。接下来是对 image[i] 的一一请求,并保存回复图像。这种事情反复发生。在这里只有我遇到问题。此操作中出现崩溃,尤其是在保存图像时。
我的假设是“信号槽”不像函数调用,你或多或少像线程,但在同一个函数(指针)上运行。因此,当一个信号请求painter,它已经在渲染某些东西时,就会出现崩溃。
谁能说出崩溃背后的事实以及如何在不崩溃的情况下保存所有图像?
编辑: 你好,这是完整的代码。运行这个,连续点击消息框
#include <QApplication>
#include <QDir>
#include <QImage>
#include <QObject>
#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QSet>
#include <QTimer>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtWebKit/QWebElement>
#include <QtWebKit/QWebFrame>
#include <QtWebKit/QWebPage>
#include <QUrl>
class ImageSaver:public QObject
{
int index;
QWebPage * main_Page;
QNetworkAccessManager * manager;
QNetworkReply * reply;
QString file_Name;
QSet<QString> image_Addresses;
QString web_Address;
Q_OBJECT
signals:
void image_Saved();
public slots:
void request_Image();
void on_Finished(bool status);
void got_Reply(QNetworkReply * reply);
public:
ImageSaver();
void start();
protected:
//void show_Frame(QWebFrame * frame);
};
ImageSaver::ImageSaver()
{
index = 0;
this->main_Page = new QWebPage;
manager = new QNetworkAccessManager;
reply = NULL;
connect(main_Page,SIGNAL(loadFinished(bool)),this,SLOT(on_Finished(bool)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(got_Reply(QNetworkReply*)));
connect(this,SIGNAL(image_Saved()),this,SLOT(request_Image()));
}
void ImageSaver::start()
{
web_Address = "yahoo.com";
QDir dir;
dir.mkdir(web_Address);
QUrl url = QUrl::fromUserInput(web_Address);
main_Page->mainFrame()->load(url);
}
void ImageSaver::request_Image()
{
QString temp_Address = *(image_Addresses.begin()+index);
int a = temp_Address.lastIndexOf("/");
file_Name = temp_Address.mid(a+1);
//Without the below message box, the program closes shortly
//This message box is slowing down that effect
QMessageBox hh;
hh.setText(file_Name);
hh.exec();
QNetworkRequest request= QNetworkRequest(QUrl(temp_Address));
request.setRawHeader("img","src");
manager->get(request);
}
void ImageSaver::on_Finished(bool status)
{
if(status)
{
QMessageBox mm;
mm.setText("Finished");
mm.exec();
QWebElementCollection temp_Collection= main_Page->mainFrame()->findAllElements("*");
for(int i=0;i<temp_Collection.count();++i)
{
QWebElement temp_Element = temp_Collection[i];
if(temp_Element.tagName().contains("img",Qt::CaseInsensitive) && temp_Element.attributeNames().contains("src",Qt::CaseInsensitive))
{
QString image_Web_Address = temp_Element.attribute("src");
if(!image_Addresses.contains(image_Web_Address))
image_Addresses.insert(image_Web_Address);
}
}
emit image_Saved();
QMessageBox kk;
kk.setText("Image is going to be saved");
kk.exec();
}
else
{
QMessageBox mm;
mm.setText("Not ready");
mm.exec();
}
QMessageBox mm;
mm.setText("Getting out of finished");
mm.exec();
}
void ImageSaver::got_Reply(QNetworkReply * reply)
{
QImage image;
if(image.load(static_cast<QIODevice *>(reply),0))
image.save(web_Address+QDir::separator()+file_Name,0);
++index;
emit image_Saved();
}
/*
void ImageSaver::show_Frame(QWebFrame * temp_Frame)
{
QImage image(temp_Frame->contentsSize(),QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setRenderHint(QPainter::TextAntialiasing,true);
painter.setRenderHint(QPainter::SmoothPixmapTransform,true);
temp_Frame->documentElement().render(&painter);
painter.end();
foreach(QWebFrame * temp_Frame0,temp_Frame->childFrames())
show_Frame(temp_Frame0);
}
*/
int main(int argc,char * argv[])
{
QApplication app(argc,argv);
ImageSaver a;
a.start();
return app.exec();
}
#include "main.moc"
这是专业文件
QT += webkit network
SOURCES += \
main.cpp
【问题讨论】:
-
哪里崩溃了?有消息吗?您应该提供一个完整的最小示例来演示该行为。插槽就像一个函数调用,信号只是稍后(在事件循环期间)调用插槽的一种方式。为什么要将算法拆分为多个插槽并不明显。我会尝试将整个过程放在一个插槽中,看看你是否仍然崩溃。
-
从您当前的示例来看,您正在使用默认方法连接信号和插槽。这是一个直接连接,这意味着您实际上只是在进行函数调用。这里没有多线程,除非你在我们看不到的地方做一些线程。 Tom K 引用了“排队连接”,但它看起来不像你正在做的事情。看到这个:doc.qt.nokia.com/latest/…
-
如果崩溃,请提供回溯。您对信号/插槽的假设是错误的,它们是正常的方法调用,不涉及多线程。
-
@Tom 尝试编辑中的代码。如果您说如何将整个过程放在一个插槽中,我将非常感谢您。
-
我认为您崩溃的原因如下。然而,像这样使用 msgboxes 调试代码是危险的:如果有一个网络操作挂起并且您打开一个消息框,则 msgbox 将在 exec 中打开一个本地事件循环。如果在对话框打开时网络操作返回,则被调用的插槽将更改应用程序的状态。关闭对话框后,将执行 exec() 之后的代码,并且由于介于两者之间的网络操作调用的插槽,在 exec() 之前可以做出的任何假设都不再有效。最好不要在这样的上下文中使用阻塞 exec() 调用。