QPainter如何使用QPropertyAnimation绘制圆弧
How to use QPropertyAnimation with QPainter to draw an arc
我正在编写一个执行系统监视器功能的桌面小部件。使用 QPainter
我画了一个圆弧,表示 cpu 使用级别的图形表示。每秒都会有一个 paintevent 以基于 cpu_percent()
函数值的跨度角重新绘制此弧。
结果是新级别表示和先前级别表示之间的突然过渡。我想使用 QPropertyAnimation
来创建平滑的缓动弧动画。不幸的是我不知道我应该使用的属性。如果你告诉我如何以正确的方式做到这一点,我会很高兴。
这是我使用的小部件 class:
from PySide2 import QtWidgets, QtCore, QtGui
from psutil import cpu_percent
class cpu_diagram(QtWidgets.QWidget):
def __init__(self, parent=None):
super(cpu_diagram, self).__init__()
self.resize(600, 600) # todo
# color constants
self.dark = "#3B3A44"
self.light = "#4A4953"
self.color = "#75ECB5"
# text constants
self.module_name = "CPU"
self.postfix = "average"
# timer with an interval of 1 sec
self.timer = QtCore.QTimer()
self.timer.setInterval(1000)
self.timer.timeout.connect(self.update)
self.timer.start()
def paintEvent(self, event:QtGui.QPaintEvent):
# get cpu usage
self.percent = cpu_percent()
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
# draw base
basic_rect = self.rect().adjusted(20, 20, -20, -20)
painter.setBrush(QtGui.QBrush(QtGui.QColor(self.dark)))
painter.drawEllipse(basic_rect)
# draw arc
pen = QtGui.QPen(QtGui.QColor(self.light))
pen.setWidth(40)
painter.setPen(pen)
arc_rect = basic_rect.adjusted(40, 40, -40, -40)
painter.drawEllipse(arc_rect)
# draw active arc
pen.setColor(QtGui.QColor(self.color))
start_angle = 90
span_angle = self.percent_to_angle(self.percent)
painter.setPen(pen)
painter.drawArc(arc_rect, start_angle * 16, span_angle * 16)
# draw text
# draw module name
painter.setPen(QtGui.QPen(QtGui.QColor(QtCore.Qt.white)))
font = QtGui.QFont()
font.setPixelSize(110)
painter.setFont(font)
arc_rect.moveTop(-25)
painter.drawText(arc_rect, QtCore.Qt.AlignCenter, self.module_name)
# draw postfix
font = QtGui.QFont()
font.setPixelSize(60)
painter.setFont(font)
arc_rect.moveTop(-125)
painter.drawText(arc_rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom, self.postfix)
# draw percents
arc_rect.moveBottom(460)
painter.setPen(QtGui.QPen(self.color))
painter.drawText(arc_rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom, f"{str(self.percent)} %")
def percent_to_angle(self, percent):
return -percent / 100 * 360
您必须创建一个代表百分比的 QProperty 并在 QPropertyAnimation 中使用它。
from PySide2 import QtWidgets, QtCore, QtGui
from psutil import cpu_percent
class CpuDiagram(QtWidgets.QWidget):
percentChanged = QtCore.Signal(float)
def __init__(self, parent=None):
super().__init__(parent)
self.resize(600, 600) # todo
# color constants
self.dark = "#3B3A44"
self.light = "#4A4953"
self.color = "#75ECB5"
# text constants
self.module_name = "CPU"
self.postfix = "average"
# timer with an interval of 1 sec
self.timer = QtCore.QTimer()
self.timer.setInterval(1000)
self.timer.timeout.connect(self.onTimeout)
self.timer.start()
self._percent = 0
self._animation = QtCore.QPropertyAnimation(self, b"percent", duration=400)
self.percentChanged.connect(self.update)
@QtCore.Slot()
def onTimeout(self):
start_value = self.percent
end_value = cpu_percent()
self._animation.setStartValue(start_value)
self._animation.setEndValue(end_value)
self._animation.start()
def get_percent(self):
return self._percent
def set_percent(self, p):
if self._percent != p:
self._percent = p
self.percentChanged.emit(p)
percent = QtCore.Property(
float, fget=get_percent, fset=set_percent, notify=percentChanged
)
def paintEvent(self, event: QtGui.QPaintEvent):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
# draw base
basic_rect = self.rect().adjusted(20, 20, -20, -20)
painter.setBrush(QtGui.QBrush(QtGui.QColor(self.dark)))
painter.drawEllipse(basic_rect)
# draw arc
pen = QtGui.QPen(QtGui.QColor(self.light))
pen.setWidth(40)
painter.setPen(pen)
arc_rect = basic_rect.adjusted(40, 40, -40, -40)
painter.drawEllipse(arc_rect)
# draw active arc
pen.setColor(QtGui.QColor(self.color))
start_angle = 90
span_angle = self.percent_to_angle(self.percent)
painter.setPen(pen)
painter.drawArc(arc_rect, start_angle * 16, span_angle * 16)
# draw text
# draw module name
painter.setPen(QtGui.QPen(QtGui.QColor(QtCore.Qt.white)))
font = QtGui.QFont()
font.setPixelSize(110)
painter.setFont(font)
arc_rect.moveTop(-25)
painter.drawText(arc_rect, QtCore.Qt.AlignCenter, self.module_name)
# draw postfix
font = QtGui.QFont()
font.setPixelSize(60)
painter.setFont(font)
arc_rect.moveTop(-125)
painter.drawText(
arc_rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom, self.postfix
)
# draw percents
arc_rect.moveBottom(460)
painter.setPen(QtGui.QPen(self.color))
painter.drawText(
arc_rect,
QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom,
f"{self.percent:.2f} %",
)
def percent_to_angle(self, percent):
return -percent / 100 * 360
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = CpuDiagram()
w.show()
sys.exit(app.exec_())
我正在编写一个执行系统监视器功能的桌面小部件。使用 QPainter
我画了一个圆弧,表示 cpu 使用级别的图形表示。每秒都会有一个 paintevent 以基于 cpu_percent()
函数值的跨度角重新绘制此弧。
结果是新级别表示和先前级别表示之间的突然过渡。我想使用 QPropertyAnimation
来创建平滑的缓动弧动画。不幸的是我不知道我应该使用的属性。如果你告诉我如何以正确的方式做到这一点,我会很高兴。
这是我使用的小部件 class:
from PySide2 import QtWidgets, QtCore, QtGui
from psutil import cpu_percent
class cpu_diagram(QtWidgets.QWidget):
def __init__(self, parent=None):
super(cpu_diagram, self).__init__()
self.resize(600, 600) # todo
# color constants
self.dark = "#3B3A44"
self.light = "#4A4953"
self.color = "#75ECB5"
# text constants
self.module_name = "CPU"
self.postfix = "average"
# timer with an interval of 1 sec
self.timer = QtCore.QTimer()
self.timer.setInterval(1000)
self.timer.timeout.connect(self.update)
self.timer.start()
def paintEvent(self, event:QtGui.QPaintEvent):
# get cpu usage
self.percent = cpu_percent()
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
# draw base
basic_rect = self.rect().adjusted(20, 20, -20, -20)
painter.setBrush(QtGui.QBrush(QtGui.QColor(self.dark)))
painter.drawEllipse(basic_rect)
# draw arc
pen = QtGui.QPen(QtGui.QColor(self.light))
pen.setWidth(40)
painter.setPen(pen)
arc_rect = basic_rect.adjusted(40, 40, -40, -40)
painter.drawEllipse(arc_rect)
# draw active arc
pen.setColor(QtGui.QColor(self.color))
start_angle = 90
span_angle = self.percent_to_angle(self.percent)
painter.setPen(pen)
painter.drawArc(arc_rect, start_angle * 16, span_angle * 16)
# draw text
# draw module name
painter.setPen(QtGui.QPen(QtGui.QColor(QtCore.Qt.white)))
font = QtGui.QFont()
font.setPixelSize(110)
painter.setFont(font)
arc_rect.moveTop(-25)
painter.drawText(arc_rect, QtCore.Qt.AlignCenter, self.module_name)
# draw postfix
font = QtGui.QFont()
font.setPixelSize(60)
painter.setFont(font)
arc_rect.moveTop(-125)
painter.drawText(arc_rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom, self.postfix)
# draw percents
arc_rect.moveBottom(460)
painter.setPen(QtGui.QPen(self.color))
painter.drawText(arc_rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom, f"{str(self.percent)} %")
def percent_to_angle(self, percent):
return -percent / 100 * 360
您必须创建一个代表百分比的 QProperty 并在 QPropertyAnimation 中使用它。
from PySide2 import QtWidgets, QtCore, QtGui
from psutil import cpu_percent
class CpuDiagram(QtWidgets.QWidget):
percentChanged = QtCore.Signal(float)
def __init__(self, parent=None):
super().__init__(parent)
self.resize(600, 600) # todo
# color constants
self.dark = "#3B3A44"
self.light = "#4A4953"
self.color = "#75ECB5"
# text constants
self.module_name = "CPU"
self.postfix = "average"
# timer with an interval of 1 sec
self.timer = QtCore.QTimer()
self.timer.setInterval(1000)
self.timer.timeout.connect(self.onTimeout)
self.timer.start()
self._percent = 0
self._animation = QtCore.QPropertyAnimation(self, b"percent", duration=400)
self.percentChanged.connect(self.update)
@QtCore.Slot()
def onTimeout(self):
start_value = self.percent
end_value = cpu_percent()
self._animation.setStartValue(start_value)
self._animation.setEndValue(end_value)
self._animation.start()
def get_percent(self):
return self._percent
def set_percent(self, p):
if self._percent != p:
self._percent = p
self.percentChanged.emit(p)
percent = QtCore.Property(
float, fget=get_percent, fset=set_percent, notify=percentChanged
)
def paintEvent(self, event: QtGui.QPaintEvent):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
# draw base
basic_rect = self.rect().adjusted(20, 20, -20, -20)
painter.setBrush(QtGui.QBrush(QtGui.QColor(self.dark)))
painter.drawEllipse(basic_rect)
# draw arc
pen = QtGui.QPen(QtGui.QColor(self.light))
pen.setWidth(40)
painter.setPen(pen)
arc_rect = basic_rect.adjusted(40, 40, -40, -40)
painter.drawEllipse(arc_rect)
# draw active arc
pen.setColor(QtGui.QColor(self.color))
start_angle = 90
span_angle = self.percent_to_angle(self.percent)
painter.setPen(pen)
painter.drawArc(arc_rect, start_angle * 16, span_angle * 16)
# draw text
# draw module name
painter.setPen(QtGui.QPen(QtGui.QColor(QtCore.Qt.white)))
font = QtGui.QFont()
font.setPixelSize(110)
painter.setFont(font)
arc_rect.moveTop(-25)
painter.drawText(arc_rect, QtCore.Qt.AlignCenter, self.module_name)
# draw postfix
font = QtGui.QFont()
font.setPixelSize(60)
painter.setFont(font)
arc_rect.moveTop(-125)
painter.drawText(
arc_rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom, self.postfix
)
# draw percents
arc_rect.moveBottom(460)
painter.setPen(QtGui.QPen(self.color))
painter.drawText(
arc_rect,
QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom,
f"{self.percent:.2f} %",
)
def percent_to_angle(self, percent):
return -percent / 100 * 360
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = CpuDiagram()
w.show()
sys.exit(app.exec_())