Search code examples
pythonpyqt5qtguiqslider

Placing label next to a slider handle


I want a label near the slider's handle, that displays the current value. I used the code provided on the forum and tried to adapt it to Python

from PyQt5 import QtCore, QtGui, QtWidgets

class test(QtWidgets.QWidget):

    def __init__(self, parent = None):
        super().__init__(parent)
        self.main_layout = QtWidgets.QHBoxLayout(self)
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setSpacing(0)
        self.slider = QtWidgets.QSlider(QtCore.Qt.Vertical,self)
        self.slider.setMaximum(100)
        self.slider.setMinimum(0)
        self.slider.setTracking(True)
        self.label= QtWidgets.QLabel(self)
        self.label.setText("label")
        self.main_layout.addWidget(self.slider,0,QtCore.Qt.AlignLeft)
        self.main_layout.addWidget(self.label,0,QtCore.Qt.AlignBottom)
        self.updateLabel(0)
        self.setLayout(self.main_layout)
        self.slider.valueChanged.connect(self.updateLabel)


    def updateLabel(self,value):
        height= QtWidgets.QStyle.sliderPositionFromValue(0,100,self.slider.value(),self.slider.height()-self.label.height(), True)
        self.label.move(self.slider.width(), height)
        self.label.setText(str(value))


    def resizeEvent(self,ev):

        self.updateLabel(self.slider.sliderPosition())


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ui = test()
    ui.show()
    sys.exit(app.exec_())

As a result, I get a label with value, but it is always shown at the bottom of the window.

wrong label position

Once I resize my window, the label moves to the correct place.

correct label position

Do I miss something?


Solution

  • With the help of @ekhumoro and @simon, I fixed the problem

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class test(QtWidgets.QWidget):
    
        def __init__(self, parent = None):
            super().__init__(parent)
            self.main_layout = QtWidgets.QHBoxLayout(self)
            self.main_layout.setContentsMargins(0, 0, 0, 0)
            self.main_layout.setSpacing(0)
            self.slider = QtWidgets.QSlider(QtCore.Qt.Vertical,self)
            self.slider.setMaximum(100)
            self.slider.setMinimum(0)
            self.slider.setTracking(True)
            self.label= QtWidgets.QLabel(self)
            self.label.setText("label")
            self.main_layout.addWidget(self.slider,0,QtCore.Qt.AlignLeft)
            self.updateLabel(0)
            self.setLayout(self.main_layout)
            self.slider.valueChanged.connect(self.updateLabel)
    
    
        def updateLabel(self,value):
            height= QtWidgets.QStyle.sliderPositionFromValue(0,100,self.slider.value(),self.slider.height()-self.label.height(), True)
            self.label.move(self.slider.width(), height)
            self.label.setText(str(value))
    
    
        def resizeEvent(self,ev):
    
            self.updateLabel(self.slider.sliderPosition())
    
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        ui = test()
        ui.show()
        sys.exit(app.exec_())
    
    

    The main difference is not adding the Qlabel inside of the layout, hence having more direct control over its location. One would need to account for label size while using the widget, since by default it's size shrinks to QSlider size