1

I ended up with a subclass of QSlider like this:

# via https://stackoverflow.com/a/49744383/6197439
class ListSlider(QSlider):
  def __init__(self, vallist, *args, **kwargs):
    QSlider.__init__(self, *args, **kwargs)
    self.valuelist = vallist
    self.listvalue = None # reserved for actual values of list (.value() will be index)
    self.setMaximum(len(self.valuelist)-1)
    self.valueChanged.connect(self.on_change_value)
    self.on_change_value(0)

  @pyqtSlot(int)
  def on_change_value(self, value):
    self.listvalue = self.valuelist[value]

... and then, have something like:

self.my_list_slider = ListSlider([1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048], Qt.Horizontal)
...
self.my_list_slider.valueChanged.connect(self.self.my_list_slider_valuechange)

...

def my_list_slider_valuechange(self):
  curval = self.my_list_slider.value()
  print("my_list_slider {} {}".format(curval, self.my_list_slider.listvalue))

... and it works, I guess - because when I drag the slider, I get a printout:

my_list_slider 0 1
my_list_slider 1 2
my_list_slider 2 4
my_list_slider 3 8
my_list_slider 4 16
my_list_slider 5 32
my_list_slider 6 64
my_list_slider 7 128
...

... except, I'm kind of nervous about having to manage two variables in the slider - the original value now becoming an index; and the actual value I need, now being derived from the list based on the index.

So, I was wondering - is QSlider possibly capable of handling lists (that is, we slide along the values of a list, not just number range) in this way natively? Or, if not, is there a more recommended/straightforward method, to handle a slider with arbitrary values (that is, values taken from a list)?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
sdbbs
  • 4,270
  • 5
  • 32
  • 87

1 Answers1

2

You can create a new signal that emits the information of the selected index and its corresponding value:

from PyQt5 import QtCore, QtGui, QtWidgets


class ListSlider(QtWidgets.QSlider):
    elementChanged = QtCore.pyqtSignal(int, int)

    def __init__(self, values=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setMinimum(0)
        self._values = []
        self.valueChanged.connect(self._on_value_changed)
        self.values = values or []

    @property
    def values(self):
        return self._values

    @values.setter
    def values(self, values):
        self._values = values
        maximum = max(0, len(self._values) - 1)
        self.setMaximum(maximum)
        self.setValue(0)

    @QtCore.pyqtSlot(int)
    def _on_value_changed(self, index):
        value = self.values[index]
        self.elementChanged.emit(index, value)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = ListSlider(orientation=QtCore.Qt.Horizontal)
    w.values = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]

    def my_list_slider_valuechange(index, value):
        print("my_list_slider {} {}".format(index, value))

    w.elementChanged.connect(my_list_slider_valuechange)

    w.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241