出现上下文菜单时如何使小部件接收鼠标释放事件
how to make widget receive mouse release event when context menu appears
在 Ubuntu20.04 上,当出现上下文菜单时,我无法让小部件接收鼠标释放事件,而 Windows 可以接收。我的pyqt版本是5.15.2.
我考虑过手动发送鼠标释放事件,但我不知道出现上下文菜单时哪些系统会收到鼠标释放事件,这样做可能会导致重复释放事件。有没有更好的解决方案?
# coding:utf-8
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMenu, QLabel
class Menu(QMenu):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.addAction('action 1')
self.addAction('action 2')
def showEvent(self, e):
print('show context menu')
super().showEvent(e)
class Widget(QLabel):
def mousePressEvent(self, e):
print('mouse press, button:', e.button())
super().mousePressEvent(e)
def mouseReleaseEvent(self, e):
print('mouse release, button:', e.button())
super().mouseReleaseEvent(e)
class Demo(QWidget):
def __init__(self):
super().__init__()
self.widget = Widget('Click Me', self)
self.widget.move(175, 180)
self.resize(400, 400)
def contextMenuEvent(self, e):
menu = Menu(self)
menu.exec(e.globalPos())
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Demo()
w.show()
app.exec_()
一般规则是在 Windows 上释放鼠标右键并在 Linux 上按下鼠标右键时触发上下文菜单事件。
为了避免不一致并具有忽略 OS 并始终执行相同操作的通用行为,您可以设置一个内部标志并在需要时检查它:因为上下文菜单事件可能优先,通过 鼠标按下和上下文菜单调用函数。
记住:
- 如果您不想处理上下文菜单事件并希望它传播到父级(如您的情况),则必须 忽略该事件;如果您覆盖
contextMenuEvent
,则必须使用 event.ignore()
或通过调用基本实现显式完成,假设它 不 接受事件;
- 如果文本交互标志支持 mouse/keyboard 导航(以允许剪贴板菜单),QLabel 可能会处理该事件;
- 快捷菜单事件也可以由键盘上的menu-key触发,所以你要保证它的
reason()
是Mouse
;如果执行“unpress”部分的函数总是检查上面的标志(它应该),这实际上不是必需的,但检查完整性和一致性的原因仍然是一个好习惯;
class Widget(QLabel):
_isPressed = False
def mousePressEvent(self, e):
print('mouse press, button:', e.button())
super().mousePressEvent(e)
self._isPressed = True
def mouseReleaseEvent(self, e):
super().mouseReleaseEvent(e)
self.unpress()
def contextMenuEvent(self, e):
super().contextMenuEvent(e)
# or, alternatively:
e.ignore()
if e.reason() == e.Mouse:
self.unpress()
def unpress(self):
if not self._isPressed:
return
self._isPressed = True
# do whatever you need
在 Ubuntu20.04 上,当出现上下文菜单时,我无法让小部件接收鼠标释放事件,而 Windows 可以接收。我的pyqt版本是5.15.2.
我考虑过手动发送鼠标释放事件,但我不知道出现上下文菜单时哪些系统会收到鼠标释放事件,这样做可能会导致重复释放事件。有没有更好的解决方案?
# coding:utf-8
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMenu, QLabel
class Menu(QMenu):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.addAction('action 1')
self.addAction('action 2')
def showEvent(self, e):
print('show context menu')
super().showEvent(e)
class Widget(QLabel):
def mousePressEvent(self, e):
print('mouse press, button:', e.button())
super().mousePressEvent(e)
def mouseReleaseEvent(self, e):
print('mouse release, button:', e.button())
super().mouseReleaseEvent(e)
class Demo(QWidget):
def __init__(self):
super().__init__()
self.widget = Widget('Click Me', self)
self.widget.move(175, 180)
self.resize(400, 400)
def contextMenuEvent(self, e):
menu = Menu(self)
menu.exec(e.globalPos())
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Demo()
w.show()
app.exec_()
一般规则是在 Windows 上释放鼠标右键并在 Linux 上按下鼠标右键时触发上下文菜单事件。
为了避免不一致并具有忽略 OS 并始终执行相同操作的通用行为,您可以设置一个内部标志并在需要时检查它:因为上下文菜单事件可能优先,通过 鼠标按下和上下文菜单调用函数。
记住:
- 如果您不想处理上下文菜单事件并希望它传播到父级(如您的情况),则必须 忽略该事件;如果您覆盖
contextMenuEvent
,则必须使用event.ignore()
或通过调用基本实现显式完成,假设它 不 接受事件; - 如果文本交互标志支持 mouse/keyboard 导航(以允许剪贴板菜单),QLabel 可能会处理该事件;
- 快捷菜单事件也可以由键盘上的menu-key触发,所以你要保证它的
reason()
是Mouse
;如果执行“unpress”部分的函数总是检查上面的标志(它应该),这实际上不是必需的,但检查完整性和一致性的原因仍然是一个好习惯;
class Widget(QLabel):
_isPressed = False
def mousePressEvent(self, e):
print('mouse press, button:', e.button())
super().mousePressEvent(e)
self._isPressed = True
def mouseReleaseEvent(self, e):
super().mouseReleaseEvent(e)
self.unpress()
def contextMenuEvent(self, e):
super().contextMenuEvent(e)
# or, alternatively:
e.ignore()
if e.reason() == e.Mouse:
self.unpress()
def unpress(self):
if not self._isPressed:
return
self._isPressed = True
# do whatever you need