我的目标是使用 PySide2 模块在 Python 3中创建具有刻度的自定义 QSlider 和刻度标签。为此,我在派生类中编辑QSlider类的默认paintEvent。但是,事实证明,可打印区域有限,并且裁切了我放置的顶部/底部标签(请参见屏幕截图)。我用来生成这些滑块的代码如下:
import sys
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
slider_x = 150
slider_y = 450
slider_step = [0.01, 0.1, 1, 10, 100] # in microns
class MySlider(QSlider):
def __init__(self, type, parent=None):
super(MySlider, self).__init__(parent)
self.Type = type
def paintEvent(self, event):
super(MySlider, self).paintEvent(event)
qp = QPainter(self)
pen = QPen()
pen.setWidth(2)
pen.setColor(Qt.red)
qp.setPen(pen)
font = QFont('Times', 10)
qp.setFont(font)
self.setContentsMargins(50, 50, 50, 50)
# size = self.size()
# print(size)
# print("margins", self.getContentsMargins())
# print(self.getContentsMargins())
# print(self.contentsRect())
contents = self.contentsRect()
self.setFixedSize(QSize(slider_x, slider_y))
max_slider = self.maximum()
y_inc = 0
for i in range(max_slider):
qp.drawText(contents.x() - font.pointSize(), y_inc + font.pointSize() / 2, '{0:2}'.format(slider_step[i]))
qp.drawLine(contents.x() + font.pointSize(), y_inc, contents.x() + contents.width(), y_inc)
y_inc += slider_y/4
class Window(QWidget):
""" Inherits from QWidget """
def __init__(self):
super().__init__()
self.title = 'Control Stages'
self.left = 10
self.top = 10
self.width = 320
self.height = 100
self.AxesMapping = [0, 1, 2, 3]
self.initUI()
def initUI(self):
""" Initializes the GUI either using the grid layout or the absolute position layout"""
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
Comp4 = self.createSlider("step_size")
Comp5 = self.createSlider("speed")
windowLayout = QGridLayout()
windowLayout.setContentsMargins(50, 50, 50, 50)
HGroupBox = QGroupBox()
layout = QGridLayout()
layout.addWidget(Comp4, 0, 0)
layout.addWidget(Comp5, 0, 1)
HGroupBox.setLayout(layout)
HGroupBox.setFixedSize(QSize(740, 480))
windowLayout.addWidget(HGroupBox, 0, 0)
self.setLayout(windowLayout)
self.show()
def createSlider(self, variant):
Slider = MySlider(Qt.Vertical)
Slider.Type = variant
Slider.setMaximum(5)
Slider.setMinimum(1)
Slider.setSingleStep(1)
Slider.setTickInterval(1)
Slider.valueChanged.connect(lambda: self.sliderChanged(Slider))
return Slider
@staticmethod
def sliderChanged(Slider):
print("Slider value changed to ", Slider.value(), "slider type is ", Slider.Type)
if Slider.Type == "step_size":
print("this is a step size slider")
elif Slider.Type == "speed":
print("this is a speed slider")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
sys.exit(app.exec_())
是否可以扩展QSlider周围的可绘制区域,如果可以,如何实现此效果?您可以在屏幕截图上看到,第一个和最后一个刻度线旁边的红色标签没有正确显示,并且被裁剪了(即,在第一个刻度线标签中,标记0.01缺少1和0的顶部)。
编辑:尝试了建议的解决方案后,顶部标签的一部分仍然被剪掉。下面的第二个版本在带有PySide2 5.12.0和Python 3.6.6的Windows 10 64位上仍然相似。
EDIT2 我有一个双启动系统,所以我在带有Python 3.5.2 / PySide 5.12.0的Ubuntu 16.04.3 LTS上尝试了它,并且开箱即用。这是那里的屏幕截图,但不幸的是它必须在Windows上可以使用。
答案 0 :(得分:4)
我的建议是调查QSlider继承的QAbstractSlider。它包含一个称为triggerAction(SliderToMaximum值为6)的方法,当set the Slider Position时可以用于action is triggered。
触发动作的语法是
QAbstractSlider.triggerAction (self, SliderAction action)
SliderAction的值如下:
QAbstractSlider.SliderNoAction 0 QAbstractSlider.SliderSingleStepAdd 1
QAbstractSlider.SliderSingleStepSub 2
QAbstractSlider.SliderPageStepAdd 3
QAbstractSlider.SliderPageStepSub 4
QAbstractSlider.SliderToMinimum 5
QAbstractSlider.SliderToMaximum 6
QAbstractSlider.SliderMove 7
(source)
使用PySide2,您可以使用
调用这些方法PySide2.QtWidgets.QAbstractSlider.maximum() //returns the value of the maximum
或
PySide2.QtWidgets.QAbstractSlider.setMaximum(arg) // pass your own value
答案 1 :(得分:3)
如果我做对了,您希望刻度线在顶部和底部都可见,因为由于边距,它们似乎被“割掉了”。 我认为这是假设小部件边距正确设置为零或类似的结果,您可以尝试更改数字并看到这种效果。 (我尝试移动页边距,但没有成功)
现在,在old post之后,我注意到实现类似的目标似乎很棘手,您可以基于{的minimum
和maximum
{1}}。
由于底部的勾号位于主窗口小部件的下方,因此您只需为其添加特殊条件即可使其可见。
不想粘贴整个代码,但是您只需要在循环之前声明QSlider
和opt
。计算内部的handle
位置,并用它代替您的y
。
y_inc
编辑:在Windows上似乎有一个大约10个单位的最高边距,这是IMHHO在Qt中的一个错误。一种解决方法是替换:
def paintEvent(self, event):
super(MySlider, self).paintEvent(event)
qp = QPainter(self)
pen = QPen()
pen.setWidth(2)
pen.setColor(Qt.red)
qp.setPen(pen)
font = QFont('Times', 10)
qp.setFont(font)
self.setContentsMargins(50, 50, 50, 50)
# size = self.size()
# print(size)
# print("margins", self.getContentsMargins())
# print(self.getContentsMargins())
# print(self.contentsRect())
contents = self.contentsRect()
self.setFixedSize(QSize(slider_x, slider_y))
# New code
max_slider = self.maximum()
min_slider = self.minimum()
len_slider = max_slider - min_slider
height = self.height()
opt = QStyleOptionSlider()
handle = self.style().subControlRect(QStyle.CC_Slider, opt, QStyle.SC_SliderHandle, self)
handle_height = handle.height() # Add +10 on windows (workarount)
height_diff = height - handle_height
point_size = font.pointSize()
for i in range(max_slider):
y = round(((1 - i / len_slider) * height_diff + (handle_height / 2.0))) - 1
# Trick for the tick at the bottom
if i == 0:
y = self.height() - handle_height/2.0 # To have the tick in the middle
#y = height_diff # to shift it a bit
qp.drawText(contents.x() - point_size, y + point_size / 2, '{0:2}'.format(slider_step[len_slider - i]))
qp.drawLine(contents.x() + point_size, y, contents.x() + contents.width(), y)
使用
handle_height = handle.height()
在handle_height = handle.height() + 10
方法内部。
答案 2 :(得分:2)
摆弄更多东西后,我终于找到了解决方案。它包括样式表,我之前曾尝试过。但是,那时我无法正确实现它。 II使小部件尺寸保持恒定,但减小了凹槽长度,以便能够将标签适合可打印区域内。完整的代码如下:
import sys
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
slider_x = 150
slider_y = 450
slider_step = [0.01, 0.1, 1, 10, 100] # in microns
groove_y = 400
handle_height = 10
class MySlider(QSlider):
def __init__(self, type, parent=None):
# super(MySlider, self).__init__(parent)
super().__init__()
self.parent = parent
self.Type = type
# self.setFixedHeight(115)
self.setStyleSheet("""QSlider::groove:vertical {
border: 1px solid black;
height: """ + str(groove_y) + """ px;
width: 10px;
border-radius: 2px;
}
QSlider::handle:vertical {
background: red;
border: 1px solid red;
height: """ + str(handle_height) + """ px;
margin: 2px 0;
border-radius: 1px;
}
QSlider::add-page:vertical {
background: blue;
}
QSlider::sub-page:vertical {
background: red;
""")
def paintEvent(self, event):
super(MySlider, self).paintEvent(event)
qp = QPainter(self)
pen = QPen()
pen.setWidth(2)
pen.setColor(Qt.black)
qp.setPen(pen)
font = QFont('Times', 10)
qp.setFont(font)
self.setContentsMargins(50, 50, 50, 50)
self.setFixedSize(QSize(slider_x, slider_y))
contents = self.contentsRect()
max = self.maximum()
min = self.minimum()
y_inc = slider_y - (slider_y - groove_y) / 2
for i in range(len(slider_step)):
qp.drawText(contents.x() - 2 * font.pointSize(), y_inc + font.pointSize() / 2, '{0:3}'.format(slider_step[i]))
qp.drawLine(contents.x() + 2 * font.pointSize(), y_inc, contents.x() + contents.width(), y_inc)
y_inc -= groove_y / (max - min)
class Window(QWidget):
""" Inherits from QWidget """
def __init__(self):
super().__init__()
self.title = 'Control Stages'
self.left = 10
self.top = 10
self.width = 320
self.height = 100
self.AxesMapping = [0, 1, 2, 3]
self.initUI()
def initUI(self):
""" Initializes the GUI either using the grid layout or the absolute position layout"""
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
Comp4 = self.createSlider("step_size")
Comp5 = self.createSlider("speed")
windowLayout = QGridLayout()
windowLayout.setContentsMargins(50, 50, 50, 50)
HGroupBox = QGroupBox()
layout = QGridLayout()
layout.addWidget(Comp4, 0, 0)
layout.addWidget(Comp5, 0, 1)
HGroupBox.setLayout(layout)
HGroupBox.setFixedSize(QSize(740, 480))
windowLayout.addWidget(HGroupBox, 0, 0)
self.setLayout(windowLayout)
self.show()
def createSlider(self, variant):
Slider = MySlider(Qt.Vertical)
Slider.Type = variant
Slider.setMaximum(len(slider_step))
Slider.setMinimum(1)
Slider.setSingleStep(1)
Slider.setTickInterval(1)
Slider.valueChanged.connect(lambda: self.sliderChanged(Slider))
return Slider
@staticmethod
def sliderChanged(Slider):
print("Slider value changed to ", Slider.value(), "slider type is ", Slider.Type)
if Slider.Type == "step_size":
print("this is a step size slider")
elif Slider.Type == "speed":
print("this is a speed slider")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
sys.exit(app.exec_())