我正在Qt中编写一个程序,该程序运行10个工作线程,用于计算空间中对象的轨迹。他们还必须画出物体的路径。我有一个“Body”类派生QGraphicsEllipseItem,它有一个QPainterPath。 “模拟”课程列出了世界上的障碍物,以及模拟和运行的身体直到身体与某物碰撞。模拟在一个单独的线程中运行(使用moveToThread完成,而不是通过继承QThread)。当身体发生碰撞时,模拟会发出一个信号表明它已完成。当所有线程都已完成时,我想绘制路径(我通过调用“Body”中的方法来实现它,该方法在其 draw 方法中启用路径绘制)。
不幸的是我收到了ASSERT错误:
ASSERT: "!unindexedItems.contains(item)" in file graphicsview\qgraphicsscenebsptreeindex.cpp, line 364
它们似乎随机发生。我尝试了不同的连接类型,没有结果
我在循环中启动线程。
我正在使用Qt 5.0
答案 0 :(得分:10)
一般来说,使用Qt,你不能在GUI线程之外进行任何GUI操作(即执行QApplication :: exec()的线程,它通常是main()线程。)
因此,如果您有多个线程操纵QGraphicsItems(尤其是当前属于QGraphicsScene的QGraphicsItems),这可能是您断言失败的原因。也就是说,当Qt GUI线程正在进行窗口刷新时,它正在从各种QGraphicsItem对象中读取数据作为其计算的一部分,并且它期望QGraphicsItem在刷新操作的持续时间内保持不变。如果在执行刷新例程时更改(由另一个线程)QGraphicsItem,则主线程进行的计算可能会变得错误/损坏,并且偶尔会导致断言失败(和/或其他不需要的行为)。
如果你真的需要使用多个线程,那么你可能需要做的就是让线程在他们自己的私有数据结构上进行所有计算,这些结构是Qt GUI线程无法访问的。然后,当线程计算了它们的结果时,它们应该将结果发送回Qt GUI线程(通过排队连接或QApplication :: postEvent())。然后GUI线程可以查看结果并使用它们来更新QGraphicsItems等;这将是“安全的”,因为此更新不会在窗口更新过程中发生。
如果这听起来太多了,那么你可能会考虑在GUI线程中做所有事情;通过这种方式使一切工作变得更加容易和简单。
答案 1 :(得分:3)
正如Jeremy所说,Qt渲染必须在主线程上完成。
虽然您可以将其全部移动到主线程,但您可能选择创建单独的线程以提高效率,尤其是因为冲突检测可能是处理器密集型的。处理此问题的最佳方法是将对象及其物理的建模与渲染分开,就像在模型/视图/控制器模式中一样。
创建未从任何QGraphicsItem / Objects派生的正文实例的表示。然后,这些可以在单独的线程上进行计算,并向主线程中运行的图形对象发出信号,这些图形对象更新每个正文实例的图形表示,从而允许实时渲染轨迹。