Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify Qt GUI from background worker thread

I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.

The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.

My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?

like image 695
Emil Grigore Avatar asked Jan 27 '13 09:01

Emil Grigore


People also ask

Is Qt multithreaded?

Qt offers many classes and functions for working with threads. Below are four different approaches that Qt programmers can use to implement multithreaded applications.

What is a GUI thread?

Graphical user interfaces often have a dedicated thread (“GUI thread”) for servicing user interactions. The thread must remain responsive to user requests even while the application has long computations running. For example, the user might want to press a “cancel” button to stop the long running computation.

How do you use QThread?

To use it, prepare a QObject subclass with all your desired functionality in it. Then create a new QThread instance, push the QObject onto it using moveToThread(QThread*) of the QObject instance and call start() on the QThread instance. That's all.

What is main thread in Qt?

As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads.


1 Answers

Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.

That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.

The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:

class WorkerThread : public QThread {     void run() {         while(1) {              // ... hard work              // Now want to notify main thread:              emit progressChanged("Some info");         }     }     // Define signal:     signals:     void progressChanged(QString info); }; 

In your widget, define a slot with same prototype as signal in .h:

class MyWidget : public QWidget {     // Your gui code      // Define slot:     public slots:     void onProgressChanged(QString info); }; 

In .cpp implement this function:

void MyWidget::onProgressChanged(QString info) {     // Processing code     textBox->setText("Latest info: " + info); } 

Now in that place where you want to spawn a thread (on button click):

void MyWidget::startWorkInAThread() {     // Create an instance of your woker     WorkerThread *workerThread = new WorkerThread;     // Connect our signal and slot     connect(workerThread, SIGNAL(progressChanged(QString)),                           SLOT(onProgressChanged(QString)));     // Setup callback for cleanup when it finishes     connect(workerThread, SIGNAL(finished()),             workerThread, SLOT(deleteLater()));     // Run, Forest, run!     workerThread->start(); // This invokes WorkerThread::run in a new thread } 

After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.

P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere

like image 54
NIA Avatar answered Oct 06 '22 13:10

NIA