检测何时按下 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_()
我想根据是否按下修饰键 (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_()