Results 1 to 20 of 20

Thread: How to connect signal-slog in second thread?

  1. #1
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default How to connect signal-slog in second thread?

    Hi everyone.

    I'm working on a little desktop gui app, which starts some other thread which would watch for changes in a certain file. I know I don't need a second thread for this, but would really like to, since I would do some time consuming processing on that file change event and would like to keep my main thread where gui app resides, still responsive to user comands.

    Ok, so I have my second thread, but the problem is, that I can not connect signal-slot in it. The message I get at run time is "QObject::connect: No such slot QThread::HandleFileChange(const QString)". The relevant part of the code is bellow. Much thanks for help.

    worker.h
    Qt Code:
    1. #ifndef WORKER_H
    2. #define WORKER_H
    3. #include <QThread>
    4. #include <QFileSystemWatcher>
    5.  
    6. class Worker: public QThread
    7. {
    8. public:
    9. Worker(QString SrcFileParam,QString WorkerFolderParam);
    10.  
    11. void run();
    12.  
    13. private:
    14. QString SrcFilename,WorkerFolder;
    15. int Cntr;
    16. QFileSystemWatcher * watcher;
    17.  
    18. public slots:
    19. void HandleFileChange(const QString fileName);
    20.  
    21. };
    22.  
    23. #endif // WORKER_H
    To copy to clipboard, switch view to plain text mode 

    worker.cpp
    Qt Code:
    1. #include "Worker.h"
    2. #include <iostream>
    3. #include <QMessageBox>
    4. #include <QFile>
    5. #include <QFileInfo>
    6.  
    7. Worker::Worker(QString SrcFileParam,QString WorkerFolderParam)
    8. {
    9. SrcFilename = SrcFileParam;
    10. WorkerFolder = WorkerFolderParam;
    11.  
    12. watcher = new QFileSystemWatcher(this);
    13. watcher->addPath(this->SrcFilename);
    14.  
    15. }
    16.  
    17. void Worker::run() {
    18. connect(watcher,SIGNAL(fileChanged(QString)),this,SLOT(HandleFileChange(const QString))); //problematical line
    19. for (int i=1;i<100;i++) {
    20. //std::cout << qPrintable(i);
    21. //std::cout << "printed from Worker class \nl";
    22. //QMessageBox::information(0,tr("Info"),QString::number(i));
    23. }
    24.  
    25. }
    26.  
    27. void Worker::HandleFileChange(const QString fileName) {
    28. // some code
    29. }
    To copy to clipboard, switch view to plain text mode 

    mainwindow.cpp
    Qt Code:
    1. Worker wkr1(ui->lineEdit->text(),ui->lineEdit_2->text());
    2. wkr1.start();
    3. wkr1.wait();
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jun 2015
    Location
    India
    Posts
    185
    Thanks
    8
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    signal is fileChanged ( const QString &) not fileChanged (QString)
    and you need to add Q_OBJECT marco in worker class.

    one more thing is, if we use signal/slot across threads we need to start local event loop with exec() at the end of the run function;
    Thanks :-)

  3. #3
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Thanks prasad_N, but
    Quote Originally Posted by prasad_N View Post
    signal is fileChanged ( const QString &) not fileChanged (QString)
    according to codecompletion that is not true.
    and you need to add Q_OBJECT marco in worker class.
    would you please show a short sample how to do it, remember a newbie
    one more thing is, if we use signal/slot across threads we need to start local event loop with exec() at the end of the run function;
    I'm not sure I understand this one,should I put exec() in main thread or inside Worker::run. If you can add adjustments to my case I would be really gratefull, much thanks again.

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Quote Originally Posted by arcull View Post
    according to codecompletion that is not true
    Correct, just QString is the simplified/normalized argument type signature.

    Quote Originally Posted by arcull View Post
    would you please show a short sample how to do it, remember a newbie
    Q_OBJECT is placed right after the opening brace { of the class declaration

    Qt Code:
    1. class MyClass : public QObject
    2. {
    3. Q_OBJECT
    4. };
    To copy to clipboard, switch view to plain text mode 

    Quote Originally Posted by arcull View Post
    I'm not sure I understand this one,should I put exec() in main thread or inside Worker::run. If you can add adjustments to my case I would be really gratefull, much thanks again.
    You only need event loop on the thread that receives the signals. In your case that is the main thread.
    The instance of Worker is created by the main thread, thus the slot HandleFileChange(QString) will be executed in the main thread.
    The signal source, in this case the file system watcher, is also in the main thread, so its events are also handled there.

    The only thing the worker thread does in this example is running a for loop and then exit.

    Cheers,
    _

  5. #5
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Quote Originally Posted by anda_skoa View Post
    Correct, just QString is the simplified/normalized argument type signature.


    Q_OBJECT is placed right after the opening brace { of the class declaration

    Qt Code:
    1. class MyClass : public QObject
    2. {
    3. Q_OBJECT
    4. };
    To copy to clipboard, switch view to plain text mode 



    You only need event loop on the thread that receives the signals. In your case that is the main thread.
    The instance of Worker is created by the main thread, thus the slot HandleFileChange(QString) will be executed in the main thread.
    The signal source, in this case the file system watcher, is also in the main thread, so its events are also handled there.

    The only thing the worker thread does in this example is running a for loop and then exit.

    Cheers,
    _
    Thanks. You are right, that is how it would work now. But I would like the second thread (Worker class) to receive the signals and connect them to correct slot, ie. I would like the watching and handling file changes to be done by the second thread. How could I accieve this? Besides, what would I put in the run method of Worker class in this case, because I need it to "keep alive" and not exit if that is not requested from the main thread. Would an infinite loop be ok? Please suggest, a short snippet of code would be great. Thanks for your help.

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    There are three options:

    1) treat your run() method like you would treat the main() function, i.e. forget about the encapsulating object.
    Just create an instance of the actual worker object and call exec() on the thread.

    2) Use the moveToThread approach: create an instance of a QObject derived worker class and an instance of plain QThread and call worker->moveToThread(threadInstance)

    3) Create the file system watcher in run() instead of your thread class' constructor and use Qt:irectConnection when connecting to the slot in your thread class.
    Call exec() at the end of run()

    Cheers,
    _

  7. #7
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Thanks anda_skoa.
    1) treat your run() method like you would treat the main() function, i.e. forget about the encapsulating object.
    Just create an instance of the actual worker object and call exec() on the thread.
    This one sounds the easiest So in my case, run() method of Worker class would have just one line of code to connect signal slot? After calling exec() on the thread, will the thread stay alive, that is, would it handle signal slot events? Am I still able to terminate this thread from the first one? Thanks again.

  8. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to connect signal-slog in second thread?

    Maybe reading some of the Qt threading examples and tutorials would help you.

  9. #9
    Join Date
    Jun 2015
    Location
    India
    Posts
    185
    Thanks
    8
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Thanks :-)

  10. #10
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Red face Re: How to connect signal-slog in second thread?

    Ok, I've solved it with a bit of trial and error. Here is a working sample:
    mainwindow.cpp
    Qt Code:
    1. Worker *wrkr1;
    2. wrkr1 = new Worker(ui->lineEdit->text(),ui->lineEdit_2->text());
    3. wrkr1->start();
    To copy to clipboard, switch view to plain text mode 
    workder.h
    Qt Code:
    1. #ifndef WORKER_H
    2. #define WORKER_H
    3. #include <QThread>
    4. #include <QFileSystemWatcher>
    5. #include <QObject>
    6.  
    7. class Worker: public QThread
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. Worker(QString SrcFileParam,QString WorkerFolderParam);
    13.  
    14. void run();
    15.  
    16. private:
    17. QString SrcFilename,WorkerFolder;
    18. int Cntr;
    19. QFileSystemWatcher * watcher;
    20.  
    21. public slots:
    22. void HandleFileChange(const QString fileName);
    23.  
    24. };
    25.  
    26. #endif // WORKER_H
    To copy to clipboard, switch view to plain text mode 
    worker.cpp
    Qt Code:
    1. #include "Worker.h"
    2. #include <iostream>
    3. #include <QMessageBox>
    4. #include <QFile>
    5. #include <QFileInfo>
    6.  
    7. Worker::Worker(QString SrcFileParam,QString WorkerFolderParam)
    8. {
    9. std::cout << "Worker constructor \n";
    10. SrcFilename = SrcFileParam;
    11. WorkerFolder = WorkerFolderParam;
    12.  
    13. watcher = new QFileSystemWatcher();
    14. watcher->addPath(this->SrcFilename);
    15.  
    16. }
    17.  
    18. void Worker::run() {
    19. connect(watcher,SIGNAL(fileChanged(QString)),this,SLOT(HandleFileChange(const QString)));
    20. qDebug("method run in Worker thread");
    21. exec();
    22. }
    23.  
    24. void Worker::HandleFileChange(const QString fileName) {
    25. qDebug("HandleFileChange triggered...");
    26. //some code
    27. }
    To copy to clipboard, switch view to plain text mode 
    To sum up, I've made 3 crucial mistakes:
    1)forgetting Q_OBJECT macro, without it the Worker thread wont have signal/slot functionality
    2)starting the second thread and then waiting.
    3)missing exec() in my Worker thread

    Now it works,I'm happy. Thank you all for help.

  11. #11
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Quote Originally Posted by arcull View Post
    So in my case, run() method of Worker class would have just one line of code to connect signal slot?
    No.
    As I wrote, this approach treats run() like main().
    There is no slot to connect to unless you create an object that has such a slot.

    Quote Originally Posted by arcull View Post
    After calling exec() on the thread, will the thread stay alive, that is, would it handle signal slot events?
    Yes.

    Quote Originally Posted by arcull View Post
    Am I still able to terminate this thread from the first one?
    Yes, simply by calling the thread's quit() method.

    Quote Originally Posted by arcull View Post
    Ok, I've solved it with a bit of trial and error. Here is a working sample:
    No.
    That still processes everything in the main thread.
    Your worker thread does nothing, it jus sits there waiting for events that never come.

    Cheers,
    _

  12. #12
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    No.
    That still processes everything in the main thread.
    Your worker thread does nothing, it jus sits there waiting for events that never come.
    I don't think you're right...or it may be I don't understand who does what in this case. I tried to run my sample and HandleFileChange method of Worker class executes every time my selected files changes, wouldn't this mean it is executed in Worker class i.e. my second thread?

  13. #13
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Quote Originally Posted by arcull View Post
    I don't think you're right...or it may be I don't understand who does what in this case. I tried to run my sample and HandleFileChange method of Worker class executes every time my selected files changes, wouldn't this mean it is executed in Worker class i.e. my second thread?
    No, it means that the connection is correctly set up and that some thread executes the slot when the signal is emitted. Unfortunately for you, the main thread is the one executing the slot.

    A QThread manages a thread, but does not live in it; it lives in the thread that allocated it.

    In your example, the line
    Qt Code:
    1. connect(watcher,SIGNAL(fileChanged(QString)),this,SLOT(HandleFileChange(const QString)));
    To copy to clipboard, switch view to plain text mode 
    connects two objects, watcher and the Worker instance, with an AutoConnection. As a result, HandleFileChange is executed in the thread in which the Worker instance lives, that is, the main thread. The second thread -- the one managed by the Worker instance -- indefinitely waits for events.

    So, just to clarify anda_skoa's proposal #1, which you decided to follow:
    Your worker object should not be the same as the QThread object.
    Declare two classes: a QThread-derived class MyThread and a QObject-derived class MyWorker.
    In MyThread::run(), allocate a MyWorker on the stack and connect some signals to its slots, then run exec().
    Since the MyWorker instance was allocated in MyThread::run(), it lives in the thread executing MyThread::run(), i.e. the thread managed by the MyThread instance. That thread will be the one executing the slots of the MyWorker instance, which is exactly what you are after.
    By contrast, the MyThread instance itself lives in the main thread.

  14. #14
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Post Re: How to connect signal-slog in second thread?

    ufff thanks, I'll try.

  15. #15
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Quote Originally Posted by yeye_olive View Post
    In MyThread::run(), allocate a MyWorker on the stack and connect some signals to its slots, then run exec().
    Right, and also allocate the file system watcher there if you want its events to be processed by the secondary thread.

    Cheers,
    _

  16. #16
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    This works, but am not sure the file change is processed by second thread now. Can you please review the code, thanks
    worker.h
    Qt Code:
    1. #ifndef WORKER_H
    2. #define WORKER_H
    3. #include <QThread>
    4. #include <QFileSystemWatcher>
    5. #include <QObject>
    6.  
    7. class Worker : public QObject
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. Worker(QString SrcFileParam,QString WorkerFolderParam);
    13.  
    14. private:
    15. QString SrcFilename,WorkerFolder;
    16. int Cntr = 0;
    17. QFileSystemWatcher * watcher;
    18.  
    19. public slots:
    20. void HandleFileChange(const QString fileName);
    21.  
    22. };
    23.  
    24. #endif // WORKER_H
    To copy to clipboard, switch view to plain text mode 
    worker.cpp
    Qt Code:
    1. #include "Worker.h"
    2. #include <iostream>
    3. #include <QMessageBox>
    4. #include <QFile>
    5. #include <QFileInfo>
    6.  
    7. Worker::Worker(QString SrcFileParam,QString WorkerFolderParam)
    8. {
    9. SrcFilename = SrcFileParam;
    10. WorkerFolder = WorkerFolderParam;
    11.  
    12. watcher = new QFileSystemWatcher();
    13. watcher->addPath(this->SrcFilename);
    14. connect(watcher,SIGNAL(fileChanged(QString)),this,SLOT(HandleFileChange(const QString)));
    15. }
    16.  
    17. void Worker::HandleFileChange(const QString fileName) {
    18. qDebug("HandleFileChange triggered...");
    19. }
    To copy to clipboard, switch view to plain text mode 
    procthread.h
    Qt Code:
    1. #ifndef PROCTHREAD_H
    2. #define PROCTHREAD_H
    3.  
    4. #include <QThread>
    5.  
    6. class ProcThread : public QThread
    7. {
    8.  
    9. private:
    10. QString SrcFilename,WorkerFolder;
    11.  
    12. public:
    13. explicit ProcThread(QString SrcFileParam,QString WorkerFolderParam);
    14.  
    15. void run();
    16. };
    17.  
    18. #endif // PROCTHREAD_H
    To copy to clipboard, switch view to plain text mode 
    procthread.cpp
    Qt Code:
    1. #include "procthread.h"
    2. #include "Worker.h"
    3.  
    4. ProcThread::ProcThread(QString SrcFileParam,QString WorkerFolderParam)
    5. {
    6. SrcFilename = SrcFileParam;
    7. WorkerFolder = WorkerFolderParam;
    8. }
    9.  
    10.  
    11. void ProcThread::run() {
    12. Worker wrkr1(SrcFilename,WorkerFolder);
    13. exec();
    14.  
    15. }
    To copy to clipboard, switch view to plain text mode 
    mainwindow.cpp
    Qt Code:
    1. procth1 = new ProcThread(ui->lineEdit->text(),ui->lineEdit_2->text());
    2. procth1->start();
    To copy to clipboard, switch view to plain text mode 

  17. #17
    Join Date
    Jul 2015
    Location
    Sweden
    Posts
    12
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to connect signal-slog in second thread?

    The link posted above shows a rather good and easy way to trace what thread executes your code...
    Just change the trace in Worker::HandleFileChange and you will know where the code executes, a second trace in mainwindow before starting the thread should give you the main GUI thread id to compare with.

    Qt Code:
    1. qDebug() << "HandleFileChange triggered... " << QThread::currentThreadId();
    To copy to clipboard, switch view to plain text mode 

    Code review even by experts can never replace tracing the code in it's correct environment.

  18. #18
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Quote Originally Posted by arcull View Post
    This works, but am not sure the file change is processed by second thread now. Can you please review the code, thanks
    Yes, that looks good, a perfect example of the "treat run() like main()" approach.

    Worker doesn't know anything about threads and it would work without change in main():

    Qt Code:
    1.  
    2. Worker worker(...);
    3.  
    4. app.exec();
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  19. #19
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    That looks about right, but there is a memory leak; the QFileSystemWatcher is never deallocated.

  20. #20
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to connect signal-slog in second thread?

    Ok, thanks all again. By the way, how do I mark thread as solved?

Similar Threads

  1. How to connect signal to signal in QWidget correctly
    By Mint87 in forum Qt Programming
    Replies: 2
    Last Post: 6th February 2013, 00:06
  2. Replies: 5
    Last Post: 13th November 2012, 12:43
  3. Connect signal/signal in Qt Designer
    By jlemaitre in forum Newbie
    Replies: 1
    Last Post: 22nd September 2010, 15:53
  4. Replies: 5
    Last Post: 16th January 2010, 09:17
  5. Replies: 9
    Last Post: 28th November 2009, 20:31

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.