PyQt Slider 没有到达我点击的特定位置,而是移动到一定的步幅
PyQt Slider not come to a specific location where I click but move to a certain stride
比如我们有一个PYQT5的QSlider实例,从左到右,0到100%
当我点击50%的位置时,手柄不会直接移动到50%,只是移动一个恒定的步幅。
我该怎么办?
您指的是“绝对集”选项,它完全依赖于当前样式。滑块通过查询 QStyle styleHint()
about the SH_Slider_AbsoluteSetButtons
, which replies with a (possibly empty) Qt.MouseButton 掩码来检查该行为。
默认情况下,用左键按下手柄外部只是重复地从当前滑块位置向鼠标光标滚动,而按下中间按钮它会将滑块精确放置在光标所在的位置(取决于 OS 和 QStyle).
如果您想覆盖它,有两种可能性。
代理样式覆盖
这通过使用 QProxyStyle 并覆盖上述 styleHint
来实现。不幸的是,QSlider 只是在不提供小部件参数的情况下查询有关提示的样式,因此无法知道 哪个 滑块发送了请求。结果是应用程序中的 all QSliders 的行为将变为 global,除非您仅将样式应用于您想要此样式的那些滑块行为,但这可能会导致一些问题和不一致,特别是如果您已经需要使用代理样式。
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
此选项依赖于子类化和部分覆盖鼠标按钮按下事件。诀窍是检查按下的按钮,如果当前按下滑块 不是 (以避免按下多个按钮时的意外行为),然后在鼠标位置移动滑块,最后调用 base 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)
比如我们有一个PYQT5的QSlider实例,从左到右,0到100% 当我点击50%的位置时,手柄不会直接移动到50%,只是移动一个恒定的步幅。 我该怎么办?
您指的是“绝对集”选项,它完全依赖于当前样式。滑块通过查询 QStyle styleHint()
about the SH_Slider_AbsoluteSetButtons
, which replies with a (possibly empty) Qt.MouseButton 掩码来检查该行为。
默认情况下,用左键按下手柄外部只是重复地从当前滑块位置向鼠标光标滚动,而按下中间按钮它会将滑块精确放置在光标所在的位置(取决于 OS 和 QStyle).
如果您想覆盖它,有两种可能性。
代理样式覆盖
这通过使用 QProxyStyle 并覆盖上述 styleHint
来实现。不幸的是,QSlider 只是在不提供小部件参数的情况下查询有关提示的样式,因此无法知道 哪个 滑块发送了请求。结果是应用程序中的 all QSliders 的行为将变为 global,除非您仅将样式应用于您想要此样式的那些滑块行为,但这可能会导致一些问题和不一致,特别是如果您已经需要使用代理样式。
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
此选项依赖于子类化和部分覆盖鼠标按钮按下事件。诀窍是检查按下的按钮,如果当前按下滑块 不是 (以避免按下多个按钮时的意外行为),然后在鼠标位置移动滑块,最后调用 base 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)