从后台工作线程修改Qt GUI

Emi*_*ore 19 linux user-interface qt multithreading

我在Qt工作,当我按下按钮GO时,我需要不断地将包发送到网络并使用我收到的信息修改界面.

问题是我有一个while(1)按钮,所以按钮永远不会完成,所以界面永远不会更新.我想在按钮中创建一个线程并将while(){}代码放在那里.

我的问题是如何从线程修改接口?(例如,如何从线程中修改textBox?

NIA*_*NIA 37

关于Qt的重要一点是,您必须仅从GUI线程(即主线程)使用Qt GUI.

这就是为什么正确的方法是从工作者通知主线程,主线程中的代码实际上将更新文本框,进度条或其他东西.

我认为,最好的方法是使用QThread而不是posix线程,并使用Qt 信号在线程之间进行通信.这将是你的工人,一个替代品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);
};
Run Code Online (Sandbox Code Playgroud)

在您的小部件中,使用与.h中的信号相同的原型定义一个插槽:

class MyWidget : public QWidget {
    // Your gui code

    // Define slot:
    public slots:
    void onProgressChanged(QString info);
};
Run Code Online (Sandbox Code Playgroud)

在.cpp中实现此功能:

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

现在在你想要产生一个线程的地方(点击按钮):

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
}
Run Code Online (Sandbox Code Playgroud)

连接信号和插槽后,emit progressChanged(...)在工作线程中发出插槽将向主线程发送消息,主线程将调用连接到该信号的插槽,onProgressChanged此处.

Ps我还没有测试过代码,所以如果我错了,可以随意建议编辑

  • 感谢这篇精彩的文章,它真的帮助我理解了 QT 中很多对我来说是新的东西!我仍然遇到 UI 锁定的问题。第一个代码块应该在 .h 还是 .cpp 文件中? (2认同)
  • @David,嗯,.h vs .cpp实际上应该没关系.你确定你正在用`workerThread-> start()`开始一个线程,**不是**用`workerThread-> run()`? (2认同)