15

I'm searching for Qt widget like QSlider, but with text tick labels support like this: example widget

This widget I'll use as mode switcher. Have you met something like that?

BiTOk
  • 716
  • 1
  • 6
  • 15

3 Answers3

19

I would use a QSlider with QLabel(s) attached as below. My usual disclaimer goes that you may need some fine-tuning and adjustment on your own for sure.

main.cpp

#include <QMainWindow>
#include <QApplication>
#include <QGridLayout>
#include <QSlider>
#include <QLabel>

class MainWindow Q_DECL_FINAL : public QMainWindow
{
    Q_OBJECT
    public:
        explicit MainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
        {
            QSlider *slider = new QSlider(Qt::Horizontal, this);
            slider->setRange(1, 4);
            slider->setSingleStep(1);
            QLabel *label1 = new QLabel("Novice", this);
            QLabel *label2 = new QLabel("Intermediate", this);
            QLabel *label3 = new QLabel("Advanced", this);
            QLabel *label4 = new QLabel("Expert", this);
            QGridLayout *layout = new QGridLayout;
            layout->addWidget(slider, 0, 0, 1, 4);
            layout->addWidget(label1, 1, 0, 1, 1);
            layout->addWidget(label2, 1, 1, 1, 1);
            layout->addWidget(label3, 1, 2, 1, 1);
            layout->addWidget(label4, 1, 3, 1, 1);
            setLayout(layout);
        }
};

#include "main.moc"

int main(int argc, char **argv)
{
    QApplication application(argc, argv);
    MainWindow mainWindow;
    mainWindow.show();
    return application.exec();
}

main.pro

TEMPLATE = app
TARGET = main
QT += widgets
SOURCES += main.cpp

Build and Run

qmake && make && ./main
László Papp
  • 51,870
  • 39
  • 111
  • 135
3

You can use my extended QSlider class in git.

hassan deldar
  • 293
  • 1
  • 11
  • 1
    Good job, but same problem as Ipapp's answer for vertical sliders. Tick labels are not aligned with ticks. – brahmin Feb 22 '19 at 09:15
  • @brahmin the problem you mentioned is easy to fix by using twice as many columns in the grid, spanning slider from 1st column (instead of 0th) till the second one from the right (instead of rightmost), then spanning each label on two columns, finally using `Qt::AlignHCenter` for them. I can post my modification of @Ipapp 's code that solves this problem if anyone is interested – mvidelgauz Dec 31 '19 at 13:21
2

I had a similar need, I ended up solving it by overriding the paintEvent. Here's a PyQt solution:


class Slider(QSlider):
    """Slider with labels (instead of tick marks) along each available position"""

    def __init__(self, parent=None):
        super(Slider, self).__init__(parent)
        # this decides the range and the labels placed along the slider
        self.values = ['one', 'two', 'three', 'four', 'five']
        self.setOrientation(Qt.Horizontal)
        self.setTickInterval(1)
        self.setTickPosition(QSlider.NoTicks)
        self.setSingleStep(1)
        self.setRange(0, len(self.values) - 1)
        self.setValue(0)

    def paintEvent(self, event):
        QSlider.paintEvent(self, event)

        rect = self.geometry()
        curr_value = str(self.value() / 1000.00)
        round_value = round(float(curr_value), 2)
        # start painter
        painter = QPainter(self)
        painter.setPen(QPen(Qt.black))

        font_metrics = QFontMetrics(self.font())
        font_width = font_metrics.boundingRect(str(round_value)).width()

        for index, value in enumerate(self.values):
            print(index, value)
            # first and last position need a slightly different offset so the text doesn't get cut
            if index == 0:
                # first position
                pos = QStyle.sliderPositionFromValue(self.minimum(), self.maximum(), index, self.width())
                painter.drawText(QPoint(pos, rect.height()), value)
            elif index == len(self.values) - 1:
                # last position
                pos = QStyle.sliderPositionFromValue(self.minimum(), self.maximum(), index, self.width())
                painter.drawText(QPoint(pos - font_width, rect.height()), value)
            else:
                pos = QStyle.sliderPositionFromValue(self.minimum(), self.maximum(), index, self.width())
                painter.drawText(QPoint(pos - font_width / 2.0, rect.height()), value)

Ends up looking something like this:

enter image description here

  • Worked for me. But to make labels placement more precise I used pixelMetric. C++: `QStyleOptionSlider slider; initStyleOption(&slider);` `const int available = style()->pixelMetric(QStyle::PM_SliderSpaceAvailable, &slider, this);` `const int fudge = style()->pixelMetric(QStyle::PM_SliderLength, &slider, this) / 2;` `const int pos = QStyle::sliderPositionFromValue(minimum(), maximum(), i, available) + fudge;` – yrHeTateJlb Dec 05 '22 at 14:52