QTimer只能与使用QThread启动的线程一起使用。

13

我有一个有趣的问题...我正在尝试编写的程序会崩溃,显示以下错误:

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

And

#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事件循环吗? - Troubadour
2个回答

10
为使用 QTimer,您需要拥有一个事件循环。QNAM 显然使用定时器定期检查网络响应。
您需要使用 QCoreApplication::exec() 启动应用程序事件循环,然后在此之后调用 QNAM 方法,如 post
我认为在调用 exec 之前调用 post 是可以的,但您可能会遇到 此错误
另外,请注意,直到 Qt 4.7,QNAM 并未使用线程,但是从 4.8 开始,这将发生改变

那很合理。就像我告诉synthesizerpatel的,直到周日我才能够测试这个代码。我应该假设QCoreApplication :: exec()应该在我的程序主类中运行而不是Transmission类中吗? - CountMurphy
是的,通常main函数的最后一行只是return app.exec() - Troubadour
到目前为止,那个错误还没有出现,但我可以确认帖子正在工作!非常感谢Troubadour。如果我能多次投票支持你的答案,我一定会的 :) - CountMurphy
1
这回答了我的问题,我的问题略有不同。我试图在我的main()中实例化的类构造函数中启动一个QTimer,在事件循环开始之前。 - Harvey
这也解决了我的问题,即使用QTest、单独的main(通过qExec执行多个测试)以及这些测试具有定时器。我添加了“QCoreApplication app(argc,argv)”,现在测试可以正常工作且没有抛出任何错误。 - Deadolus

1

这可能与在Send方法内创建QNetworkAccessManager有关 - 尝试改用RAII。

在Transmissions的头文件中定义QNetworkAccessManager作为类变量,并在构造函数中创建一个类实例,然后您将能够从Send线程向其发送请求。

否则,我认为它会超出范围。


1
QNAM的作用范围仅限于“send”方法 - 一旦该方法完成,该对象就会消失(除非您创建一个类变量/类实例)。如果您将其创建为类变量并在构造函数中创建一个实例,那么它将在“send”运行后保留,并能够响应/发送信号。请参阅http://www.java2s.com/Code/Cpp/Qt/DownloadfromURL.htm - synthesizerpatel
1
指针超出范围,而不是对象。该对象已被分配至传输实例的父级,因此当传输实例被销毁时将被删除。 - Troubadour
没错,指针超出了作用域。我表述不太好,但解决方案仍然是正确的。 - synthesizerpatel
先生们,非常感谢你们。同时也要感谢synthesizerpatel提供的链接。+1。 - CountMurphy
我仍在努力理解一件事情。我知道当Send完成运行时,QNAM就会超出范围。从我阅读代码的方式来看(可能是因为我对信号不够了解),难道networkManager->post不会将数据发送到Web服务器,调用serviceRequestFinished,然后在完成并渲染指针超出范围之前返回到send方法吗? - CountMurphy
显示剩余3条评论

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