从任何小部件获取鼠标按下事件
Get mouse press event from ANY widget
我有一个 QMainWindow 应用程序,里面有多个小部件(按钮、标签等)。
当用户按下应用程序的任意位置时,如何获取事件?
我尝试自定义 mousePressEvent()
功能,但这不接受按下其他小部件(按钮、标签等)时的事件。
解释:
widgets之间鼠标事件的处理是从children到parents,也就是说,如果child不接受事件(不使用),那么它会把事件传递给parent。例如,如果您按下 QPushButton,它会接受事件并且不会通知父级,这与不使用它的 QLabel 不同,因此事件会传递给父级。
工具:
另一方面,监听事件的方法一般有以下几种,如:
覆盖任何方法,如 mousePressEvent、keyPressEvent 等或事件或自定义事件方法。
使用事件过滤器。
解决方案:
另一种方法是将以前的一些方法应用于所有小部件,但您可以放弃当前 objective 的所有小部件,例如:
在第一种和第二种方法中,它将涉及检测何时添加或删除小部件(使用 QEvent::ChildAdded
或 QEvent::ChildRemoved
)。
在第一种方法中,它意味着覆盖多次不可能的方法。
综上所述,问题出在widgets端,但还有其他方案:
重写Q{Core, GUi,}Application
的notify()
方法,验证它是一个widget,属于window,也意味着判断事件是否已经吃完了
侦听与 window (QWindow) 关联的鼠标事件。
这种情况最合理的是第二种方法。
import sys
from PyQt5 import QtCore, QtWidgets
class MouseObserver(QtCore.QObject):
pressed = QtCore.pyqtSignal(QtCore.QPoint)
released = QtCore.pyqtSignal(QtCore.QPoint)
moved = QtCore.pyqtSignal(QtCore.QPoint)
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 self.window is obj:
if event.type() == QtCore.QEvent.MouseButtonPress:
self.pressed.emit(event.pos())
elif event.type() == QtCore.QEvent.MouseMove:
self.moved.emit(event.pos())
elif event.type() == QtCore.QEvent.MouseButtonRelease:
self.released.emit(event.pos())
return super().eventFilter(obj, event)
class MainWindow(QtWidgets.QMainWindow):
pass
def main(args):
app = QtWidgets.QApplication(args)
w = MainWindow()
w.show()
mouse_observer = MouseObserver(w.window().windowHandle())
mouse_observer.pressed.connect(lambda pos: print(f"pressed: {pos}"))
mouse_observer.released.connect(lambda pos: print(f"released: {pos}"))
mouse_observer.moved.connect(lambda pos: print(f"moved: {pos}"))
app.exec_()
if __name__ == "__main__":
main(sys.argv)
我有一个 QMainWindow 应用程序,里面有多个小部件(按钮、标签等)。
当用户按下应用程序的任意位置时,如何获取事件?
我尝试自定义 mousePressEvent()
功能,但这不接受按下其他小部件(按钮、标签等)时的事件。
解释:
widgets之间鼠标事件的处理是从children到parents,也就是说,如果child不接受事件(不使用),那么它会把事件传递给parent。例如,如果您按下 QPushButton,它会接受事件并且不会通知父级,这与不使用它的 QLabel 不同,因此事件会传递给父级。
工具:
另一方面,监听事件的方法一般有以下几种,如:
覆盖任何方法,如 mousePressEvent、keyPressEvent 等或事件或自定义事件方法。
使用事件过滤器。
解决方案:
另一种方法是将以前的一些方法应用于所有小部件,但您可以放弃当前 objective 的所有小部件,例如:
在第一种和第二种方法中,它将涉及检测何时添加或删除小部件(使用
QEvent::ChildAdded
或QEvent::ChildRemoved
)。在第一种方法中,它意味着覆盖多次不可能的方法。
综上所述,问题出在widgets端,但还有其他方案:
重写
Q{Core, GUi,}Application
的notify()
方法,验证它是一个widget,属于window,也意味着判断事件是否已经吃完了侦听与 window (QWindow) 关联的鼠标事件。
这种情况最合理的是第二种方法。
import sys
from PyQt5 import QtCore, QtWidgets
class MouseObserver(QtCore.QObject):
pressed = QtCore.pyqtSignal(QtCore.QPoint)
released = QtCore.pyqtSignal(QtCore.QPoint)
moved = QtCore.pyqtSignal(QtCore.QPoint)
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 self.window is obj:
if event.type() == QtCore.QEvent.MouseButtonPress:
self.pressed.emit(event.pos())
elif event.type() == QtCore.QEvent.MouseMove:
self.moved.emit(event.pos())
elif event.type() == QtCore.QEvent.MouseButtonRelease:
self.released.emit(event.pos())
return super().eventFilter(obj, event)
class MainWindow(QtWidgets.QMainWindow):
pass
def main(args):
app = QtWidgets.QApplication(args)
w = MainWindow()
w.show()
mouse_observer = MouseObserver(w.window().windowHandle())
mouse_observer.pressed.connect(lambda pos: print(f"pressed: {pos}"))
mouse_observer.released.connect(lambda pos: print(f"released: {pos}"))
mouse_observer.moved.connect(lambda pos: print(f"moved: {pos}"))
app.exec_()
if __name__ == "__main__":
main(sys.argv)