Home > Net >  QSlider Stylesheet According to a Numpy Array
QSlider Stylesheet According to a Numpy Array

Time:08-27

I have a numpy 1d-array where each entry is either 0 or 1. I want to set the sytle sheet of QSlider systematically according to this numpy array .


Suppose I have a numpy array like this :

import numpy as np
myarray = np.array([0,0,0,1,1,1,0,1,0,1]) #len(myarray) = 10

I want to construct a QSlider with the same length as myarray with background blue whenever myarray reads 1 and background red whenever myarray reads 0. The slider should have no iteraction at all: the user can neither see nor use the handle.

slider = QSlider()
slider.setRange(0, len(myarray)-1)

But I am stuck afterwards: the command

slider.setStyleSheet("QSlider::groove:horizontal {background-color:blue;}")

will give a whole blue bar: enter image description here

What I need is, wherever the array reads 0, it shows red background like this(the picture only paints the first cell to red):enter image description here

I am not sure about how to change parts of it to red. In my program, myarray can be a large array so I probably need a way to programmatically generate a stylesheet, which I don't know how to do.

CodePudding user response:

This cannot be achieved using style sheets, as there is no way to set a different background for each "chunk" of the slider.

The only way to properly "colorize" each value is by using QStyle features. Specifically, we need to use Screenshot of the result

And the code (note that I added ticks to the slider to highlight the alignment of the chunks):

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class SliderChunkWidget(QWidget):
    def __init__(self, slider, values):
        super().__init__()
        self.slider = slider
        self.values = values
        self.setFixedHeight(self.fontMetrics().height())

    def paintEvent(self, event):
        opt = QStyleOptionSlider()
        self.slider.initStyleOption(opt)

        style = self.slider.style()

        # get the extent of the slider handle
        sliderLength = style.pixelMetric(style.PM_SliderLength, opt, self.slider)
        offset = sliderLength // 2
        # the actual space in which the handle can move
        avail = opt.rect.width() - sliderLength

        smin = self.slider.minimum()
        smax = self.slider.maximum()
        # get the position of the first value of the slider
        start = style.sliderPositionFromValue(
            smin, smax, smin, avail)   offset

        # the size of each "chunk"
        chunkSize = avail / (len(self.values) - 1)
        x = start - chunkSize / 2
        chunks = 1
        height = self.height() - 1

        qp = QPainter(self)
        qp.setRenderHint(qp.Antialiasing)
        qp.setPen(Qt.NoPen)

        oldValue = self.values[0]
        for value in self.values[1:]:
            if value != oldValue:
                # the new value is different, draw the previous rectangle
                qp.setBrush(Qt.blue if oldValue else Qt.red)
                rect = QRectF(x, 0, chunks * chunkSize, height)
                qp.drawRect(rect)
                chunks = 1
                x = rect.right()
            else:
                chunks  = 1
            oldValue = value

        # draw the last rectangle
        qp.setBrush(Qt.blue if value else Qt.red)
        qp.drawRect(x, 0, chunks * chunkSize, height)


app = QApplication([])
values = [0, 0, 0, 1, 1, 1, 0, 1, 0, 1]

test = QWidget()
layout = QVBoxLayout(test)

slider = QSlider(Qt.Horizontal, maximum=len(values) - 1)
layout.addWidget(slider)
slider.setTickPosition(slider.TicksBothSides)
slider.setTickInterval(1)

chunkWidget = SliderChunkWidget(slider, values)
layout.addWidget(chunkWidget)

test.show()
app.exec()
  • Related