等待信号

11

我正在开发一个应用程序,它会将文件内容上传到服务器。

为了将文件上传到服务器,我使用了 'QNetworkAccessManager' 类。由于它以异步方式工作,所以我使用 QEventLoop 将其改为同步方式。

Class FileTransfer
{
Public : 
     QNetworkAccessManager mNetworkManager;
     Void Upload(QNetworkRequest request, QIODevice *data)
     {
           responce = mNetworkManager.put(request, data);
           EventLoop.exec();
           ReadResponce(responce);
      }

      Void Stop()
      {
            responce ->close();
      }
}
在我的示例应用程序中,我有两个窗口。第一个窗口用于选择文件,第二个窗口用于显示进度。
当用户在第一个窗口中点击上传按钮时,将显示第二个窗口,然后我创建 FileTransfer 对象并开始上传。
在上传文件的过程中,如果用户关闭了窗体,则在窗口的析构函数中调用 'FileTransfer' 的停止方法,之后删除 'FileTransfer' 对象。
但此时 Upload() 函数尚未完成,因此程序将崩溃。
请帮助我解决以下问题: 如何在 'stop()' 函数中等待 Upload() 函数完成。
3个回答

19

从您的代码中可以看出,您正在执行一个QEventLoop,但实际上并没有将其“quit”槽连接到任何信号。以下是一个示例,login是一个QHttp - 代码来自不同的地方 - 但原则适用。

/* Create the QEventLoop */
QEventLoop pause;
/* connect the QHttp.requestFinished() Signal to the QEventLoop.quit() Slot */
connect(&login, SIGNAL(requestFinished( int, bool )), &pause, SLOT(quit()));
/* The code that will run during the QEventLoop */
login.request(header,&logmein,&result);
/* Execute the QEventLoop - it will quit when the above finished due to the connect() */
pause.exec();

如果我没记错的话,这个可以应用到你的代码中,像这样...

/* connect the signal to the relevant slot */
connect(&mNetworkManager, SIGNAL(finished( QNetworkReply )), &EventLoop, SLOT(quit()));
/* Execute the code that will run during QEventLoop */
responce = mNetworkManager.put(request, data);
/* Execute the QEventLoop */
EventLoop.exec();

如果我误解了你的问题,我很抱歉!我刚刚重新开始学习qt,可能有点不熟悉,但我相信这就是你想要的!祝你好运!


是的,我已经添加了代码以尽快退出事件循环,一旦我们得到完成插槽。但问题在于,如果用户在下载文件时停止连接并删除对象,则会崩溃,而上传功能尚未完成。此时它将崩溃。 - Umesha MS

0

个人而言,我建议不要使用这些答案中的任何一个。

只需将倒计时门闩连接到信号即可。

因此,您可以编写以下代码:

Latch latch( 1 );
QObject::connect( reply, SIGNAL(finished()),
                  &latch, SLOT(countDown()) );

latch.wait();

为此,您需要一个包装器:

class Latch : public QObject {
    Q_OBJECT
public:
    Latch( uint count );
    void wait();
public slots:
    void countDown();
private:
    gcl::countdown_latch _latch;
};

我可能错了,但我认为这不会起作用,因为gcl倒计时门闩是用于阻塞线程的。put()调用发生在主GUI线程中,然后QNetworkAccessManager在单独的线程中获取网页,并且finished()槽在主GUI线程中执行。因此,使用此代码与示例将导致整个应用程序锁定。将finished槽移动到另一个线程是可能的,但这需要更多未在此处显示的代码。 - Ph0t0n

0

我认为你需要在上传函数中添加类似这样的内容:

if (upf->openFile())
{
    reply = manager->post(request, upf);
    connect(reply, SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(progress(qint64,qint64)));
    connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
    isInProgress = true;
    emit started();
} else
{
    emit finished(true, false, tr("Error: can't open file %1").arg(filename));
}

这是完整的代码文本:datacod-qt-tools

希望它能帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接