On Ubuntu20.04, I can't have the widget receive the mouse release event when context menu appears while Windows can receive. My pyqt version is 5.15.2.
I've considered sending a mouse release event manually, but I don't know which systems will receive the mouse release event when context menu appears, and doing so may cause repeated release events. Is there any better solution?
# 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_()
CodePudding user response:
The general rule is that the context menu event is fired when the right mouse buttons is released on Windows and pressed on Linux.
To avoid inconsistency and have a generic behavior that just ignores the OS and always does the same, you can set an internal flag and check it whenever is required: since the context menu event might take precedence, call a function from both mouse press and context menu.
Remember that:
- if you don't want to handle the context menu event and want it to propagate to the parent (like in your case), the event must be ignored; if you override
contextMenuEvent
this must be done explicitly either withevent.ignore()
or by calling the base implementation, assuming that it does not accept the event; - QLabel might handle the event if the text interaction flag supports mouse/keyboard navigation (to allow the clipboard menu);
- context menu event can also be triggered by the menu-key on the keyboard, so you should ensure that its
reason()
isMouse
; this is not actually required if the function that does the "unpress" part always check for the above flag (and it should), but it's still good practice to check for the reason for completeness and consistency;
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