Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QTimer can only be used with threads started with QThread

So I have an interesting problem....a program I am (trying) to write is crashing with this error:

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

The thing that baffles me is my program is single threaded. The goal of the class in question is to send POST data to a php page I have on my server. As soon as it tries to send the POST, I get that message. Here is my code.

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

}

I think what I am trying to do is fairly simple, but it is frustrating me to no end trying to get it to work. I didn't see anything in the documentation about QNetworkAccessManager requiring threads. I admit I don't know Qt that well, so any help (or links to complete POST examples) would be very appreciated.

like image 847
CountMurphy Avatar asked Sep 16 '11 20:09

CountMurphy


2 Answers

To use a QTimer you need to have an event loop. QNAM obviously uses a timer to periodically check for the network reply.

You need to start the application event loop with QCoreApplication::exec() and then call QNAM methods like post after that.

I think you can call post before exec but you may come across this bug.

Also, note that up to Qt 4.7 QNAM did not use threading but with 4.8 this is changing.

like image 72
Troubadour Avatar answered Nov 10 '22 23:11

Troubadour


This may be related to creating the QNetworkAccessManager inside the Send method - try instead using RAII.

Define the QNetworkAccessManager in the header for Transmissions as a class variable, and create a class instance it in the ctor, then you will be able to post to it from the Send thread.

Otherwise I think it goes out of scope.

like image 37
synthesizerpatel Avatar answered Nov 11 '22 01:11

synthesizerpatel