在Qt中从多个线程中绘图

Drawing from multiple threads in Qt

本文关键字:线程 绘图 Qt      更新时间:2023-10-16

我正在用Qt写一个程序,它运行10个工作线程,计算空间中物体的轨迹。还需要画出物体的路径。我有一个"体"类派生QGraphicsEllipseItem,它有一个QPainterPath在它。"模拟"类获取世界中的障碍物列表,以及要模拟的身体,并运行直到身体与某些东西碰撞。模拟运行在一个单独的线程中(通过moveToThread完成,而不是通过子类化QThread)。当身体碰撞时,模拟会发出一个信号说它结束了。当所有线程都完成后,我想绘制路径(我通过调用"Body"中的方法来实现路径绘制,该方法在其draw方法中)。

不幸的是,我得到ASSERT错误:

ASSERT: "!unindexedItems.contains(item)" in file graphicsviewqgraphicsscenebsptreeindex.cpp, line 364

它们似乎是随机发生的。我尝试了不同的连接类型,但没有结果。
我正在启动一个循环中的线程。
我正在使用Qt 5.0

一般来说,Qt不能在GUI线程(即执行QApplication::exec()的线程,通常是main()线程)之外做任何GUI操作。

因此,如果您有多个线程操作QGraphicsItems(特别是当前属于QGraphicsScene的QGraphicsItems),那么很可能导致断言失败。也就是说,当Qt GUI线程进行窗口刷新时,它正在从各种QGraphicsItem对象中读取数据,作为其计算的一部分,并且它期望QGraphicsItem在刷新操作期间保持不变。如果在执行刷新例程时(由另一个线程)更改了QGraphicsItem,则主线程进行的计算可能会出错/损坏,并且偶尔会导致断言失败(和/或其他不想要的行为)。

如果你真的需要使用多个线程,你可能需要做的是让线程在自己的私有数据结构上完成所有的计算,Qt GUI线程无法访问这些数据结构。然后,当线程计算出结果时,它们应该将结果发送回Qt GUI线程(通过排队连接或QApplication::postEvent())。然后,GUI线程可以查看结果并使用它们来更新QGraphicsItems等;这将是"安全的",因为此更新不会发生在窗口更新的中间。

如果这听起来工作量太大,那么您可能会考虑在GUI线程中完成所有工作;这样做会更容易、更简单。

正如Jeremy所提到的,Qt渲染必须在主线程上完成。

虽然您可以将其全部移动到主线程,但您可能会选择创建单独的线程以提高效率,特别是因为碰撞检测可能是处理器密集型的。处理这个问题的最好方法是将对象的建模及其物理属性从渲染中分离出来,就像你在模型/视图/控制器模式中所做的那样。

创建不从任何QGraphicsItem/Objects派生的主体实例的表示。然后,它们可以在单独的线程上进行计算,并向主线程中运行的图形对象发送信号,主线程更新每个主体实例的图形表示,从而允许实时渲染轨迹。