python - 我需要在 Qslider 上打几个标记
问题描述
我有一个用 Python 开发的媒体播放器,我创建了一个按钮来提取滑块刻度的实际值,问题是如果我能在滑块上看到它只是为了知道我标记的位置,那就太好了已经提取了。这个想法是每次我按下按钮时,一个标记应该出现在该值位置的滑块上。有谁知道该怎么做?
解决方案
虽然 QSlider 提供了绘制刻度线的可能性,但它们只能用于恒定间隔。
一种可能的解决方案是创建一个自定义小部件,该小部件将滑块“嵌入”到具有适当边距(例如在顶部)的布局中,然后将使用请求的刻度线进行绘制。虽然这个解决方案是有效的,但它可能不是最一致的,因为它会导致整个滑块为刻度占用大量空间。
class TickSlider(QtWidgets.QWidget):
valueChanged = QtCore.pyqtSignal(int)
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(0, 12, 0, 0)
layout.setSpacing(0)
self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, maximum=101)
layout.addWidget(self.slider)
# link slider functions; be aware that this is not usually advised
# and you should better write specific functions that call the actual
# slider methods
self.value = self.slider.value
self.setValue = self.slider.setValue
self.minimum = self.slider.minimum
self.setMinimum = self.slider.setMinimum
self.maximum = self.slider.maximum
self.setMaximum = self.slider.setMaximum
self.ticks = set()
self.slider.valueChanged.connect(self.valueChanged)
def addTick(self, value=None):
if isinstance(value, bool) or value is None:
value = self.slider.value()
if not value in self.ticks and self.minimum() <= value <= self.maximum():
self.ticks.add(value)
self.update()
def removeTick(self, value=None):
if isinstance(value, bool) or value is None:
value = self.slider.value()
if value in self.ticks:
self.ticks.discard(value)
self.update()
def paintEvent(self, event):
if not self.ticks:
return
sliderMin = self.slider.minimum()
sliderMax = self.slider.maximum()
style = self.style()
opt = QtWidgets.QStyleOptionSlider()
self.slider.initStyleOption(opt)
sliderLength = style.pixelMetric(
style.PM_SliderLength, opt, self.slider)
span = style.pixelMetric(
style.PM_SliderSpaceAvailable, opt, self.slider)
qp = QtGui.QPainter(self)
qp.translate(opt.rect.x() + sliderLength / 2, 0)
y = self.slider.y() - 2
for value in sorted(self.ticks):
x = style.sliderPositionFromValue(
sliderMin, sliderMax, value, span)
qp.drawLine(x, 0, x, y)
另一种可能性意味着围绕当前风格进行一些“黑客攻击”。
主要问题来自这样一个事实,即在某些系统和样式中,Qt 使用像素图来绘制对象,这会“覆盖”任何先前在实际滑块“下方”绘制东西的尝试。
诀窍是单独绘制滑块的组件,以便可以在背景(包括手柄移动的凹槽)和实际绘制手柄之前绘制刻度。
这种方法提供了直接使用 QSlider 而不是容器小部件的主要好处。
class TickOverride(QtWidgets.QSlider):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ticks = set()
self.setTickPosition(self.TicksAbove)
def addTick(self, value=None):
if isinstance(value, bool) or value is None:
value = self.value()
if not value in self.ticks and self.minimum() <= value <= self.maximum():
self.ticks.add(value)
self.update()
def removeTick(self, value=None):
if isinstance(value, bool) or value is None:
value = self.value()
if value in self.ticks:
self.ticks.discard(value)
self.update()
def paintEvent(self, event):
qp = QtWidgets.QStylePainter(self)
opt = QtWidgets.QStyleOptionSlider()
style = self.style()
self.initStyleOption(opt)
# draw the groove only
opt.subControls = style.SC_SliderGroove
qp.drawComplexControl(style.CC_Slider, opt)
sliderMin = self.minimum()
sliderMax = self.maximum()
sliderLength = style.pixelMetric(style.PM_SliderLength, opt, self)
span = style.pixelMetric(style.PM_SliderSpaceAvailable, opt, self)
# if the tick option is set and ticks actually exist, draw them
if self.ticks and self.tickPosition():
qp.save()
qp.translate(opt.rect.x() + sliderLength / 2, 0)
grooveRect = style.subControlRect(
style.CC_Slider, opt, style.SC_SliderGroove)
grooveTop = grooveRect.top() - 1
grooveBottom = grooveRect.bottom() + 1
ticks = self.tickPosition()
bottom = self.height()
for value in sorted(self.ticks):
x = style.sliderPositionFromValue(
sliderMin, sliderMax, value, span)
if ticks & self.TicksAbove:
qp.drawLine(x, 0, x, grooveTop)
if ticks & self.TicksBelow:
qp.drawLine(x, grooveBottom, x, bottom)
qp.restore()
opt.subControls = style.SC_SliderHandle
opt.activeSubControls = style.SC_SliderHandle
if self.isSliderDown():
opt.state |= style.State_Sunken
qp.drawComplexControl(style.CC_Slider, opt)
注意:为了简单起见,这个答案显然只涵盖水平滑块,并考虑到 OP 所需的目的。
推荐阅读
- html - jsPDF:ol li::marker 项目在生成的 PDF 中未对齐
- python - python中“w”模式创建的文件保存在哪里?
- python - Seleneum Xpath 点击:我做对了吗?
- unity3d - Unity Quaternion Lerp 方法总是返回 to 值
- ios - Apple Search Ads 证书创建不可用
- javascript - 当事件仅与 bind(this) 一起工作时,js 中的 removeEventListener 如何
- c# - 如何使用计时器制作动画?
- quarkus - Optaplanner 自定义阶段命令在本机构建中失败,找不到生成的 Gizmo 供应商
- android - 有没有办法在特定日期之前在应用订阅中销售?
- node.js - 如何使用 nodejs 中的套接字建立多个客户端和服务器连接?