问题
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:
- Draw the static pixmap of the gauge background
- Draw a pie shape with a gradient
- 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)
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