如何在 Python 中使用 QSignalBlocker?

How to use QSignalBlocker in Python?

我正在寻找特定于 Python 的文档,或者——更好的是——显示如何使用 QSignalBlocker 的 Python 代码示例片段。将不胜感激。

QSignalBlocker class 有一个简单的行为:当它被设置为 QObject 时,来自 QObject 的信号发射被阻止,使用 unblock() 方法移除阻止,使用 reblock()又被封了

在下面的示例中,如果单选按钮未被选中,则每次从 QComboBox 中选择一个项目时,它将通过信号将所选文本传输到 QLabel,如果单选按钮被选中,则信号将不会发射,因此QLabel 不会显示 QComboBox 选择的文本:

from PyQt5 import QtCore, QtGui, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        radiobutton = QtWidgets.QRadioButton("block/unblock")
        self.m_label = QtWidgets.QLabel()
        self.m_combobox = QtWidgets.QComboBox()
        self.m_combobox.addItems(
            [
                "Monday",
                "Tuesday",
                "Wednesday",
                "Thursday",
                "Friday",
                "Saturday",
                "Sunday",
            ]
        )

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(radiobutton)
        lay.addWidget(self.m_label)
        lay.addWidget(self.m_combobox)

        self.m_blocker = QtCore.QSignalBlocker(self.m_combobox)
        self.m_blocker.unblock()
        self.m_combobox.currentTextChanged.connect(self.m_label.setText)
        radiobutton.toggled.connect(self.on_toggled)

    @QtCore.pyqtSlot(bool)
    def on_toggled(self, state):
        if state:
            self.m_blocker.reblock()
        else:
            self.m_blocker.unblock()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

可以使用 QObject 的 blockSignals() 方法完成相同的逻辑:

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        radiobutton = QtWidgets.QRadioButton("block/unblock")
        self.m_label = QtWidgets.QLabel()
        self.m_combobox = QtWidgets.QComboBox()
        self.m_combobox.addItems(
            [
                "Monday",
                "Tuesday",
                "Wednesday",
                "Thursday",
                "Friday",
                "Saturday",
                "Sunday",
            ]
        )

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(radiobutton)
        lay.addWidget(self.m_label)
        lay.addWidget(self.m_combobox)

        radiobutton.toggled.connect(self.m_combobox.blockSignals)
        self.m_combobox.currentTextChanged.connect(self.m_label.setText)

以上方法有效,但我目前使用的替代机制也有效:

  self.blockSignals(True)
  self.field.clear()
  self.blockSignals(False)

查看 the documation you can see, that the QSignalBlocker provides a __enter__ and a __exit__ function. On __enter__ the signals of the given object are blocked and on __exit__ the blocked state is set to the previous state. You can see this, when you look at the original Qt-documentation for QSignalBlocker 并将 __enter__ 函数视为 C++ 构造函数,将 __exit__ 函数视为 C++ 析构函数。

要利用这些功能,您可以使用 with-statement 并通过此调用有效地阻止信号:

with QSignalBlocker(self.double_spin_box) as blocker:
    self.double_spin_box.setValue(2.5)

此 with 语句会将此调用转换为

blocker = QSignalBlocker(self.double_spin_box)
blocker.__enter__()
try:
    self.double_spin_box.setValue(2.5)
finally:
    blocker.__exit__()