Reputation: 3890
I set the QSlider in QT using the qss style, which I set at the beginning
QSlider::groove: horizontal {
background: rgb(217,221,227);
height: 14px;
border-radius: 7px;
}
QSlider::handle: horizontal {
background: #0078D7;
border: 2px solid white;
width: 10px;
height: 10px;
border-radius: 7px;
}
This all worked fine, but I wanted to add color to the sliding process, so I added it
QSlider::sub-page:horizontal {
background: rgb(56, 121, 216);
height: 8px;
border-radius: 7px;
}
QSlider::add-page:horizontal {
background: rgb(217,221,227);
height: 8px;
border-radius: 7px;
}
But this causes the rounded border to disappear at the start and end positions, how do I display the rounded border properly in this case?
Upvotes: 1
Views: 79
Reputation: 48509
I'm not 100% sure, but I'm afraid that this is not immediately possible by using QSS only.
The problem comes from two aspects:
add-page
and sub-page
rectangles are created based on the groove rectangle and the center of the handle (for instance, for the sub-page
it's the rectangle of the groove "clipped" to the middle of the handle);This is how the QSS implementation draws add-page
and sub-page
subcontrols of QSlider (see the PseudoElement_SliderSubPage
usage in the source code), and there's no way to override that behavior.
The only possible solution would be to use a carefully crafted QSlider subclass that updates its stylesheet based on the value and handle position, considering its size.
For instance, if it's near the minimum and the radius is smaller than half the slider height, we then override the ::groove
background by forcing it to the color of the sub-page
, while setting the sub-page
background to transparent.
The OP doesn't specify the language, and I can't really write proper C++ code, so I'll provide a Python based example that should work as pseudo-code too.
class RoundedSlider(QSlider):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._updateQSS()
def _updateQSS(self):
halfHeight = self.height() // 2
grooveWidth = self.width() - halfHeight * 2
p = self.style().sliderPositionFromValue(
self.minimum(), self.maximum(),
self.value(), grooveWidth
)
if p < halfHeight:
qss = '''
QSlider::groove {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop: 0.0 rgb(56, 121, 216),
stop: 0.5 rgb(56, 121, 216),
stop: 0.5 transparent
);
}
QSlider::sub-page {
background: transparent;
}
QSlider::add-page {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
'''
elif p > grooveWidth - halfHeight:
qss = '''
QSlider::groove {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop: 0.5 transparent,
stop: 0.5 rgb(217, 221, 227),
stop: 1.0 rgb(217, 221, 227)
);
}
QSlider::add-page {
background: transparent;
}
QaSlider::sub-page {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
'''
else:
qss = ''
self.setStyleSheet(qss)
def sliderChange(self, change):
if change == self.SliderValueChange:
self.ensurePolished()
self._updateQSS()
super().sliderChange(change)
def resizeEvent(self, event):
super().resizeEvent(event)
self._updateQSS()
app = QApplication([])
app.setStyleSheet('''
QSlider::groove:horizontal {
background: rgb(217, 221, 227);
height: 14px;
border-radius: 7px;
}
QSlider::handle:horizontal {
background: #0078D7;
border: 2px solid white;
width: 10px;
height: 10px;
border-radius: 7px;
}
QSlider::sub-page:horizontal {
background: rgb(56, 121, 216);
border-radius: 7px;
}
QSlider::add-page:horizontal {
background: rgb(217, 221, 227);
border-radius: 7px;
}
''')
test = QWidget()
layout = QVBoxLayout(test)
for i in range(4):
layout.addWidget(RoundedSlider(Qt.Horizontal, maximum=50, value=i * 2))
test.show()
app.exec()
Note that the above implementation is only acceptable for horizontal and not inverted sliders. If you need to work with vertical sliders or inverted values, you will have to fix it up accordingly. Moreover, note that the usage of linear gradients is to avoid small artifacts caused by antialiasing at the rounded borders.
In any case, remember that QSS should always be used with caution and awareness. If you need a specially styled widget, it's probably better to completely implement it on your own by subclassing, overriding paintEvent()
and all other actions that are based on QStyle functions (eg.: sizeHint()
, mouse event handlers, etc.).
Finally, be aware that your initial QSS has an important syntax error, since you added a space within QSlider::groove: horizontal
and QSlider::handle: horizontal
. I didn't check if the latest Qt version is able to work around that, but it's still an invalid syntax that should be avoided in any case, since spaces in style sheet selectors are used as separators for descendants.
Upvotes: 0