我正在使用PyQt开发GUI。 GUI有一个qListWidget,一个qTableWidget和一个用Mayavi实现的绘图。列表指的是绘制的形状(例如圆柱和圆锥)。当在列表中选择一个形状时,我希望将形状的属性加载到表中(从字典变量中)和要在图中突出显示的形状。我有Mayavi密谋工作正常。此外,如果编辑了表格,我需要重新绘制形状,以反映新的属性值(如圆柱体,如果半径已更改)。
因此,当选择列表项时 - >使用项目的属性(从字典变量)更新表格,突出显示图表上的项目
编辑表格时 - >更新字典变量并重新绘制项目
问题:当我选择一个列表项并将数据加载到表中时,每次更新单元格时都会触发qTableWidget ItemChanged信号,这会触发多次使用不完整数据重新绘制形状。
在以编程方式更新表时,是否存在禁用GUI事件循环的典型方法? (我有使用Excel VBA的经验,在该上下文设置中,Application.EnableEvents = False将阻止每次以编程方式更新单元格时触发WorksheetChange事件。) 我是否应该使用“表更新进行中”变量来阻止在更新表时采取措施? 有没有办法一次更新Table Widget而不是逐项更新? (我承认我目前故意避开模型 - 视图框架,因此qListWIdget和qTableWidget)。
有什么建议吗?
我是第一次发布海报,但却是StackOverflow的长期用户,所以我只是想提前感谢您成为这样一个非常棒的社区!
答案 0 :(得分:11)
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
是包装大量列表/表/树更新的常用方法。之后再次启用时,将执行单个帖子更新。
答案 1 :(得分:6)
对于继承QObject
self.tableWidget.blockSignals(True)
# perform updates, etc
self.tableWidget.blockSignals(False)
答案 2 :(得分:0)
如果禁用整个事件循环,则应用程序将无响应。并且,即使用户没有注意到,操作系统也可以,并提出某种“挂起”通知(如OS X的颜色鲜艳的旋转沙滩球,没有用户会错过)。
您可能希望在不完全禁用事件循环的情况下禁用重新绘制。但即使这样也可能过于激烈。
你真正要做的就是确保表格不再重绘自己(不改变你实现表格视图的方式,你承认这是不理想的,但你有理由)。
因此,只需禁用ItemChanged更新即可。几乎在所有情况下,最简单的方法是在小部件上调用blockSignals(True)
。
在极少数情况下,这将不起作用(或者当您处理的是古代代码,这些代码意味着在基于Qt4和早期的项目中使用时),您仍然可以获得信号的处理程序,将它们藏起来,然后删除它们,然后完成你的工作,然后恢复以前的处理程序。
您可以改为创建处理程序可以访问的标志,并更改它们,以便在设置标志时它们不执行任何操作。这是传统的C做事方式,但通常不是你想用Python做的事情。