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