pythoneventspyqtmousewheeleventfilter

Update a QLineEdit on a WheelEvent when scroll bar is already set


I'm trying to update a QLineEdit when I do a wheel move on the mouse and if I press a number on the keyboard at the same time. Unfortunatly, I don't see a mouse wheel event for QLineEdit widget so I don't understand how I can set a signal to each QLineEdit. The other issue I have is as the QLineEdit are already in a scroll bar environment, I cannot detect all wheel event because the scroll is done first.

For instance with this code:

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys


class SurfViewer(QMainWindow):
    def __init__(self, parent=None):
        super(SurfViewer, self).__init__()
        self.parent = parent

        self.centralTabs= QTabWidget()
        self.setCentralWidget(self.centralTabs)
        self.setFixedWidth(200)
        self.setFixedHeight(200)

        #tab Model selection
        self.tab_ModelSelect = QWidget()
        self.centralTabs.addTab(self.tab_ModelSelect,"Label")


        self.groupscrolllayouttest = QHBoxLayout() ####
        self.groupscrollbartest = QGroupBox() ####


        self.mainHBOX_param_scene = QVBoxLayout()
        for i in range(10):
            LineEdit = QLineEdit(str(i))
            LineEdit.setFixedWidth(200)
            self.mainHBOX_param_scene.addWidget(LineEdit) 
        self.installEventFilter(self)

        scroll = QScrollArea()
        widget = QWidget(self)
        widget.setLayout(QVBoxLayout())
        widget.layout().addWidget(self.groupscrollbartest)
        scroll.setWidget(widget)
        scroll.setWidgetResizable(True)
        self.groupscrollbartest.setLayout(self.mainHBOX_param_scene)
        self.groupscrolllayouttest.addWidget(scroll)

        self.tab_ModelSelect.setLayout(self.groupscrolllayouttest)

    def eventFilter(self, widget, event):
        if (event.type() == QEvent.Wheel) :
            # get which key is pressed 
            # if the key is a number, put the number in 'num' variable
            # get on which QLineEdit the wheel was make
            # set the text of that QLineEdit to previous value +- num

            event.ignore()
        return QWidget.eventFilter(self, widget, event) 

def main():
    app = QApplication(sys.argv)
    ex = SurfViewer(app)
    ex.setWindowTitle('window')
    # ex.showMaximized()
    ex.show()
    sys.exit(app.exec_( ))


if __name__ == '__main__':
    main()  

I tried to something with wheelevent but as mention, I don't enter in this function because the scroll bar is activated first. I tried to test if the wheel event happend on a QLineEdit but I even struggle to do that...

What I'm seeking to do is when I do a wheelevent with the mouse on a QlineEdit with the '5' key pressed, I want increase or decrease the QLineEdit text by 5 according to the direction of the mouse wheel.

I red some post with eventfilter (as How to get Click Event of QLineEdit in Qt?) but I don't understand how does this work.

In my eventFilter function, I need to do several step:

# get which key is pressed 
# if the key is a number, put the number in 'num' variable
# get on which QLineEdit the wheel was make
# set the text of that QLineEdit to previous value +- num

but I don't know how to make them. In particular getting the pressed key and knowing on which QlineEdit the wheel was made.


Solution

  • If you wish that all QLineEdit have that behavior then it is appropriate that you create your own class and overwrite the necessary events, to avoid that when you move the scroll when the pointer is inside the QLineEdit and pressing an established key, we accept the event so that it does not propage.

    Another recommendation is not to use the 5 key since this is a text that QLineEdit can handle causing problems, for this you can use the SHIFT key:

    class LineEdit(QLineEdit):
        KEY = Qt.Key_Shift
        def __init__(self, *args, **kwargs):
            QLineEdit.__init__(self, *args, **kwargs)
            self.isKeyPressed = False
    
        def keyPressEvent(self, event):
            if event.key() == LineEdit.KEY:
                self.isKeyPressed = True
            QLineEdit.keyPressEvent(self, event)
    
        def keyReleaseEvent(self, event):
            if event.key() == LineEdit.KEY:
                self.isKeyPressed = False
            QLineEdit.keyReleaseEvent(self, event)
    
        def wheelEvent(self, event):
            if self.isKeyPressed:
                delta = 1 if event.angleDelta().y() > 0 else -1
                fn = self.font()
                fn.setPointSize(fn.pointSize() +  delta)
                self.setFont(fn)
                event.accept()
    

    The complete example:

    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    import sys
    
    class LineEdit(QLineEdit):
        KEY = Qt.Key_Shift
        def __init__(self, *args, **kwargs):
            QLineEdit.__init__(self, *args, **kwargs)
            self.isKeyPressed = False
    
        def keyPressEvent(self, event):
            if event.key() == LineEdit.KEY:
                self.isKeyPressed = True
            QLineEdit.keyPressEvent(self, event)
    
        def keyReleaseEvent(self, event):
            if event.key() == LineEdit.KEY:
                self.isKeyPressed = False
            QLineEdit.keyReleaseEvent(self, event)
    
        def wheelEvent(self, event):
            if self.isKeyPressed:
                delta = 1 if event.angleDelta().y() > 0 else -1
                fn = self.font()
                fn.setPointSize(fn.pointSize() +  delta)
                self.setFont(fn)
                event.accept()
    
    class SurfViewer(QMainWindow):
        def __init__(self, parent=None):
            super(SurfViewer, self).__init__()
            self.parent = parent
    
            self.centralTabs= QTabWidget()
            self.setCentralWidget(self.centralTabs)
            self.setFixedWidth(200)
            self.setFixedHeight(200)
    
            #tab Model selection
            self.tab_ModelSelect = QWidget()
            self.centralTabs.addTab(self.tab_ModelSelect,"Label")
    
    
            self.groupscrolllayouttest = QHBoxLayout() ####
            self.groupscrollbartest = QGroupBox() ####
    
    
            self.mainHBOX_param_scene = QVBoxLayout()
            for i in range(10):
                le = LineEdit(str(i))
                le.setFixedWidth(200)
                self.mainHBOX_param_scene.addWidget(le) 
            self.installEventFilter(self)
    
            scroll = QScrollArea()
            widget = QWidget(self)
            widget.setLayout(QVBoxLayout())
            widget.layout().addWidget(self.groupscrollbartest)
            scroll.setWidget(widget)
            scroll.setWidgetResizable(True)
            self.groupscrollbartest.setLayout(self.mainHBOX_param_scene)
            self.groupscrolllayouttest.addWidget(scroll)
            self.tab_ModelSelect.setLayout(self.groupscrolllayouttest)
    
    def main():
        app = QApplication(sys.argv)
        ex = SurfViewer(app)
        ex.setWindowTitle('window')
        # ex.showMaximized()
        ex.show()
        sys.exit(app.exec_( ))
    
    
    if __name__ == '__main__':
        main()