1

Given a set of images, I'd like to move a QSlider such that every step shows a little thumbnail icon just above it representing one of the images. Any tips or suggestions?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241

1 Answers1

3

You have to use a QLabel to show the icon and the valueChanged signal of QSlider to make the icon change.

import sys

from PyQt4.QtCore import pyqtSlot, Qt
from PyQt4.QtGui import QWidget, QVBoxLayout, QLabel, QSlider, QApplication, QPixmap


class Widget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.list_icons = ["icon1.png", "icon2.png", "icon3.png", "icon4.png", "icon5.png", "icon6.png"]

        lay = QVBoxLayout(self)
        self.label = QLabel()
        self.label.setAlignment(Qt.AlignHCenter)
        slider = QSlider(Qt.Horizontal)
        lay.addWidget(self.label)
        lay.addWidget(slider)
        slider.setMaximum(len(self.list_icons)-1)
        slider.valueChanged.connect(self.on_change_value)
        self.on_change_value(0)

    @pyqtSlot(int)
    def on_change_value(self, value):
        icon = self.list_icons[value]
        self.label.setPixmap(QPixmap(icon))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

Update:

It is not necessary to calculate the position, you should only use Qt Style Sheet.

import sys

from PyQt4.QtCore import pyqtSlot, Qt
from PyQt4.QtGui import QWidget, QVBoxLayout, QLabel, QSlider, QApplication, QPixmap


class IconSlider(QSlider):
    def __init__(self, icons, *args, **kwargs):
        QSlider.__init__(self, *args, **kwargs)
        self.icons = icons
        self.setMaximum(len(self.icons)-1)
        self.valueChanged.connect(self.on_change_value)
        self.on_change_value(0)

    @pyqtSlot(int)
    def on_change_value(self, value):
        icon = self.icons[value]
        self.setStyleSheet('''
                QSlider::handle:horizontal{{
                    image: url({});
                    margin: -4px 0;
                }}
            '''.format(icon))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = IconSlider(["icon1.png", "icon2.png", "icon3.png", "icon4.png", "icon5.png", "icon6.png"], Qt.Horizontal)
    w.show()
    sys.exit(app.exec_())

enter image description here

enter image description here

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you! That's helpful. But what I'm most interested in is how to position the icon just above the actual slider's main control. Wonder how I'd get the actual X-position of the slider control, perhaps via mapTo() function? Mind you that's not the same as the value() or (i think) the sliderPosition(). – Coleslaw5000 Apr 10 '18 at 18:51
  • That's cool! I might use it that way, but I had intended for the icon image to float just above the slider's main tick,etc. but I'll use your suggestion and explore a stylesheet solution. Thank you very much! – Coleslaw5000 Apr 10 '18 at 19:03
  • Btw, are you on Windows? On Linux, the stylesheet errors with "ValueError: zero length field name in format". However, we're on the older Python 2.6 / PyQt4.8. – Coleslaw5000 Apr 10 '18 at 19:09
  • lol, good for you! :-) What worked for me is: self.setStyleSheet('''QSlider::handle:horizontal{{ image: url({icon}); margin: -4px 0; }}'''.format(icon=icon)) – Coleslaw5000 Apr 10 '18 at 19:17
  • Just to add, I think I may have found something helpful, thought I'd return the favor ;-) https://doc-snapshots.qt.io/4.8/qstyle.html#sliderPositionFromValue – Coleslaw5000 Apr 10 '18 at 19:22
  • To your function, I added the last two lines: @pyqtSlot(int) def on_change_value(self, value): icon = self.icons[value] self.setStyleSheet('''QSlider::handle:horizontal{{ image: url({icon}); margin: -4px 0; }}'''.format(icon=icon)) val = QStyle.sliderPositionFromValue(self.minimum(), self.maximum(), value, self.width()) print val – Coleslaw5000 Apr 10 '18 at 19:36