0

A colleague made a custom QMenu derivative so that one can select multiple entries before the menu closes.

It is triggered via a QToolButton.

The problem is if the menu is large enough it will overlap with the button. The item at the current cursor position then gets selected instantly when clicking the QToolButton.

How does one prevent this?

Code for my menu, I tried to ignore the first event with a Bool flag, but it doesn't work.

class StayOpenMenu(QMenu):
    """
    a class that overrides the QMenu mouseReleaseEvent to let the menu stay open when an element is selected
    """
    def __init__(self, parent=None):
        self.isfirstEvent = True
        super().__init__("Stay open Menu", parent=parent)

    def mouseReleaseEvent(self, a0: QMouseEvent):
        if self.isfirstEvent:
            a0.ignore()
            self.isfirstEvent = False
            return
        try:
            action = self.actionAt(a0.pos())
            action.trigger()
        except:
            pass
    
    def aboutToShow(self):
        self.isfirstEvent = True
        return super().aboutToShow()

    def aboutToHide(self):
        self.isfirstEvent = True
        return super().aboutToShow()

Image: Before clicking the button

Image: After clicking the QToolButton

Raphael
  • 810
  • 6
  • 18

1 Answers1

0

aboutToShow() and aboutToHide() are signals, not methods, so they can't be "overridden".

Create a slot for setting the variable to True and connect it to the aboutToShow signal only.
Also note that you'll have to take care of the mousePressEvent too: if the menu is not activated from a mouse click (most likely by pressing the tool button via keyboard), it will prevent it from receiving a legitimate release event.

class StayOpenMenu(QMenu):
    def __init__(self, parent=None):
        self.isfirstEvent = False
        super().__init__("Stay open Menu", parent=parent)
        self.aboutToShow.connect(self.isShowing)

    def isShowing(self):
        self.isfirstEvent = True

    def mousePressEvent(self, a0: QMouseEvent):
        self.isfirstEvent = False
        super().mousePressEvent(a0)

    def mouseReleaseEvent(self, a0: QMouseEvent):
        if self.isfirstEvent:
            a0.ignore()
            self.isfirstEvent = False
            return
        try:
            action = self.actionAt(a0.pos())
            action.trigger()
        except:
            pass
musicamante
  • 41,230
  • 6
  • 33
  • 58
  • I thought they were member functions, like in .NET. Thanks for explaining! Your code works perfectly. – Raphael Jan 27 '20 at 13:02