信号槽弄得一团糟

发布于 2024-12-02 20:06:24 字数 6584 浏览 0 评论 0原文

我正在尝试使用 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"

简而言之,第一个调用是“start”。调用“on_Finished”,在此之前没有问题。所以所有图像文件的地址都被推入列表中。接下来是对 image[i] 的一一请求,并且回复图像已保存。这种事情屡屡发生。只有我遇到问题。在此操作中尤其是在保存图像时会出现崩溃。

我的假设是“信号槽”不像函数调用,它们或多或少像线程但在相同的函数(指针)上操作。因此,当一个信号请求画家时,画家已经在渲染某些东西,那么就会出现崩溃。

有人能说出崩溃背后的事实以及如何在不崩溃的情况下保存所有图像吗?

编辑: 你好,这是完整的代码。运行这个,然后连续单击消息框

    #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"

这是 pro 文件

QT += webkit network

SOURCES += \
    main.cpp

I am trying to create a image-saving application using Qt. Now the stub

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"

In short First call is to "start".That calls "on_Finished" and there is no problem untill this. So all the image files's addresses got pushed in the list. Next is one by one request for image[i] made, and the reply image got saved. This thing is happening repeatedly. Here only I am getting problem. Crashes are appearing in this operation especially in saving the image.

My assumption is "signal-slot" is not like function call, thy are more or less like thread but operates on the same function( pointer). So when one signal requests for painter, which is already rendering something then the crash will appear.

Can anybody say the fact behind the crash and how to save all the images without crash?

EDIT:
Hi, This is the full code. Run this one, and click the message boxes contineously

    #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"

This is the pro file

QT += webkit network

SOURCES += \
    main.cpp

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

西瑶 2024-12-09 20:06:24

您的代码崩溃是因为您读取的内容超出了 image_Addresses 集的边界。

void ImageSaver::request_Image()
{
    QString temp_Address = *(image_Addresses.begin()+index);
    ...

您在收到每个图像后递增索引,但代码中没有任何地方检查索引是否仍然小于 image_Addresses.size(),因此一旦取消引用 image_Addresses.begin()+index for index == image_Addresses.size,它就会崩溃()。

Your code crashes because you read beyond the boundaries of the image_Addresses set.

void ImageSaver::request_Image()
{
    QString temp_Address = *(image_Addresses.begin()+index);
    ...

You increment index after every image received, but there isn't any check anywhere in the code whether index is still less than image_Addresses.size(), so it crashes once dereferencing image_Addresses.begin()+index for index == image_Addresses.size().

困倦 2024-12-09 20:06:24

这个问题可能有很多解决方案。我认为您应该看看状态机框架。在简单的情况下,您可以仅使用布尔变量来检查是否可以继续。您还应该考虑当您忙于处理图像时该怎么办。您可以对请求进行排队或直接拒绝它们。您还可以实现线程,以便新的请求由新的线程提供服务。

PS 信号对我来说更像是事件而不是线程。

There may be many solutions to this problem. I think that you should have a look at The State Machine Framework. In easy situations you can just use boolean variable to check if you can go on. You should also think what to do when you're busy processing the image. You can queue request or just reject them. Also you can implement threading, so that new requests are served by new threads.

P.S. Signals are more like events than threads to me.

悲歌长辞 2024-12-09 20:06:24

错误是什么?为什么末尾有 #include

仅供参考,您可以使用一个 QImage 类,其中包括从 QIODevice*(例如 QNetworkReply)保存和加载。在 Qt 这个庞大的框架中,很少需要重新发明轮子。

What's the error and why do you have a #include at the end?

FYI there is a QImage class you can use instead which includes saving and loading from a QIODevice* such as QNetworkReply for example. It's extremely rare to need to reinvent the wheel in the massive framework that is Qt.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文