我想显示一个用于显示动画加载gif的小部件,而另一个函数(pthread
)则计算任务。
我尝试使用QThread
类对我的窗口小部件进行子类化,并实现方法run()
,我调用方法show()
。但是,我的小部件GUI冻结了。
如何启动单独处理GUI的小部件?
答案 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}}