Error: no such slot while using QNetworkAccessManager with threads



  • 0 down vote favorite

    I am in troubled situation on using QNetworkAccessManager in QThread. The same functions working fine without using threads. I am currently using only one thread and I need to add few more also.

    It fires error message : "Object::connect: No such slot QThread::replyFinished(QNetworkrReply*)"

    The header file code (NewThread.h ) is:
    @
    class NewThread: public QThread
    {
    public slots:
    void replyFinished(QNetworkReply* reply);

    protected:
         void run();
    
    private: 
    

    };
    @

    The source code file(NewThread.cpp ):
    @
    void NewThread::replyFinished(QNetworkReply *net_reply)
    {
    QByteArray data = net_reply->readAll();
    QString str(data);
    }

    void NewThread::run()
    {

    QNetworkAccessManager *manager;
    manager = new QNetworkAccessManager ();
    QNetworkRequest req;
    req.setUrl(QUrl("My url"));

        QByteArray postData;
    
        postData.append("some data string");
    
    
        req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    
        manager->setCookieJar(new QNetworkCookieJar(manager));
        //Define the Request-url:
        connect (manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinish (QNetworkReply  *)));
        //Send the request:
        manager->post(req, postData);
    

    }

    void NewThread::replyFinish(QNetworkReply *reply)
    {
    QString answer = QString::fromUtf8(reply->readAll());
    qDebug () << answer;
    }
    @

    I am creating an object of NewThread class in another class, like below:

    @

    NewThread thread1;
    thread1.start();

    @

    I am wondering why the same code working without threads and not with threads. I am in hard situation, any help appreciated.


  • Moderators

    You don't have a Q_OBJECT macro in your class header.

    Edit to add:

    Also, what is your reasoning for using QThread with QNetworkAccessManager? QNAM is already asynchronous, and typically isn't necessary.

    (Also, subclassing QThread is not the preferred method of using QThreads)


  • Moderators

    [quote author="mlong" date="1350574118"](Also, subclassing QThread is not the preferred method of using QThreads)[/quote]Following up on mlong's comment: The preferred way is shown at http://doc-snapshot.qt-project.org/5.0/qthread.html (that is Qt5 documentation, but most of it is applicable to Qt4.5 and above)



  • The new QThread documentation really is is a great improvement over the old one. Great job JKSH!



  • @mlong, thanks for the reply.
    I used the Q_OBJECT macro and it resolved the error....BUT now the replyFinish slot(finished signal) is not working (it never get called) .
    When I checked the debug details it says.. invalid rpc server exception..
    I am unable to get that why on the earth is this exception firing here in threads and every thing working fine without threads.. I really need to do it with threads.
    Any suggestions...


  • Moderators

    @KA510: Thanks for your kind words :) It was a community effort though; people on the forum and mailing list gave lots of helpful advice and insight

    @Zain: Some questions --

    Which class throws the exception? Your code doesn't show it

    Can you please provide more details on WHAT needs to be done with threads? Your example only sends a HTTP post request from your thread. But, I believe QNetworkAccessManager already does that in a separate thread.

    Also, take note: Your NewThread object was created in the MAIN thread, so NewThread::replyfinished() will execute in the MAIN thread (not the thread which contains QNetworkAccessManager!)

    Subclassing QThread is a bad idea, and adding slots to a subclass causes lots of problems. If you really want to create your own thread, I recommend reading the first example at http://doc-snapshot.qt-project.org/5.0/qthread.html ("Detailed Description")



  • Thank you all for your efforts.

    I have done some exploration on this issue, and got a strange solution of adding a moc*.cpp file to the classes. And I actually got one in my debug folder. Please suggest:

    1. Will this work?
    2. how to add an external moc file to the project?

    I have copied it to project folder and added it to .pro as well.
    But it shows so many multiple declaration errors. (perhaps as many declaration as in moc file).

    Also clear if this is not going to work.

    @ JKSH, Its the same class (NetThread) which is showing the error.
    I want to get page source from url, as it should run in back ground because the post data will change and every time it will get different page source (I will run the thread, more than one time). During this process I need the program GUI user interface free for other things.
    Any suggestions.

    Thanks in advance


  • Moderators

    Qt reads your source code, and automatically generates moc*.cpp files. You cannot add "external" moc*.cpp files. You never need to add "external" moc*.cpp files.

    Qt classes do not throw exceptions, so I'm guessing that the exception was thrown by code which you haven't shown us.

    [quote author="Zain" date="1350656433"]I want to get page source from url, as it should run in back ground because the post data will change and every time it will get different page source (I will run the thread, more than one time).[/quote]I think you don't need to create more threads -- you just need asynchronous, object-oriented, event-driven programming.

    You can re-use QNetworkAccessManager, and call manager->post() over and over again. If you use signals and slots, your GUI should still be free.

    [quote]I am wondering why the same code working without threads and not with threads.

    ...

    During this process I need the program GUI user interface free for other things.[/quote]When you used code without threads, did your GUI freeze or lag?

    [quote author="Zain" date="1350645720"]now the replyFinish slot(finished signal) is not working (it never get called) [/quote]Your slot was never called because your signal was never emitted, because your thread didn't have an event loop, because NewThread::run() did not call exec()

    More questions: What does your post data contain?



  • Thanks for the replies,

    @JKSH

    The postdata contains some values of the form...some check box and radio buttons true /false and few textbox values..for different values the url gives different data.

    Your eventLoop suggestion get the reply finished called. But it is of no use when I execute the thread again.(I have tried the exit,, quit and again start and execute with so many combinations).

    Now I am thinking that it is not possible to use the QNetworkAccessManger in thread it is already asynchronous.. so Now I will use it directly without threads..
    ...please share if you get any Idea to execute a single thread with qNetworkAccessManager in loop (it is an indirect recursion in my case)

    Thank you all for your efforts....I am leaving the thought of using QNetworkAccessManager in threads.


  • Moderators

    Here's an example. I can fill in the form 100 times, and download 100 different websites, while using the same QNetworkAccessManager.

    @
    class ProgramCore : public QObject
    {
    private:
    Q_OBJECT

    MainWindow            *gui;
    QNetworkAccessManager *manager;
    

    private slots:
    void getPage() const
    {
    QNetworkRequest req;
    req.setUrl(QUrl("My url"));

        QByteArray postData = gui->readFormData();
    
        // Connect the signal from the reply, not from the manager.
        // The QNetworkReply will download data in the background. Your GUI is free
        // during this time.
        QNetworkReply *reply = manager->post(req, postData);
        connect(reply, SIGNAL(finished()), this, SLOT(processReply()));
    }
    
    void processReply() const
    {
        // Use QObject::sender() to find the object that emitted the signal
        QNetworkReply *reply = qobject_cast<QNetworkReply*>(this->sender());
    
        QString answer = QString::fromUtf8(reply->readAll());
        qDebug () << answer;
    
        // Make sure you don't have a memory leak! Delete the object when you've finished
        reply->deleteLater();        
    }
    

    public:
    ProgramCore(QObject *parent = 0) : QObject(parent)
    {
    this->gui = new MainWindow(this);
    this->manager = new QNetworkAccessManager(this);

        connect(gui, SIGNAL(userSubmittedTheForm()), this, SLOT(getPage()));
    }
    

    }
    @

    Final notes: This is just Repetition, not "Indirect Recursion". You only wanted to repeat a task, so you shouldn't use threads to do that. Threads are for Parallel Processing -- for example, making 2 CPU cores process different data at the same time.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.