检测何时按下 Ctrl(或其他修改键)的正确方法

Proper way to detect when Ctrl (or other modifier key) is pressed

我想根据是否按下修饰键 (Ctrl) 来设置动作。我发现的一种解决方法是安装事件过滤器并使用 QApplication.queryKeyboardModifiers() 检测何时按下 Ctrl,并使用 QApplication.keyboardModifiers() 检测何时释放 Ctrl

from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QApplication, QMainWindow

class MainWindow(QMainWindow):

    ctrl_signal = Signal(bool)

    def __init__(self):
        QMainWindow.__init__(self)
        self.installEventFilter(self)
        self.ctrl_signal.connect(self.ctrl_slot)

    def eventFilter(self, _object, e):
        if QApplication.queryKeyboardModifiers() == Qt.CTRL: # This runs twice, and only on key press (not release)
            print("Ctrl pressed")
            self.ctrl_signal.emit(True)
        elif QApplication.keyboardModifiers() == Qt.CTRL: # This runs once, but only on release
            print("Ctrl released")
            self.ctrl_signal.emit(False)
        return False

    def ctrl_slot(self, e):
        print("e: ", e)  # Do something

app = QApplication([])
window = MainWindow()
window.show()
app.exec_()

不过,我担心这是对 .queryKeyboardModifiers().keyboardModifiers() 函数的无意使用,因此以后可能会导致更多麻烦。 是否有正确的方法来检测修改键何时处于隔离状态pressed/released(即没有按下任何其他键)?

虽然我使用的是 PySide6,但如果有帮助,我会接受 C++ 或 PyQt 的答案。

您目前正在做的是检查每次事件发生时(例如单击、移动、调整大小等)是否按下了 Ctrl 键,似乎这不是您的目标,而只是检测何时发生更改,因此您必须改进 Qt.KeyPress 或 Qt.KeyRelease 事件的过滤器。另一方面,如果您想检测另一个 child 小部件何时消耗事件,您的方法将不起作用,因为它不会传播到 parent,相反,最好将过滤器应用于QWindow由于键盘事件在获得焦点时到达,并不依赖于children.

的逻辑
from PySide6.QtCore import Qt, Signal, QObject, QEvent
from PySide6.QtWidgets import QApplication, QMainWindow


class ControlHelper(QObject):
    ctrl_signal = Signal(bool)

    def __init__(self, window):
        super().__init__(window)
        self._window = window

        self.window.installEventFilter(self)

    @property
    def window(self):
        return self._window

    def eventFilter(self, obj, event):
        if obj is self.window:
            if event.type() == QEvent.KeyPress:
                if event.key() == Qt.Key_Control:
                    self.ctrl_signal.emit(True)
            if event.type() == QEvent.KeyRelease:
                if event.key() == Qt.Key_Control:
                    self.ctrl_signal.emit(False)
        return super().eventFilter(obj, event)


class MainWindow(QMainWindow):
    ctrl_signal = Signal(bool)

    def ctrl_slot(self, e):
        print("e: ", e)


app = QApplication([])
window = MainWindow()
window.show()

helper = ControlHelper(window.windowHandle())
helper.ctrl_signal.connect(window.ctrl_slot)

app.exec_()