9

我正在用 PyQt 开发一个 GUI。GUI 有一个 qListWidget、一个 qTableWidget 和一个用 Mayavi 实现的绘图。该列表指的是绘制的形状(例如圆柱体和圆锥体)。在列表中选择形状时,我希望将形状的属性加载到表中(从字典变量)并在图中突出显示形状。我的 Mayavi 绘图工作正常。此外,如果表格被编辑,我需要重新绘制形状,以反映新的属性值(如圆柱体,如果半径改变)。

So, when a list item is selected -> update the table with the item's properties (from a dictionary variable), highlight the item on the plot

编辑表格时 -> 更新字典变量并重新绘制项目

问题:当我选择一个列表项并将数据加载到表中时,每次更新单元格时都会触发 qTableWidget ItemChanged 信号,这会触发多次使用不完整数据重新绘制形状。

在以编程方式更新表时,是否有禁用 GUI 事件循环的典型方法?(我有使用 Excel VBA 的经验,在该上下文中设置 Application.EnableEvents=False 将防止在每次以编程方式更新单元格时触发 WorksheetChange 事件。)我是否应该有一个“正在进行的表更新”变量来防止在表正在更新?有没有办法一次更新表格小部件而不是逐项更新?(我承认我暂时有意避免使用 Model-View 框架,因此使用 qListWIdget 和 qTableWidget)。

有什么建议么?

我是第一次发帖,但是 StackOverflow 的长期用户,所以我只想提前感谢您成为如此棒的社区!

4

3 回答 3

15

blockSignals(bool)旨在抑制QObjects及其子类发出信号,从而防止任何其他对象在插槽中接收它们。但这是一种QObject方法。如果您特别试图阻止一个对象发出信号以响应您所做的更改,这可能会触发插槽中的计算或其他一些昂贵的处理,那么这就是您想要的。

但是,如果您的情况是进行重复更改会导致反复进行昂贵的绘制操作(或在小部件上生成其他昂贵的事件),那么您可以使用updatesEnabled(bool). 这种方法的一个好处是它递归地禁用目标小部件的子部件,从而阻止它们被更新。因此,在您再次启用之前,层次结构中的任何内容都不会收到更新。

mainWidget.setUpdatesEnabled(False)
# do a bunch of operations that would trigger expensive events
# like repaints
mainWidget.setUpdatesEnabled(True)

最终,这取决于问题的根源是来自触发信号还是触发小部件事件。阻塞信号仍将允许小部件处理其事件,但不会通知任何其他侦听器。updatesEnabled是包装许多列表/表/树更新的常用方法。之后再次启用时,将执行单个帖子更新。

于 2012-12-08T20:22:16.773 回答
11

对于继承的任何对象,可以暂时阻止QObject信号:

self.tableWidget.blockSignals(True)
# perform updates, etc
self.tableWidget.blockSignals(False)
于 2012-12-07T22:59:43.240 回答
0

如果您禁用整个事件循环,应用程序将变得无响应。而且,即使用户没有注意到,操作系统也可能会发出某种“挂起”通知(就像 OS X 的色彩鲜艳的旋转沙滩球,用户永远不会错过)。

您可能希望在不完全禁用事件循环的情况下禁用重绘。但即使这样也可能太激烈了。

您真正要做的就是确保表格停止重绘本身(不改变您实现表格视图的方式,您承认这并不理想,但您有理由这样做)。

因此,只需禁用 ItemChanged 更新。几乎在所有情况下,最简单的方法是调用blockSignals(True)小部件。

在极少数情况下这不起作用(或者当您正在处理旨在用于基于 Qt4 和早期项目的古老代码时),您仍然可以获得信号的处理程序,将它们存储起来离开,删除它们,然后做你的工作,然后恢复以前的处理程序。

您可以改为创建处理程序可以访问的标志,并更改它们,以便在设置标志时它们不执行任何操作。这是传统的 C 做事方式,但通常不是您想要在 Python 中做的事情。

于 2012-12-07T22:25:32.780 回答