QTimer 只能用于以 QThread 启动的线程

Posted

技术标签:

【中文标题】QTimer 只能用于以 QThread 启动的线程【英文标题】:QTimer can only be used with threads started with QThread 【发布时间】:2011-09-16 20:29:17 【问题描述】:

所以我有一个有趣的问题....我正在(尝试)编写的程序因此错误而崩溃:

QObject::startTimer: QTimer can only be used with threads started with QThread 

让我感到困惑的是我的程序是单线程的。有问题的课程的目标是将 POST 数据发送到我服务器上的 php 页面。一旦它尝试发送 POST,我就会收到该消息。这是我的代码。

#ifndef TRANSMISSIONS_H
#define TRANSMISSIONS_H
#include "name_spawn.h"
#include <QNetworkReply>
#include <QObject>
#include <QNetworkConfigurationManager>

class Transmissions : public QObject

    Q_OBJECT
public:
    Transmissions();
    void Send(GeneratedData);
public slots:
    void serviceRequestFinished(QNetworkReply*);
signals:
    void configurationAdded(const QNetworkConfiguration);
    void configurationChanged(const QNetworkConfiguration);
    void configurationRemoved(const QNetworkConfiguration);
    void onlineStateChanged(bool);
    void updateCompleted();
;

#endif // TRANSMISSIONS_H

还有

#include "transmissions.h"
#include "name_spawn.h"
#include <QHttp>
#include <QUrl>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <iostream>
#include <QNetworkAccessManager>
#include <QNetworkConfigurationManager>
#include <QObject>

using namespace std;

Transmissions::Transmissions()



void Transmissions::Send(GeneratedData User)

    cerr<<"transmitting"<<endl;
    QUrl serviceUrl = QUrl("http://192.168.1.138/postTest.php");
    QByteArray postData;
    QString username="user="+User.Email()+"&";
    QString Passwd="password="+User.pass();
    postData.append(username);
    postData.append(Passwd);

    QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
    connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serviceRequestFinished(QNetworkReply*)));
    networkManager->post(QNetworkRequest(serviceUrl), postData);


void Transmissions::serviceRequestFinished(QNetworkReply *reply)

    //this will do other things once post is working
    QString data = reply->readAll();
    cerr <<"Data is "<< data.toStdString()<<endl;


我认为我正在尝试做的事情相当简单,但是让我无法让它发挥作用让我感到沮丧。我在文档中没有看到关于 QNetworkAccessManager 需要线程的任何内容。我承认我不太了解 Qt,因此非常感谢任何帮助(或完整 POST 示例的链接)。

【问题讨论】:

你在运行 Qt 事件循环吗? 【参考方案1】:

要使用QTimer,您需要有一个事件循环。 QNAM 显然使用计时器来定期检查网络回复。

您需要使用QCoreApplication::exec() 启动应用程序事件循环,然后调用QNAM 方法,如post

我认为您可以在exec 之前致电post,但您可能会遇到this bug。

另外,请注意 Qt 4.7 QNAM 没有使用线程,而是使用了 4.8 this is changing。

【讨论】:

这很有意义。就像我告诉 synthesizerpatel 一样,我要到周日才能测试这个。我是否应该假设 QCoreApplication::exec() 应该通过我的程序 main 而不是在传输类中运行? 是的,通常main 的最后一行就是return app.exec() 到目前为止,该错误尚未出现,但我可以确认帖子正在运行!非常感谢游吟诗人。如果我能多次支持你的答案,我会:) 这回答了我的问题,但略有不同。在事件循环开始之前,我试图在我的 main() 中实例化的类构造函数中启动 QTimer。 这也解决了我使用 QTest、一个单独的 main(通过 qExec 执行多个测试)和那些具有计时器的测试的问题。我添加了“QCoreApplication app(argc,argv)”,现在测试工作正常,没有抛出任何错误。【参考方案2】:

这可能与在 Send 方法中创建 QNetworkAccessManager 有关 - 请尝试使用 RAII。

在Transmissions 的头文件中定义QNetworkAccessManager 作为类变量,并在ctor 中创建一个类实例,然后您就可以从Send 线程向它发布。

否则我认为它超出了范围。

【讨论】:

我将在几天内无法对此进行测试,但我会在周日之前通知您它是否有效。我不太明白如果 networkManager 以与声明它的方法相同的方法使用,它将如何超出范围。你能解释一下吗? “你将能够从发送线程向它发布”据我所知,我的程序甚至没有使用线程。 QNetworkAccessManager 是否在某处创建了一个? QNAM 的范围仅在“发送”方法内 - 一旦该方法完成,该对象就消失了(除非您创建它的类变量/类实例。如果您将其创建为class 变量并在 ctor 中创建一个实例,然后它会在 'send' 运行后出现,并且能够响应/发送信号。见java2s.com/Code/Cpp/Qt/DownloadfromURL.htm 指针超出范围,而不是对象。该对象是传输实例的父对象,因此在销毁时将被删除。 正确,指针超出范围。我的解释不好,但解决方案仍然正确。 先生们,谢谢你们。也为该链接的 synthesizerpatel +1。

以上是关于QTimer 只能用于以 QThread 启动的线程的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 错误中使用 QProcess 启动进程:“计时器只能用于以 QThread 启动的线程”

Viber 程序停止工作日志文件:启动计时器计时器只能用于以 QThread 1 启动的线程

如何在 QThread 中使用 QTimer?

QObject 子类未检测到 QGuiApplication 事件循环

QTimer在QThread中失效

QThread 与 QTimer 和 QSerial - 育儿