【问题标题】:Different colours in an arc弧线中的不同颜色
【发布时间】:2020-09-24 17:19:06
【问题描述】:

考虑以下玩具示例:

from PyQt5 import QtWidgets, QtGui, QtCore

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        w = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout()
        w.setLayout(layout)
        self.setCentralWidget(w)

        label = QtWidgets.QLabel()
        canvas = QtGui.QPixmap(400, 300)
        label.setPixmap(canvas)
        layout.addWidget(label)

        def paintEvent():
            painter = QtGui.QPainter(label.pixmap())
            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            painter.setPen(QtCore.Qt.red)
            painter.drawArc(0, 0, 100, 100, 1440, -2880)
            painter.end()

        paintEvent()

        self.show()

app = QtWidgets.QApplication([])
window = MainWindow()
app.exec_()

如何使用任意数量的理想颜色绘制弧线?

我尝试用渐变(线性和锥形)来做,但我无法获得准确的结果。

我想更广泛的问题是在绘制弧线时我可以以某种方式使用不同的笔颜色吗?请注意,圆弧可以是半圆、整圆或介于两者之间的任何东西。

颜色将使用百分比分布。每种颜色都是弧长的一小部分。但我对所有颜色均等间隔的解决方案感到满意。

【问题讨论】:

    标签: python python-3.x pyqt5 pyside2


    【解决方案1】:

    一种可能的解决方案是分段绘制弧线:

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
    
            w = QtWidgets.QWidget()
            layout = QtWidgets.QVBoxLayout()
            w.setLayout(layout)
            self.setCentralWidget(w)
    
            label = QtWidgets.QLabel()
            canvas = QtGui.QPixmap(400, 300)
            canvas.fill(QtGui.QColor("white"))
            label.setPixmap(canvas)
            layout.addWidget(label)
    
            def paint_label():
                painter = QtGui.QPainter(label.pixmap())
                painter.setRenderHint(QtGui.QPainter.Antialiasing)
                r = QtCore.QRect(0, 0, 100, 100)
                delta_angle = -180 * 16
                start_angle = 90 * 16
                values = (1, 2, 3, 4)
                colors = (
                    QtGui.QColor("red"),
                    QtGui.QColor("blue"),
                    QtGui.QColor("green"),
                    QtGui.QColor("yellow"),
                )
                sum_of_values = sum(values)
                for value, color in zip(values, colors):
                    end_angle = start_angle + int((value/sum_of_values) * delta_angle)
                    painter.setPen(color)
                    painter.drawArc(r, start_angle, end_angle - start_angle)
                    start_angle = end_angle
                painter.end()
    
            paint_label()
    
            self.show()
    
    
    def main():
    
        app = QtWidgets.QApplication([])
        window = MainWindow()
        app.exec_()
    
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

      【解决方案2】:

      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)
      

      【讨论】:

        猜你喜欢
        • 2012-01-22
        • 1970-01-01
        • 2014-09-09
        • 1970-01-01
        • 1970-01-01
        • 2016-08-14
        • 1970-01-01
        • 2018-11-26
        • 1970-01-01
        相关资源
        最近更新 更多