Modify Qt GUI from background worker thread

后端 未结 3 1574
执笔经年
执笔经年 2020-11-30 00:57

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

相关标签:
3条回答
  • 2020-11-30 01:22

    you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue

    0 讨论(0)
  • 2020-11-30 01:25

    you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .

    Below is example ,where it shows How to change the text of a label from a thread:

    //file1.cpp

    QObject *obj = NULL; //global 
    QLabel *label = new QLabel("test");
    obj = label;   //Keep this as global and assign this once in constructor.
    

    Next in your WorkerThread you can do as below:

    //file2.cpp (ie.,thread)

    extern QObject *obj;
    void workerThread::run()
    {
         for(int i = 0; i<10 ;i++
         {
             QMetaObject::invokeMethod(obj, "setText",
                                    Q_ARG(QString,QString::number(i)));
         }
         emit finished();
    }
    
    0 讨论(0)
  • 2020-11-30 01:33

    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

    0 讨论(0)
提交回复
热议问题