QThread 中的 Qt 信号和槽

Posted

技术标签:

【中文标题】QThread 中的 Qt 信号和槽【英文标题】:Qt Signals and slots in a QThread 【发布时间】:2012-11-03 17:43:18 【问题描述】:

我目前在 Qt 线程上遇到问题。

我必须在 QThread 中上传文件列表,但显然一次上传不起作用和/或我的插槽从未被调用。如果我把方法放在线程之外,它就可以完美地工作。

这里是 run() 方法:

void UploadThread::run()

    for (int i = 0; i < Window::_listUpload.size(); i++) 
        qDebug() << Window::_listUpload[i].getPath();
        this->sendFile(Window::_listUpload[i].getPath());
    

这里是 sendFile() 方法:

void UploadThread::sendFile(const QString & path)

    QFreeDesktopMime mime;
    QNetworkAccessManager *manager = new QNetworkAccessManager;
    QFileInfo fInfo(path);
    QNetworkRequest request(QUrl("http://my-url/"));
    QNetworkReply *reply;

    QString bound = "---------------------------723690991551375881941828858";
    QByteArray data(QString("--"+bound+"\r\n").toAscii());
    data += "Content-Disposition: form-data; name=\"action\"\r\n\r\n";
    data += "\r\n";
    data += QString("--" + bound + "\r\n").toAscii();
    data += "Content-Disposition: form-data; name=\"file\"; filename=\""+fInfo.fileName()+"\"\r\n";
    data += "Content-Type: "+mime.fromFile(path)+"\r\n\r\n";

    QFile file(fInfo.absoluteFilePath());
    file.open(QIODevice::ReadOnly);
    data += file.readAll();
    data += "\r\n";
    data += QString("--" + bound + "\r\n").toAscii();
    data += QString("--" + bound + "\r\n").toAscii();
    data += "Content-Disposition: form-data; name=\"desc\"\r\n\r\n";
    data += "Description for my image here :)\r\n";
    data += "\r\n";
    request.setRawHeader(QString("Accept-Encoding").toAscii(), QString("gzip,deflate").toAscii());
    request.setRawHeader(QString("Content-Type").toAscii(),QString("multipart/form-data; boundary=" + bound).toAscii());
    request.setRawHeader(QString("Content-Length").toAscii(), QString::number(data.length()).toAscii());

    reply = manager->post(request, data);

    QObject::connect(reply, SIGNAL(uploadProgress(qint64,qint64)), currentThread(), SLOT(receiveUploadProgress(qint64, qint64)));
    QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), currentThread(), SLOT(uploadFinished(QNetworkReply*)));

这是我的插槽:

void UploadThread::uploadFinished(QNetworkReply *reply)

    _isFinished = true;


void UploadThread::receiveUploadProgress(qint64 bytesSent, qint64 bytesTotal)

    qDebug() << bytesSent << " " << bytesTotal;

您在我的代码中发现问题了吗? 谢谢。

【问题讨论】:

【参考方案1】:

好的,我明白了。

对于每次上传,我需要使用 exec() 启动 QEventLoop,并且在上传结束时我必须使用 exit() 来完成 QEventLoop。它现在就像一个魅力。

【讨论】:

【参考方案2】:

您似乎在您的sendFile() 方法中调用了QObject::connect()

QObject::connect() 使用插槽方法连接信号。可以使用emit signalName() 之类的方式触发信号。

在您的示例中,您的 UploadThread 标头应如下所示:

class UploadThread: public QThread 
    ...
signals:
    void uploadProgress(int sent, int total);
    void uploadFinished(QNetworkReply *reply);

不要实现信号,它们是由 Qt 自动实现的。

在 sendFile() 中,调用它们即可:

...
emit uploadProgress(sent, total);
...

在您的主线程(=gui 线程)中,您应该有一个具有处理信号插槽的类(您当前的 uploadFinished() 和 recieveUploadProgress() 方法)。如果您想更新 GUI,重要的是它们在 GUI 线程中执行。

最后你必须连接它们(连接并不意味着调用它们)并开始上传。

UploadThread *uploadThread = new UploadThread();
connect(uploadThread, SIGNAL(uploadProgress(...)), objectInGuiThread, SLOT(actualUploadProgressSlot(...)));

uploadThread.start()

查看 Qt 的 Signal & Slot 文档,了解有关如何使用它们的更多信息。

【讨论】:

我不必重新实现uploadProgress() 和finished() 信号,它们分别由QNetworkReply 和QNetworkAccessManager 实现。我不必手动发出它们。所以,我的代码应该可以工作,不是吗?

以上是关于QThread 中的 Qt 信号和槽的主要内容,如果未能解决你的问题,请参考以下文章

Qt C++ 信号和槽没有触发

QT信号和槽在哪个线程执行问题

Qt 6.x中的信号和槽介绍及示例

Qt 6.x中的信号和槽介绍及示例

Qt4 中的信号和槽

QT学习之信号和槽