def pixelPosToRangeValue(self, pos): opt = QStyleOptionSlider() self.initStyleOption(opt) gr = self.style().subControlRect( QStyle.CC_Slider, opt, QStyle.SC_SliderGroove, self ) sr = self.style().subControlRect( QStyle.CC_Slider, opt, QStyle.SC_SliderHandle, self ) if self.orientation() == Qt.Horizontal: sliderLength = sr.width() sliderMin = gr.x() sliderMax = gr.right() - sliderLength + 1 else: sliderLength = sr.height() sliderMin = gr.y() sliderMax = gr.bottom() - sliderLength + 1 pr = pos - sr.center() + sr.topLeft() p = pr.x() if self.orientation() == Qt.Horizontal else pr.y() return QStyle.sliderValueFromPosition( self.minimum(), self.maximum(), p - sliderMin, sliderMax - sliderMin, opt.upsideDown, )
def __pixelPosToRangeValue(self, pos): opt = QStyleOptionSlider() self.initStyleOption(opt) style = self.style() gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self) sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self) if self.orientation() == Qt.Horizontal: slider_length = sr.width() slider_min = gr.x() slider_max = gr.right() - slider_length + 1 else: slider_length = sr.height() slider_min = gr.y() slider_max = gr.bottom() - slider_length + 1 return style.sliderValueFromPosition( self.minimum(), self.maximum(), pos - slider_min, slider_max - slider_min, opt.upsideDown, )
def mousePressEvent(self, event): event.accept() style = self.style() button = event.button() # In a normal slider control, when the user clicks on a point in the # slider's total range, but not on the slider part of the control the # control would jump the slider value to where the user clicked. # For this control, clicks which are not direct hits will slide both # slider parts if button: opt = QStyleOptionSlider() self.initStyleOption(opt) self.active_slider = -1 self.setSliderDown(True) for i, value in enumerate([self._low, self._high]): opt.sliderPosition = value hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self) if hit == style.SC_SliderHandle: self.active_slider = i self.pressed_control = hit self.triggerAction(self.SliderMove) self.setRepeatAction(self.SliderNoAction) # self.setSliderDown(True) break if self.active_slider < 0: self.pressed_control = QStyle.SC_SliderHandle self.click_offset = self.__pixelPosToRangeValue( self.__pick(event.pos())) self.triggerAction(self.SliderMove) self.setRepeatAction(self.SliderNoAction) self.update() else: event.ignore()
def showSizeTip(self, _): """ Size Slider Tooltip Trick """ self.style = self.sl_Size.style() self.opt = QStyleOptionSlider() self.sl_Size.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle, self.sl_Size) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.sl_Size.mapToGlobal(pos_local) QToolTip.showText(pos_global, str(self.sl_Size.value()) + " px", self)
def mouseMoveEvent(self, event): if self.pressed_control != QStyle.SC_SliderHandle: event.ignore() return event.accept() new_pos = self.__pixelPosToRangeValue(self.__pick(event.pos())) opt = QStyleOptionSlider() self.initStyleOption(opt) if self.active_slider < 0: offset = new_pos - self.click_offset self._high += offset self._low += offset if self._low < self.minimum(): diff = self.minimum() - self._low self._low += diff self._high += diff if self._high > self.maximum(): diff = self.maximum() - self._high self._low += diff self._high += diff elif self.active_slider == 0: if new_pos >= self._high: new_pos = self._high - 1 self._low = new_pos else: if new_pos <= self._low: new_pos = self._low + 1 self._high = new_pos self.click_offset = new_pos self.update() self.sliderMoved.emit(new_pos) self.activeRangeChanged.emit(self._low, self._high)
def paintEvent(self, event): # based on # http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp painter = QPainter(self) style = self.style() opt = QStyleOptionSlider() self.initStyleOption(opt) groove_rect = style.subControlRect(style.CC_Slider, opt, QStyle.SC_SliderGroove, self) handle_rect = style.subControlRect(style.CC_Slider, opt, QStyle.SC_SliderHandle, self) slider_space = style.pixelMetric(style.PM_SliderSpaceAvailable, opt) range_x1 = style.sliderPositionFromValue(self.minimum(), self.maximum(), self._low, slider_space) range_x2 = style.sliderPositionFromValue(self.minimum(), self.maximum(), self._high, slider_space) range_height = 4 groove_rect = QRectF( groove_rect.x(), handle_rect.center().y() - (range_height / 2), groove_rect.width(), range_height, ) range_rect = QRectF( groove_rect.x() + (handle_rect.width() / 2) + range_x1, handle_rect.center().y() - (range_height / 2), range_x2 - range_x1, range_height, ) if style.metaObject().className() != "QMacStyle": # Paint groove for Fusion and Windows styles cur_brush = painter.brush() cur_pen = painter.pen() painter.setBrush(QBrush(QColor(169, 169, 169))) painter.setPen(Qt.NoPen) # painter.drawRect(groove_rect) painter.drawRoundedRect(groove_rect, groove_rect.height() / 2, groove_rect.height() / 2) painter.setBrush(cur_brush) painter.setPen(cur_pen) cur_brush = painter.brush() cur_pen = painter.pen() # painter.setBrush(QBrush(QColor(18, 141, 148))) # painter.setPen(Qt.NoPen) painter.drawRect(range_rect) painter.setBrush(cur_brush) painter.setPen(cur_pen) for i, value in enumerate([self._low, self._high]): opt = QStyleOptionSlider() self.initStyleOption(opt) # Only draw the groove for the first slider so it doesn't get drawn # on top of the existing ones every time # if i == 0: # opt.subControls = QStyle.SC_SliderGroove | \ # QStyle.SC_SliderHandle # else: opt.subControls = QStyle.SC_SliderHandle if self.tickPosition() != self.NoTicks: opt.subControls |= QStyle.SC_SliderTickmarks if self.isSliderDown(): opt.state |= QStyle.State_Sunken else: opt.state |= QStyle.State_Active if self.pressed_control: opt.activeSubControls = self.pressed_control else: opt.activeSubControls = self.hover_control opt.sliderPosition = value opt.sliderValue = value style.drawComplexControl(QStyle.CC_Slider, opt, painter, self)