Multithreading Qt:使用线程构造小部件

Multithreading Qt:使用线程构造小部件,multithreading,qt,qwidget,Multithreading,Qt,Qwidget,在我的应用程序中,我有一个QWidget MyWidget,我需要在按下按钮后构建它。现在,MyWidget是一个很重的小部件,有很多子组件,这些子组件也有很多组件。现在,当我试着在按下按钮后构建小部件时,小部件有时会出现,这是我不喜欢的。因此,我需要在单击按钮之前构造小部件,并在手边准备一个实例。这条线似乎非常适合这项工作。但我对Qt线程知之甚少 现在有人能建议我如何处理这个问题,以及可以做些什么来解决这个问题吗 注: 为了明确说明为什么我的小部件如此沉重,在MyWidget中,我有7*24个

在我的应用程序中,我有一个
QWidget MyWidget
,我需要在按下按钮后构建它。现在,MyWidget是一个很重的小部件,有很多子组件,这些子组件也有很多组件。现在,当我试着在按下按钮后构建小部件时,小部件有时会出现,这是我不喜欢的。因此,我需要在单击按钮之前构造小部件,并在手边准备一个实例。这条线似乎非常适合这项工作。但我对Qt线程知之甚少

现在有人能建议我如何处理这个问题,以及可以做些什么来解决这个问题吗

注:
为了明确说明为什么我的小部件如此沉重,在MyWidget中,我有7*24个小部件,每个小部件都有一个堆叠的小部件,上面有两个小部件,每个小部件都有一个按钮

首先,Qt和几乎所有其他处理UI元素的框架(最后是我所知道的框架)对多线程支持都有非常具体的要求

Qt需要将每个
QObject
子体(如
QWidget
)分配给线程(请参阅)

此属性在对象创建时自动指定给正在创建对象的线程

问题在于,Qt还要求小部件仅当它属于运行事件循环的同一线程(并且它被正确地添加到父小部件)时才接收事件

如果您在某个不同的线程上创建大型小部件,它将不会接收事件,直到它被移动到带有事件循环的线程并重新设置父级

您可以通过调用方法将
QWidget
移动到另一个线程。假设
mParent
是您的
QMainWindow
mMyWidget
是您的大型小部件:

mMyWidget->setParent(0);
mMyWidget->moveToThread(mParent->thread());
mMyWidget->setParent(mParent); // change this to match your layout requirements.
查看更多信息

大型小部件的创建不应与主线程在同一线程中执行。这只是一个练习,因为它非常简单,Qt文档在线程上非常广泛

如果在小部件创建完成之前按下了按钮,请小心:必须同步对变量的访问,以避免未定义的行为

这是一个非常高层次的问题,但这是一个开始,因为你没有提供任何代码,我给你一个最低限度;D


另一个选择(可能是更好的选择)是查看为什么创建小部件如此耗时,但如果没有更多信息,我将无能为力。

Qt不支持在非gui线程中创建小部件。原因很简单:小部件构造函数可以随时访问主线程可以使用的线程不安全API。因此,即使它看起来可以工作,但如果您这样做,它实际上是代码中的一个bug

一般来说,在重量级小部件类中,并行化非图形化、长时间运行的初始化任务。为此,您可以使用
QtConcurrent::run
。当然,您需要为此使实现线程安全

您还必须确保在小部件代码中绝对不使用任何阻塞API。一般来说,没有GUI代码,但没有小部件构造函数,应该:

  • 等待任何文件访问完成

  • 等待任何网络连接完成

  • 等待任何数据库访问完成

  • 在Qt中使用任何
    waitForXxxx
    方法

  • 使用可能间接访问文件系统的东西,例如
    QSettings


当你建议在另一个线程中实例化
QWidget
不是未定义的行为时,我认为你是在假设很多。就我而言,任何这样做的尝试都是一个迟早会咬到你的错误。如果您的小部件实例化花费了这么多时间,那么您应该将耗时的非gui内容交给一个通过
QtConcurrent::run
执行的助手。这是你能做的最好的了。当然,一些图形化的事情可以从任何线程完成。例如,绘画或加载
QImage
s。当然,我希望这里是错的。请出示一些佐证(Qt源代码的文档或相关分析),表明在随机线程上创建小部件是可以的。目前,我把这个答案视为严重的错误建议。当我开始学习Qt时,我“测试了这个”。我想学习Qt内部的线程和东西,我是一个非常糟糕的编程(刚刚开始我的毕业课程),所以我玩了(很多!)这个糟糕的东西。我同意你的看法,这是一个非常糟糕的建议,但我成功地让它工作了一次,根据用户提供的详细信息,没有太多的话要说。问题是,你的代码运行了一段时间而没有崩溃并不表示它工作。没有办法测试它是否有效。在非常狭窄的环境之外,测试结果不能被视为缺少bug的指示,它们只能用于在测试失败时指示bug的存在。在非gui线程中构造
QWidget
时,正确设计的测试总是会失败。这只是编写这样一个测试的问题。这些子组件是您自己的小部件吗?什么东西在初始化过程中花费了这么长时间?为什么要在构造函数中进行初始化?我可以使用什么替代方法?此时必须显示代码。我们可以编译和测试的代码。复制“慢度”的代码如果你告诉我让ui构造函数线程安全,我已经让它线程安全了。稍后,ui调用一些控制器类,构造函数类代表控制器访问数据库。它足够好吗?@ShakibAhmed一个
QWidget
构造函数根据定义不是线程安全的,你不能“制造”它。要使线程安全,您需要的是执行非图形化初始化的长时间运行的代码,该初始化可能会运行很长时间。这样的公司