PyQt Slider没有到达我点击的特定位置,而是移动到某个步幅[重复]

Posted

技术标签:

【中文标题】PyQt Slider没有到达我点击的特定位置,而是移动到某个步幅[重复]【英文标题】:PyQt Slider not come to a specific location where I click but move to a certain stride [duplicate] 【发布时间】:2021-04-28 11:59:19 【问题描述】:

比如我们有一个PYQT5的QSlider实例,从左到右,0到100% 当我单击 50% 的位置时,手柄不会直接移动到 50%,而只会移动一个恒定的步幅。 我该怎么办?

【问题讨论】:

【参考方案1】:

您指的是“绝对集”选项,它完全依赖于当前样式。滑块通过查询关于SH_Slider_AbsoluteSetButtons 的QStyle styleHint() 来检查该行为,它以(可能为空的)Qt.MouseButton 掩码回复。

默认情况下,使用左键在手柄外部按下只会从当前滑块位置向鼠标光标重复滚动,而使用中键按下时会将滑块准确放置在光标所在的位置(取决于操作系统和 QStyle) .

如果你想覆盖它,有两种可能性。

代理样式覆盖

这通过使用 QProxyStyle 并覆盖上述styleHint 来工作。不幸的是,QSlider 只是在没有提供小部件参数的情况下查询有关提示的样式,因此无法知道 哪个 滑块发送了请求。结果是应用程序中的 all QSlider 的行为将变为 全局,除非您仅将样式应用于您想要此行为的那些滑块,但这可能会导致在一些问题和不一致的地方,特别是如果您已经需要使用代理样式。

class ProxyStyle(QtWidgets.QProxyStyle):
    def styleHint(self, hint, opt=None, widget=None, returnData=None):
        res = super().styleHint(hint, opt, widget, returnData)
        if hint == self.SH_Slider_AbsoluteSetButtons:
            res |= QtCore.Qt.LeftButton
        return res

app = QtWidgets.QApplication(sys.argv)
# set the style globally for the application
app.setStyle(ProxyStyle())

slider = QtWidgets.QSlider()
# or just for the slider
slider.setStyle(ProxyStyle())

覆盖mouseButtonPress

此选项依赖于子类化和部分覆盖鼠标按钮按下事件。诀窍是检查按下的按钮,如果滑块当前被按下(以避免按下多个按钮时出现意外行为),然后将滑块移动到鼠标位置,最后调用基础mouseButtonPress实现:因为此时手柄将在鼠标下方,滑块将“相信”手柄已经存在,从而开始实际的滑块移动。

class SliderCustom(QtWidgets.QSlider):
    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton and not self.isSliderDown():
            opt = QtWidgets.QStyleOptionSlider()
            self.initStyleOption(opt)
            sliderRect = self.style().subControlRect(
                QtWidgets.QStyle.CC_Slider, opt, 
                QtWidgets.QStyle.SC_SliderHandle, self)
            if event.pos() not in sliderRect:
                # the mouse is not over the handle, let's move it; this is based
                # on the original C++ code that moves the handle when the
                # "absolute button" is pressed
                grooveRect = self.style().subControlRect(
                    QtWidgets.QStyle.CC_Slider, opt, 
                    QtWidgets.QStyle.SC_SliderGroove, self)
                center = sliderRect.center() - sliderRect.topLeft()
                pos = event.pos() - center
                if self.orientation() == QtCore.Qt.Horizontal:
                    sliderLength = sliderRect.width()
                    sliderMin = grooveRect.x()
                    sliderMax = grooveRect.right() - sliderLength + 1
                    pos = pos.x()
                else:
                    sliderLength = sliderRect.height()
                    sliderMin = grooveRect.y()
                    sliderMax = grooveRect.bottom() - sliderLength + 1
                    pos = pos.y()
                value = self.style().sliderValueFromPosition(
                    self.minimum(), self.maximum(), pos - sliderMin, 
                    sliderMax - sliderMin, opt.upsideDown
                )
                self.setSliderPosition(value)
        super().mousePressEvent(event)

【讨论】:

谢谢你的朋友。这就是我需要的 @Hadid,不客气!请记住,如果某个答案解决了您的问题,您应该通过单击其左侧的灰色勾号将其标记为已接受。

以上是关于PyQt Slider没有到达我点击的特定位置,而是移动到某个步幅[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何到达特定范围内的附近位置?

如何创建自定义 Slider 控件

pyqt5点击按钮从本地加载图片并显示在界面上

wpf 的 slider控件问题

WPF 中的 Slider 控件如何捕捉特定值?

PyQt5 - 如何在鼠标点击位置上画一个点?