如何在禁用 table 后阻止 QTableWidget 信号?
How can I block QTableWidget signals after disabling the table?
我有一个 python QTableWidget 填充了 4 列。选择任何列运行 qTableWidget.cellClicked() 信号,然后突出显示整行,并运行一堆代码。
self._qTableWidget.cellClicked.connect(self.cellClicked)
def cellClicked(self, row, column):
"""
Handle cell clicked signal.
"""
self._qTableWidget.setDisabled(True)
qTableWidgetItem = self._qTableWidget.item(row, column)
if qTableWidgetItem is None:
return
else:
# ***RUNS SOME CODE***
pass
self._qTableWidget.setEnabled(True)
在代码中,我想在代码运行之前禁用 QTableWidget 接受任何点击,然后启用 QTableWidget(我已尝试使用 setDisabled()/setEnabled())。
但是,如果您单击一个单元格,table 将被正确禁用,但您仍然可以单击 table 中的单元格。当 table 再次启用时,它会在您单击的 QTableWidgetItem 上再次运行 cellClicked() 信号,而 table 被禁用。
我试过使用以下方法:
self._qTableWidget.blockSignals(True)
self._qTableWidget.blockSignals(False)
self._qTableWidget.cellClicked.disconnect(self.cellClicked)
self._qTableWidget.cellClicked.connect(self.cellClicked)
self.setAllCellItemFlags(QtCore.Qt.NoItemFlags)
def setAllCellItemFlags(self, flag):
"""
Sets all QTableWidgetItem flags
"""
for row in range(self._qTableWidget.rowCount()):
for column in range(self._qTableWidget.columnCount()):
qTableWidgetItem = self._qTableWidget.item(row, column)
qTableWidgetItem.setFlags(flag)
这就是您的代码中可能发生的情况:
- 第一次点击到达并发出信号
- 在连接的插槽中禁用(或断开)信号
- 你开始你的代码,当它运行正在运行时它会阻塞主线程中的事件循环
- 同时另一个鼠标点击出现,它创建了鼠标点击事件,但它被放入等待队列等待事件循环能够处理它
- 一段时间后,您的冗长代码完成,您 re-enable(或 re-connect)发出信号
- 事件循环解除阻塞并处理等待的鼠标事件
- 作为对点击事件的响应,发出另一个信号并且连接的插槽再次获得 运行,即转到第 2 步...
如您所见,第二次点击在信号获得 re-enabled 后得到处理。这是您问题的根本原因。您需要做的是 re-enable 事件循环处理等待的鼠标点击(或鼠标点击)后的信号。
最简单的解决方案是在 re-enable 信号之前调用 QApplication.processEvents(QEventLoop.AllEvents, 0)
。这将导致所有点击事件被处理,即被忽略,因为此时信号仍将被禁用。请阅读有关处理还发布(尚未排队)事件的方法的此重载的文档。与没有 ms
参数的其他重载相反,它只处理已经排队的事件。如果值 0
不够,则尝试更长的时间延迟,例如100 毫秒
我有一个 python QTableWidget 填充了 4 列。选择任何列运行 qTableWidget.cellClicked() 信号,然后突出显示整行,并运行一堆代码。
self._qTableWidget.cellClicked.connect(self.cellClicked)
def cellClicked(self, row, column):
"""
Handle cell clicked signal.
"""
self._qTableWidget.setDisabled(True)
qTableWidgetItem = self._qTableWidget.item(row, column)
if qTableWidgetItem is None:
return
else:
# ***RUNS SOME CODE***
pass
self._qTableWidget.setEnabled(True)
在代码中,我想在代码运行之前禁用 QTableWidget 接受任何点击,然后启用 QTableWidget(我已尝试使用 setDisabled()/setEnabled())。
但是,如果您单击一个单元格,table 将被正确禁用,但您仍然可以单击 table 中的单元格。当 table 再次启用时,它会在您单击的 QTableWidgetItem 上再次运行 cellClicked() 信号,而 table 被禁用。
我试过使用以下方法:
self._qTableWidget.blockSignals(True)
self._qTableWidget.blockSignals(False)
self._qTableWidget.cellClicked.disconnect(self.cellClicked)
self._qTableWidget.cellClicked.connect(self.cellClicked)
self.setAllCellItemFlags(QtCore.Qt.NoItemFlags)
def setAllCellItemFlags(self, flag):
"""
Sets all QTableWidgetItem flags
"""
for row in range(self._qTableWidget.rowCount()):
for column in range(self._qTableWidget.columnCount()):
qTableWidgetItem = self._qTableWidget.item(row, column)
qTableWidgetItem.setFlags(flag)
这就是您的代码中可能发生的情况:
- 第一次点击到达并发出信号
- 在连接的插槽中禁用(或断开)信号
- 你开始你的代码,当它运行正在运行时它会阻塞主线程中的事件循环
- 同时另一个鼠标点击出现,它创建了鼠标点击事件,但它被放入等待队列等待事件循环能够处理它
- 一段时间后,您的冗长代码完成,您 re-enable(或 re-connect)发出信号
- 事件循环解除阻塞并处理等待的鼠标事件
- 作为对点击事件的响应,发出另一个信号并且连接的插槽再次获得 运行,即转到第 2 步...
如您所见,第二次点击在信号获得 re-enabled 后得到处理。这是您问题的根本原因。您需要做的是 re-enable 事件循环处理等待的鼠标点击(或鼠标点击)后的信号。
最简单的解决方案是在 re-enable 信号之前调用 QApplication.processEvents(QEventLoop.AllEvents, 0)
。这将导致所有点击事件被处理,即被忽略,因为此时信号仍将被禁用。请阅读有关处理还发布(尚未排队)事件的方法的此重载的文档。与没有 ms
参数的其他重载相反,它只处理已经排队的事件。如果值 0
不够,则尝试更长的时间延迟,例如100 毫秒