The following code creates a range slider as a Qt widget with a native looks and feel
from PySide2.QtWidgets import * | |
from PySide2.QtCore import * | |
from PySide2.QtGui import * | |
import sys | |
class RangeSlider(QWidget): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
self.first_position = 1 | |
self.second_position = 8 | |
self.opt = QStyleOptionSlider() | |
self.opt.minimum = 0 | |
self.opt.maximum = 10 | |
self.setTickPosition(QSlider.TicksAbove) | |
self.setTickInterval(1) | |
self.setSizePolicy( | |
QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed, QSizePolicy.Slider) | |
) | |
def setRangeLimit(self, minimum: int, maximum: int): | |
self.opt.minimum = minimum | |
self.opt.maximum = maximum | |
def setRange(self, start: int, end: int): | |
self.first_position = start | |
self.second_position = end | |
def getRange(self): | |
return (self.first_position, self.second_position) | |
def setTickPosition(self, position: QSlider.TickPosition): | |
self.opt.tickPosition = position | |
def setTickInterval(self, ti: int): | |
self.opt.tickInterval = ti | |
def paintEvent(self, event: QPaintEvent): | |
painter = QPainter(self) | |
# Draw rule | |
self.opt.initFrom(self) | |
self.opt.rect = self.rect() | |
self.opt.sliderPosition = 0 | |
self.opt.subControls = QStyle.SC_SliderGroove | QStyle.SC_SliderTickmarks | |
# Draw GROOVE | |
self.style().drawComplexControl(QStyle.CC_Slider, self.opt, painter) | |
# Draw INTERVAL | |
color = self.palette().color(QPalette.Highlight) | |
color.setAlpha(160) | |
painter.setBrush(QBrush(color)) | |
painter.setPen(Qt.NoPen) | |
self.opt.sliderPosition = self.first_position | |
x_left_handle = ( | |
self.style() | |
.subControlRect(QStyle.CC_Slider, self.opt, QStyle.SC_SliderHandle) | |
.right() | |
) | |
self.opt.sliderPosition = self.second_position | |
x_right_handle = ( | |
self.style() | |
.subControlRect(QStyle.CC_Slider, self.opt, QStyle.SC_SliderHandle) | |
.left() | |
) | |
groove_rect = self.style().subControlRect( | |
QStyle.CC_Slider, self.opt, QStyle.SC_SliderGroove | |
) | |
selection = QRect( | |
x_left_handle, | |
groove_rect.y(), | |
x_right_handle - x_left_handle, | |
groove_rect.height(), | |
).adjusted(-1, 1, 1, -1) | |
painter.drawRect(selection) | |
# Draw first handle | |
self.opt.subControls = QStyle.SC_SliderHandle | |
self.opt.sliderPosition = self.first_position | |
self.style().drawComplexControl(QStyle.CC_Slider, self.opt, painter) | |
# Draw second handle | |
self.opt.sliderPosition = self.second_position | |
self.style().drawComplexControl(QStyle.CC_Slider, self.opt, painter) | |
def mousePressEvent(self, event: QMouseEvent): | |
self.opt.sliderPosition = self.first_position | |
self._first_sc = self.style().hitTestComplexControl( | |
QStyle.CC_Slider, self.opt, event.pos(), self | |
) | |
self.opt.sliderPosition = self.second_position | |
self._second_sc = self.style().hitTestComplexControl( | |
QStyle.CC_Slider, self.opt, event.pos(), self | |
) | |
def mouseMoveEvent(self, event: QMouseEvent): | |
distance = self.opt.maximum - self.opt.minimum | |
pos = self.style().sliderValueFromPosition( | |
0, distance, event.pos().x(), self.rect().width() | |
) | |
if self._first_sc == QStyle.SC_SliderHandle: | |
if pos <= self.second_position: | |
self.first_position = pos | |
self.update() | |
return | |
if self._second_sc == QStyle.SC_SliderHandle: | |
if pos >= self.first_position: | |
self.second_position = pos | |
self.update() | |
def sizeHint(self): | |
""" override """ | |
SliderLength = 84 | |
TickSpace = 5 | |
w = SliderLength | |
h = self.style().pixelMetric(QStyle.PM_SliderThickness, self.opt, self) | |
if ( | |
self.opt.tickPosition & QSlider.TicksAbove | |
or self.opt.tickPosition & QSlider.TicksBelow | |
): | |
h += TickSpace | |
return ( | |
self.style() | |
.sizeFromContents(QStyle.CT_Slider, self.opt, QSize(w, h), self) | |
.expandedTo(QApplication.globalStrut()) | |
) | |
if __name__ == "__main__": | |
app = QApplication(sys.argv) | |
w = RangeSlider() | |
w.show() | |
# q = QSlider() | |
# q.show() | |
app.exec_() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment