How to create a 3-color gradient dial indicator (the one that shows green-yellow-red)

喜夏-厌秋 提交于 2021-02-07 19:22:14

问题


Dial-with-static-gradient-indicator

So I have this dial image I'm using for a PyQt widget. Right now, as you can see, the gradient indicator, the arc of green-yellow-red is static and is part of the image.

I want to create this dynamically, so that based on some ranges, the color can be determined. For example, instead of equal parts green and red, I might want about 60 degrees worth of it to be red and the rest green and yellow. For this, I shall specify some range (eg. 0-90 degrees worth should be green etc).

Any ideas on how I can draw such a CURVED color gradient?


回答1:


To accomplish this, one way is to create a widget and do a custom paintEvent. You will build up this result with a couple elements:

  1. Draw the static pixmap of the gauge background
  2. Draw a pie shape with a gradient
  3. Re-fill the center with the original image to cut it back out again

You will need to cache the pixmap once in the init so you don't keep creating it from disk. Then you can give the widget a method to set the value from 0.0 - 1.0.

class GaugeWidget(QtGui.QWidget):

    def __init__(self, initialValue=0, *args, **kwargs):
        super(GaugeWidget, self).__init__(*args, **kwargs)
        self._bg = QtGui.QPixmap("bg.png")
        self.setValue(initialValue)

    def setValue(self, val):
        val = float(min(max(val, 0), 1))
        self._value = -270 * val
        self.update()


    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.setRenderHint(painter.Antialiasing)
        rect = event.rect()

        gauge_rect = QtCore.QRect(rect)
        size = gauge_rect.size()
        pos = gauge_rect.center()
        gauge_rect.moveCenter( QtCore.QPoint(pos.x()-size.width(), pos.y()-size.height()) )
        gauge_rect.setSize(size*.9)
        gauge_rect.moveCenter(pos)

        refill_rect = QtCore.QRect(gauge_rect)
        size = refill_rect.size()
        pos = refill_rect.center()
        refill_rect.moveCenter( QtCore.QPoint(pos.x()-size.width(), pos.y()-size.height()) )
        # smaller than .9 == thicker gauge
        refill_rect.setSize(size*.9)
        refill_rect.moveCenter(pos)

        painter.setPen(QtCore.Qt.NoPen)

        painter.drawPixmap(rect, self._bg)

        painter.save()
        grad = QtGui.QConicalGradient(QtCore.QPointF(gauge_rect.center()), 270.0)
        grad.setColorAt(.75, QtCore.Qt.green)
        grad.setColorAt(.5, QtCore.Qt.yellow)
        grad.setColorAt(.25, QtCore.Qt.red)
        painter.setBrush(grad)
        painter.drawPie(gauge_rect, 225.0*16, self._value*16)
        painter.restore()

        painter.setBrush(QtGui.QBrush(self._bg.scaled(rect.size())))
        painter.drawEllipse(refill_rect)

        super(GaugeWidget,self).paintEvent(event)

Quarter value

Half value

Full Value

You can expand on this widget even more by exposing a way to set the colors and also maybe even changing the start and end ranges. They would be attributes that the paintEvent would reference, just like the value attribute it is using now.

You can also adjust the color stop values to change the balance of the ranges.

Make sure to have the paintEvent do as little processing as possible.



来源:https://stackoverflow.com/questions/12011147/how-to-create-a-3-color-gradient-dial-indicator-the-one-that-shows-green-yellow

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!