In pyqt5 how can I have a HoverEnter event triggered on a QPushbutton while having the right button of the mouse clicked?

Manos Chaniotakis :

If I have 2 buttons, buttonA and buttonB in a QDialog. When I mouse click on buttonA and move my cursor with the mouse still clicked to buttonB I cant detect a HoverEnter Event. This is probably due to pyqt setting the mouse grab at buttonA. I cant find a way to detect the entering event when the mouse is clicked while entering the buttonB. example code:

class MainDialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(MainDialog, self).__init__()
        self.installEventFilter(self)
        self.buttonA= QtWidgets.QPushButton(MainDialog)
        self.buttonB= QtWidgets.QPushButton(MainDialog)
        self.buttonA.installEventFilter(self)
        self.buttonB.installEventFilter(self)


    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.HoverEnter:
            print("HOVERE ENTER")
            return True

My platform is windows 10 on python 3.7 and pyqt 5

I have also tried to ignore() event after first mouse click in order to lose the mouse grab and also an if self.buttonB.underMouse(): (in the event filter) but still no luck.

musicamante :

The short answer is that when a mouse button is clicked on a widget that accepts the button press event, only that widget will receive mouse move events, until the mouse button is released.

There are various problems in your code that prevent you to get what you want:

  1. you are checking against HoverEnter, but this only works when no mouse button was pressed when entering the widget;
  2. you forgot to return the super().eventFilter(source, event) in case the event type was different (this is very important);
  3. you are using the class as parameter argument for the buttons; you should use the instance (self) instead;
  4. "class" is lower case;

Finally, the enter event cannot be tracked when another widget has "grabbed" the mouse through button click, so you will have to find another way to get it only once, since you can only use the mouse move event to find it.

This is a possible implementation:

class MainDialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(MainDialog, self).__init__()
        layout = QtWidgets.QHBoxLayout(self)
        self.buttonA = QtWidgets.QPushButton('A')
        self.buttonB = QtWidgets.QPushButton('B')
        layout.addWidget(self.buttonA)
        layout.addWidget(self.buttonB)
        self.buttonA.installEventFilter(self)
        self.buttonB.installEventFilter(self)
        self.enterButton = self.pressedButton = None

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.MouseButtonPress and event.button() == QtCore.Qt.LeftButton:
            self.pressedButton = source
        elif event.type() == QtCore.QEvent.MouseMove:
            widget = QtWidgets.QApplication.widgetAt(event.globalPos())
            if widget in (self.buttonA, self.buttonB):
                if widget != self.pressedButton:
                    if self.enterButton != widget:
                        self.enterButton = widget
                        print('Button {} entered!'.format(widget.text()))
                else:
                    self.enterButton = None
        return super().eventFilter(source, event)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=27293&siteId=1