Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving QSlider to Mouse Click Position

I have a QSlider that I want to move to the position of the mouse cursor when the user presses the left mouse button. I've been hunting around and couldn't find anything that was recent and solved my problem.

Progress Bar

This is the slider I have. I want to be able to click to have the slider jump to the position where the mouse clicks. I can drag the slider, but I want to be able to click. I tested out clicking on the slider in the Dolphin file manager. It incremented rather than jumping to the exact position of the mouse.

Looking at the Qt5 documentation

QSlider has very few of its own functions [...]

This would indicate that there is no built-in way to do this. Is there no way to get where the mouse clicked and move the slider to that point?

like image 252
Eamonn Avatar asked Oct 07 '18 13:10

Eamonn


Video Answer


1 Answers

The solution is to make a calculation of the position and set it in the mousePressEvent, the calculation is not easy as an arithmetic calculation since it depends on the style of each OS and the stylesheet so we must use QStyle as shown below:

from PyQt5 import QtCore, QtWidgets


class Slider(QtWidgets.QSlider):
    def mousePressEvent(self, event):
        super(Slider, self).mousePressEvent(event)
        if event.button() == QtCore.Qt.LeftButton:
            val = self.pixelPosToRangeValue(event.pos())
            self.setValue(val)

    def pixelPosToRangeValue(self, pos):
        opt = QtWidgets.QStyleOptionSlider()
        self.initStyleOption(opt)
        gr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderGroove, self)
        sr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderHandle, self)

        if self.orientation() == QtCore.Qt.Horizontal:
            sliderLength = sr.width()
            sliderMin = gr.x()
            sliderMax = gr.right() - sliderLength + 1
        else:
            sliderLength = sr.height()
            sliderMin = gr.y()
            sliderMax = gr.bottom() - sliderLength + 1;
        pr = pos - sr.center() + sr.topLeft()
        p = pr.x() if self.orientation() == QtCore.Qt.Horizontal else pr.y()
        return QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), p - sliderMin,
                                               sliderMax - sliderMin, opt.upsideDown)


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QWidget()
    flay = QtWidgets.QFormLayout(w)
    w1 = QtWidgets.QSlider(QtCore.Qt.Horizontal)
    w2 = Slider(QtCore.Qt.Horizontal)
    flay.addRow("default: ", w1)
    flay.addRow("modified: ", w2)
    w.show()
    sys.exit(app.exec_())
like image 136
eyllanesc Avatar answered Sep 21 '22 19:09

eyllanesc