我的问题是一个简单但令人讨厌的用户体验破坏问题。我试图在QGraphicsScene
上显示大量(成千上万)的自定义QGraphicsItem
。我也需要QGraphicsLayout
,但据我所知,不能简单地在场景中放置布局,因为布局必须设置在QGraphicsWidget
上,然后将小部件添加到场景中。
现在,当我需要加载大量项目并准备显示它们时,场景只是空的,因为我不能使无效或重新绘制上述QGraphicsWidget
。只有最后它才能添加到场景中,否则以后的任何更改都不会显示。
目标:添加某种布局管理到场景->{准备项目->添加项目到布局->显示->准备项目->}重复
但我有:{准备一项->准备另一项->}重复…->将所有内容添加到布局->设置场景布局管理->显示
那么问题来了:有什么方法可以创建一个对场景有响应的布局/容器,在添加新的子对象后重新绘制它自己?
来自Qt手册:
场景发生变化时(例如,项目移动或变换时)QGraphicsScene发出changed()信号。
它没有提到addItem()和removeItem()。希望这些也包括在内。
如果是这样,您可以申请以下内容:
信号处理程序可以"捕捉"更改并请求重新绘制场景(例如通过invalidate())。(Un-)幸运的是,这不会立即重新绘制场景(使用其父视图),但会对重新绘制事件进行排队。因此,在再次传递事件循环之前,不会进行实际的重新绘制。
(事件循环是QApplication的一部分。如果你在用户界面启动的命令中停止应用程序,你会在调用堆栈中发现这样的东西:
Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags)
Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags)
Qt5Cored.dll!QCoreApplication::exec()
)
您可以通过调用QApplication::processEvents()来强制执行此操作。(它甚至是静态的。)AFAIK,如果嵌套事件循环通常没有问题,因为它们已经为此做好了准备(只要没有形成非终止递归)。
然而,这可能需要一些微调,因为过多的重新绘制可能会大大降低应用程序的速度。
设法找到我的错误。它在我为QGraphicsWidget
创建的自定义布局中。
正如医生在设置布局时所说:
当前由布局或其所有子布局管理的所有小部件都会自动重新分配到此项。然后布局无效,并根据该项的geometry()和contentsMargins()调整子窗口小部件的几何图形。未由布局明确管理的子级在将布局分配给此小部件后仍不受布局的影响。
布局设置到小部件后,添加到其中的任何新项目都不会重新分配到小部件,因此它们不会受到影响,也不会显示。
在插入到布局的每个项目上调用QGraphicsLayout::addChildLayoutItem(QGraphicsLayoutItem* newItem)
链接解决了我的问题。