PyQt6 在 QSlider 的 paintEvent 中设置自定义矩形
PyQt6 Setting custom rect in QSlider's paintEvent
如何让 QSlider 的 paintEvent 的 rect 变小一点?我想要一个非常薄的滑块,但我希望它能够轻松接收点击,因此它的实际尺寸必须比绘制的尺寸大一点。如果滑块真的很薄,例如 2 个像素,那么尝试抓住手柄或单击它会很烦人。我尝试在 paintEvent
方法中创建自定义 QPaintEvent 并使其矩形高度等于 1-2,然后将其传递给 super().paintEvent(my_new_paint_event)
但它没有用。如何做到这一点?
除了使用 QSS(需要设置 all 属性的样式)之外,唯一可靠的解决方案是使用代理样式。
虽然可以覆盖滑块的 paintEvent()
,但有两个主要问题:
- 更改事件区域完全没有意义,因为它只会更改函数将利用的公开区域(并且该区域也可能会被完全忽略);
- QSlider 的默认
paintEvent()
会在调用样式函数之前根据当前状态和 active/hovered 子控件更新其选项,除非您愿意覆盖一堆其他函数(enter/leave、鼠标 press/move/release、键盘事件等),您只会得到部分有效的结果,不会反映实际的小部件状态;
QSlider 使用 drawComplexControl()
function of QStyle, and this is achieved by providing a set of flags used for the subControls
and activeSubControls
of QStyleOptionSlider.
绘制自己
由于这些控件之一是 SC_SliderGroove
,它是手柄在其上移动的滑块部分,解决方案是将其从 subControls
中删除,然后在您的自己的。请记住,绘画是从下到上进行的,因此必须在 调用基本实现之前 绘制自定义凹槽。
class Style(QtWidgets.QProxyStyle):
def drawComplexControl(self, control, opt, qp, widget=None):
if control == self.CC_Slider:
# get the default rectangle of the groove
groove = self.subControlRect(
control, opt, self.SC_SliderGroove, widget)
# create a small one
if opt.orientation == QtCore.Qt.Horizontal:
rect = QtCore.QRectF(
groove.x(), groove.center().y() - .5,
groove.width(), 2)
else:
rect = QtCore.QRectF(
groove.center().x() - .5, groove.y(),
2, groove.height())
qp.save()
qp.setBrush(opt.palette.mid())
qp.setPen(opt.palette.dark().color())
qp.setRenderHints(qp.Antialiasing)
qp.drawRoundedRect(rect, 1, 1)
qp.restore()
# remove the groove flag from the subcontrol list
opt.subControls &= ~self.SC_SliderGroove
super().drawComplexControl(control, opt, qp, widget)
以上是 PyQt5 和 PySide 通用的,对于 PyQt6,您需要使用它们的类型更改标志名称,如 Qt.Orientation.Horizontal
,等
如何让 QSlider 的 paintEvent 的 rect 变小一点?我想要一个非常薄的滑块,但我希望它能够轻松接收点击,因此它的实际尺寸必须比绘制的尺寸大一点。如果滑块真的很薄,例如 2 个像素,那么尝试抓住手柄或单击它会很烦人。我尝试在 paintEvent
方法中创建自定义 QPaintEvent 并使其矩形高度等于 1-2,然后将其传递给 super().paintEvent(my_new_paint_event)
但它没有用。如何做到这一点?
除了使用 QSS(需要设置 all 属性的样式)之外,唯一可靠的解决方案是使用代理样式。
虽然可以覆盖滑块的 paintEvent()
,但有两个主要问题:
- 更改事件区域完全没有意义,因为它只会更改函数将利用的公开区域(并且该区域也可能会被完全忽略);
- QSlider 的默认
paintEvent()
会在调用样式函数之前根据当前状态和 active/hovered 子控件更新其选项,除非您愿意覆盖一堆其他函数(enter/leave、鼠标 press/move/release、键盘事件等),您只会得到部分有效的结果,不会反映实际的小部件状态;
QSlider 使用 drawComplexControl()
function of QStyle, and this is achieved by providing a set of flags used for the subControls
and activeSubControls
of QStyleOptionSlider.
由于这些控件之一是 SC_SliderGroove
,它是手柄在其上移动的滑块部分,解决方案是将其从 subControls
中删除,然后在您的自己的。请记住,绘画是从下到上进行的,因此必须在 调用基本实现之前 绘制自定义凹槽。
class Style(QtWidgets.QProxyStyle):
def drawComplexControl(self, control, opt, qp, widget=None):
if control == self.CC_Slider:
# get the default rectangle of the groove
groove = self.subControlRect(
control, opt, self.SC_SliderGroove, widget)
# create a small one
if opt.orientation == QtCore.Qt.Horizontal:
rect = QtCore.QRectF(
groove.x(), groove.center().y() - .5,
groove.width(), 2)
else:
rect = QtCore.QRectF(
groove.center().x() - .5, groove.y(),
2, groove.height())
qp.save()
qp.setBrush(opt.palette.mid())
qp.setPen(opt.palette.dark().color())
qp.setRenderHints(qp.Antialiasing)
qp.drawRoundedRect(rect, 1, 1)
qp.restore()
# remove the groove flag from the subcontrol list
opt.subControls &= ~self.SC_SliderGroove
super().drawComplexControl(control, opt, qp, widget)
以上是 PyQt5 和 PySide 通用的,对于 PyQt6,您需要使用它们的类型更改标志名称,如 Qt.Orientation.Horizontal
,等