6

I'd like to specify the steps that a QSlider can slide, like it is possible for the QSpinBox by using setSingleStep. I tried to use setSingleStep of QAbstractSlider, but this seems to have no effect.

Any ideas?

Daniel Hedberg
  • 5,677
  • 4
  • 36
  • 61
Richard Durr
  • 3,081
  • 3
  • 20
  • 26

4 Answers4

9

Try setting the tickInterval

EDIT

Sorry for the tickInterval, didn't quite thinked about it, however i have this working code and it does what you want using setSingleStep

import sys
from PyQt4.QtGui import QApplication, QSlider, QMainWindow

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

        slider = QSlider()
        slider.setMinimum(0)
        slider.setMaximum(100)

        slider.setTickInterval(20)
        slider.setSingleStep(20)


        self.setCentralWidget(slider)


if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = Window()
    window.show()

    sys.exit(app.exec_())
armonge
  • 3,108
  • 20
  • 36
  • 3
    This works great so far, thanks! But the user is still able to track the slider to values in between the steps. How can this be prevented? – Richard Durr Jan 28 '11 at 17:38
  • I don't think theres much more to do than this, maybe if you can give some background i can provide an alternate approach – armonge Jan 28 '11 at 17:46
  • 4
    Let's say there is a QSlider with a min-value of 0 and a max-value of 100. Now the user shall be able to select 0, 10, 20, .., 90, 100 but not 1,2,3,..21,22,23,..91,92,93...,99 by moving the sliding-knob. – Richard Durr Jan 28 '11 at 17:55
  • Then why not using slider with a range 0 to 10 and in your code multipliying the input by ten? – armonge Jan 28 '11 at 19:55
  • 1
    Possible, but impure. For example using signals and slots to connect a slider and a stepper will not work then. – Richard Durr Jan 29 '11 at 09:38
  • 5
    This doesn't seem to work for PyQt5, I still get steps of 1 even I've set `slider.setTickInterval(50)` and `slider.setSingleStep(50)`. Any idea? – Jason Dec 02 '17 at 14:06
  • Is there a solution ? – PBrockmann Mar 03 '22 at 17:49
  • This works as long as you dont want a float step size. You only need to use `setSingleStep()` unless you also want tick marks. – user3711502 Mar 10 '22 at 22:23
  • As suggested above, the correct way to solve this is to simply set the range to the number of steps (e.g. `0-10`), and set the tick-interval and single-step to `1`. You then just need some simple functions to convert to/from the required final values (e.g. for use with signals and slots). This approach is by far the easiest to implement (see [this answer](https://stackoverflow.com/a/47500102/984421), for example). – ekhumoro Aug 21 '22 at 12:26
1

I extended the QSlider class to limit the user so that they cannot track the slider between the steps. The SetInterval method is equivalent to combining the setTickInterval and setSingleStep methods, but also stops the slider being positioned between tick values.

The class also allows the use of float values as slider limits or intervals and allows the index of the point selected on the slider to be set and read.

class DoubleSlider(qw.QSlider):

    def __init__(self, *args, **kargs):
        super(DoubleSlider, self).__init__( *args, **kargs)
        self._min = 0
        self._max = 99
        self.interval = 1

    def setValue(self, value):
        index = round((value - self._min) / self.interval)
        return super(DoubleSlider, self).setValue(index)

    def value(self):
        return self.index * self.interval + self._min

    @property
    def index(self):
        return super(DoubleSlider, self).value()

    def setIndex(self, index):
        return super(DoubleSlider, self).setValue(index)

    def setMinimum(self, value):
        self._min = value
        self._range_adjusted()

    def setMaximum(self, value):
        self._max = value
        self._range_adjusted()

    def setInterval(self, value):
        # To avoid division by zero
        if not value:
            raise ValueError('Interval of zero specified')
        self.interval = value
        self._range_adjusted()

    def _range_adjusted(self):
        number_of_steps = int((self._max - self._min) / self.interval)
        super(DoubleSlider, self).setMaximum(number_of_steps)
Siyh
  • 1,747
  • 1
  • 17
  • 24
  • This is great, thanks! I found that `valueChanged` still seems to emit the underlying index as opposed to `self.value()`. I was able to address this by connecting a new signal to `valueChanged` that emits `self.value()`. Thanks! – RoHS4U Sep 01 '20 at 07:02
0

My solution is using signal sliderMoved and correct the position. The below example moves slider to value 50 or 100

import sys
from PyQt5.QtGui import QApplication, QSlider, QMainWindow

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

        self.slider = QSlider(self)
        self.slider.setMinimum(0)
        self.slider.setMaximum(100)

        self.slider.setTickInterval(20)
        self.slider.setSingleStep(20)

        self.slider.sliderMoved.connect(self.correct_pos)    

        self.setCentralWidget(self.slider)
     
    def correct_pos(self, pos):
        if pos < 50:
            corrected = 50
        else:
            corrected = 100
        self.slider.setValue(corrected)


if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = Window()
    window.show()

    sys.exit(app.exec_())
LiberiFatali
  • 185
  • 11
-1

setSingleStep() still don't work on slider in PyQt5 now

so I tried this to make the same effect

your_slider = QtWidgets.QSlider()
your_slider.valueChanged.connect(lambda:set_step(step))
flag = 0
def your_func():
    pass
    #func here
def set_step(step):
    value = your_slider.value()//step*step
    your_slider.setValue(value)
    if flag != value:
        flag = value
        your_func()
    

I just learned python for several months

Please correct it if there is a mistake

jiahao.d
  • 1
  • 1
  • setSingleStep() is the step amount that the slider moves for a given input. For QSlider the input is the arrow keys on the keyboard and setSingleStep does indeed work.https://doc.qt.io/qt-6/qabstractslider.html#singleStep-prop – hansonap Jul 25 '23 at 20:23