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;}")
What I need is, wherever the array reads 0, it shows red background like this(the picture only paints the first cell to red):
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
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()