Home > OS >  how to make widget receive mouse release event when context menu appears
how to make widget receive mouse release event when context menu appears

Time:05-27

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 with event.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() is Mouse; 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
  • Related