provided by eyllanesc 的解决方案非常好,但我想展示使用锥形渐变而不是绘制单个圆弧来实现相同结果的可能性。
由于我们想要绘制实际的弧线,因此诀窍是使用边距非常窄的颜色“范围”。
例如,要获得半红半蓝的锥形渐变,我们将使用如下内容:
gradient.setColorAt(.5, QtCore.Qt.red)
# set the next color with a stop very close to the previous
gradient.setColorAt(.500001, QtCore.Qt.blue)
我准备了一个带有小界面的示例来测试它的可能性。
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
w = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout()
w.setLayout(layout)
self.setCentralWidget(w)
panelLayout = QtWidgets.QHBoxLayout()
layout.addLayout(panelLayout)
panelLayout.addWidget(QtWidgets.QLabel('Start'))
self.startSpin = QtWidgets.QSpinBox(maximum=360, suffix='°')
self.startSpin.setValue(90)
panelLayout.addWidget(self.startSpin)
panelLayout.addWidget(QtWidgets.QLabel('Extent'))
self.extentSpin = QtWidgets.QSpinBox(maximum=360, suffix='°')
self.extentSpin.setValue(180)
panelLayout.addWidget(self.extentSpin)
panelLayout.addWidget(QtWidgets.QLabel('Width'))
self.penSpin = QtWidgets.QSpinBox(minimum=1, maximum=20, suffix='px')
self.penSpin.setValue(3)
panelLayout.addWidget(self.penSpin)
self.startSpin.valueChanged.connect(self.updateCanvas)
self.extentSpin.valueChanged.connect(self.updateCanvas)
self.penSpin.valueChanged.connect(self.updateCanvas)
self.colors = []
self.colorSpins = []
colorLayout = QtWidgets.QHBoxLayout()
layout.addLayout(colorLayout)
for color in ('red', 'green', 'blue', 'yellow'):
colorLayout.addWidget(QtWidgets.QLabel(color))
self.colors.append(QtGui.QColor(color))
colorSpin = QtWidgets.QSpinBox(minimum=1, maximum=50, value=25)
colorLayout.addWidget(colorSpin)
colorSpin.valueChanged.connect(self.updateCanvas)
self.colorSpins.append(colorSpin)
self.label = QtWidgets.QLabel()
canvas = QtGui.QPixmap(400, 300)
self.label.setPixmap(canvas)
layout.addWidget(self.label)
self.updateCanvas()
self.show()
def updateCanvas(self):
pm = QtGui.QPixmap(self.label.pixmap().size())
pm.fill(QtCore.Qt.transparent)
painter = QtGui.QPainter(pm)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.translate(.5, .5)
sizes = [spin.value() for spin in self.colorSpins]
total = sum(sizes)
extent = self.extentSpin.value() / 360
grad = QtGui.QConicalGradient(50, 50, self.startSpin.value())
gradPos = 1
# set colors starting from stop 1.0 to (1.0 - extent), since
# conical gradients are always counter-clockwise and the actual arc
# is negative, so it is drawn clockwise
for i, (size, color) in enumerate(zip(sizes, self.colors)):
grad.setColorAt(gradPos, color)
gradPos -= size / total * extent
if i < len(self.colors) - 1:
# extend the color right next to the next value
grad.setColorAt(gradPos + .000001, color)
if extent != 1:
# ensure that the first color is not painted at the edget of the
# last due to antialiasing
grad.setColorAt(0, self.colors[0])
grad.setColorAt(1 - extent, self.colors[-1])
offset = self.penSpin.maximum()
pen = QtGui.QPen(grad, self.penSpin.value(), cap=QtCore.Qt.FlatCap)
painter.setPen(pen)
# move the brush origin so that the conical gradient correctly centered
# in the middle of the ellipse
painter.setBrushOrigin(offset, offset)
painter.drawArc(offset, offset, 100, 100, self.startSpin.value() * 16, -self.extentSpin.value() * 16)
painter.end()
self.label.setPixmap(pm)