Multithreading QT-在不阻塞GUI的情况下显示小部件

Multithreading QT-在不阻塞GUI的情况下显示小部件,multithreading,qt,user-interface,Multithreading,Qt,User Interface,我想显示一个小部件,用于在另一个函数(pthread)计算任务时显示动画加载gif 我尝试用QThread类对我的小部件进行子类化,并实现了方法run(),在这里我调用方法show()。然而,我的小部件GUI冻结了 如何启动一个单独处理GUI的小部件?除了主线程之外,任何东西都不能运行小部件 此外,除非您想更改Qt处理线程的方式,否则不应该从QThread继承 相反,创建一个从QObject继承的工作对象,并将其移动到新线程。你可以阅读 然后可以将worker对象移动到另一个线程,进行计算,并通

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

我尝试用
QThread
类对我的小部件进行子类化,并实现了方法
run()
,在这里我调用方法
show()
。然而,我的小部件GUI冻结了


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

除了主线程之外,任何东西都不能运行小部件

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

相反,创建一个从QObject继承的工作对象,并将其移动到新线程。你可以阅读

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

// 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()));
例如,下面是工人阶级的简要概述:-

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();
通过这种方式,它还可以将多个对象移动到单个新线程,而不是为每个对象实例创建一个新线程

例如,现在,如果您想在worker对象中的处理过程中的某个时间点显示一个小部件,您应该发出它的displayWidget()信号,之前将它连接到小部件的show()插槽


除了主线程,你不能在任何东西上运行小部件

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

相反,创建一个从QObject继承的工作对象,并将其移动到新线程。你可以阅读

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

// 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()));
例如,下面是工人阶级的简要概述:-

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();
通过这种方式,它还可以将多个对象移动到单个新线程,而不是为每个对象实例创建一个新线程

例如,现在,如果您想在worker对象中的处理过程中的某个时间点显示一个小部件,您应该发出它的displayWidget()信号,之前将它连接到小部件的show()插槽


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

您需要的是一种执行
show()
的方法,它不是直接在调用线程中执行,而是在GUI线程的上下文中间接执行。这非常简单,因为
QWidget::show()
是一个插槽。因此,在计算线程中,只需执行以下操作:

QMetaObject::invokeMethod(widget, "show");
就这些。
invokeMethod
的实现将确定
widget
位于不同的线程中,并将自动选择呼叫传递的
QueuedConnection
方法。在内部,它将发布一个
QMetaCallEvent
小部件
。小部件的
QObject::event
方法将对事件起作用,并调用
show
方法。这将在GUI线程中发生

您可以使用相同的方法设置
QProgressBar
,例如:

int value = ...;
QMetaObject::invokeMethod(progressBar, "setValue", Q_ARG(int, value));

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

您需要的是一种执行
show()
的方法,它不是直接在调用线程中执行,而是在GUI线程的上下文中间接执行。这非常简单,因为
QWidget::show()
是一个插槽。因此,在计算线程中,只需执行以下操作:

QMetaObject::invokeMethod(widget, "show");
就这些。
invokeMethod
的实现将确定
widget
位于不同的线程中,并将自动选择呼叫传递的
QueuedConnection
方法。在内部,它将发布一个
QMetaCallEvent
小部件
。小部件的
QObject::event
方法将对事件起作用,并调用
show
方法。这将在GUI线程中发生

您可以使用相同的方法设置
QProgressBar
,例如:

int value = ...;
QMetaObject::invokeMethod(progressBar, "setValue", Q_ARG(int, value));

你们没注意到user2543127用QThread子类化了他的小部件,这是他尝试的邪恶的根源吗?无法从UI线程(主线程)外部访问/创建UI。是的,这就是为什么我建议他创建一个从QObject继承的worker对象。但是您没有对此回答进行太多解释OP没有显示任何可使用的示例代码。我没有从一篇优秀的文章中重复信息,而是链接到它。所有信息都在那里。@Merlin069这些都不能解决提问者的问题:如何从非GUI线程调用
widget->show()
。“信号和插槽”的提及似乎朝着这个方向发展,但随后突然停止。关于如何正确使用
QThread
的建议虽然有效,但在这里有些离题。教育学要求不要一次调用太多的新东西。你们没注意到user2543127用QThread子类化了他的小部件,这是他尝试的邪恶的根源吗?无法从UI线程(主线程)外部访问/创建UI。是的,这就是为什么我建议他创建一个从QObject继承的worker对象。但是您没有对此回答进行太多解释OP没有显示任何可使用的示例代码。我没有从一篇优秀的文章中重复信息,而是链接到它。所有的信息都在那里。@Merlin069这些都不能解决这个问题