QT - 显示Widget而不阻止他的GUI

时间:2014-04-10 13:44:15

标签: multithreading qt user-interface

我想显示一个用于显示动画加载gif的小部件,而另一个函数(pthread)则计算任务。

我尝试使用QThread类对我的窗口小部件进行子类化,并实现方法run(),我调用方法show()。但是,我的小部件GUI冻结了。

如何启动单独处理GUI的小部件?

2 个答案:

答案 0 :(得分:4)

除主线程外,您不能运行任何小部件。

此外,除非您想要更改Qt处理线程的方式,否则您不应继承QThread。

相反,创建一个继承自QObject的worker对象并将其移动到新线程。您可以阅读how to really use QThread here

然后可以将您的工作对象移动到另一个线程,进行计算并通过信号和插槽与主线程上的Gui小部件进行通信。

例如,这是工人阶级的简要概述: -

class Worker : public QObject
{
    Q_OBJECT        

    signals:
        void finished();

        void displayWidget();

    private slots:
        void run();
}

QThread pThread = new QThread;
Worker pObject = new Worker;

// move the pObject to the thread
pObject->moveToThread(pThread);  

然后,您可以使用信号和插槽控制线程。

// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));

// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));

然后开始主题: -

pThread->start();

以这种方式使用,它还可以将多个对象移动到一个新线程,而不是为每个对象实例创建一个新线程。

所以现在,例如,如果你想在工作对象的处理过程中的某个时刻显示一个小部件,你就会发出它的displayWidget()信号,之前已将它连接到Widget的show()插槽。 / p>

QWidget* pWidget = new QWidget(parent); // assumes parent is initialized
// using Qt 5 connect call
connect(pWorker, &Worker::displayWidget, pWidget, &Widget::show);

答案 1 :(得分:0)

您不能从GUI线程以外的线程直接使用QWidget(也不是任何派生类) 。您只能直接使用工作线程拥有的QImage并直接从该线程绘制它。在这里,直接意味着您只是调用对象的方法。

您需要的是一种不直接在调用线程中执行show()的方法,而是间接地在GUI线程的上下文中执行QWidget::show()。这很简单,因为QMetaObject::invokeMethod(widget, "show"); 是一个插槽。因此,从您的计算线程中,只需执行:

invokeMethod

这就是全部。 widget的实施将确定QueuedConnection生活在不同的帖子中,并会自动选择QMetaCallEvent来电传递方式。在内部,它会将widget发布到QObject::event。窗口小部件的show方法将对事件起作用,并将调用置于QProgressBar方法。这将发生在GUI线程中。

您可以使用相同的方法来设置int value = ...; QMetaObject::invokeMethod(progressBar, "setValue", Q_ARG(int, value)); ,例如:

{{1}}