语境
我有一个自定义小部件,它应该制作点移动的动画,以制作一种加载小部件。为了实现这个目标,我开始使用 QPainter 和 QVariantAnimation 对象,这似乎是完成这项工作的不错工具。问题是我认为我在绘图时初始化的 QPainter 相互冲突。
技术
为了实现这一点,我初始化了多个 QVariantAnimation,它表示 .valueChanged() 我连接到一个函数 update(),它应该启动 painEvent(),例如文档中所写
绘制事件是重新绘制全部或部分小部件的请求。它可能由于以下原因之一发生:调用了 repaint() 或 update(),小部件被遮挡并且现在已被发现,或许多其他原因。
由于我在不同的时间启动不同的动画,我认为 update() 被调用了很多次,从而干扰了另一个已经在工作的 QPainter。但是,正如我在文档中所读到的,
当 update() 被多次调用或窗口系统发送多个绘制事件时,Qt 将这些事件合并为一个具有更大区域的事件。
但它没有指定 QPainter 具有相同的区域,这就是我认为它崩溃的原因。它记录以下消息:
QBackingStore::endPaint() called with active painter on backingstore paint device
最小的工作示例
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QDialog, QPushButton
from PyQt5.QtCore import Qt, pyqtSlot, QVariantAnimation, QVariant, QTimer
from PyQt5.QtGui import QColor, QPainter, QBrush
import time
class Dialog(QDialog):
def __init__(self, *args, **kwargs):
QDialog.__init__(self, *args, **kwargs)
self.resize(500, 500)
self.setLayout(QVBoxLayout())
self.button = QPushButton()
self.layout().addWidget(self.button)
self.paintWidget = PaintWidget()
self.layout().addWidget(self.paintWidget)
self.button.clicked.connect(self.paintWidget.startPainting)
self.button.clicked.connect(self.reverse)
def reverse(self):
if self.paintWidget.isMoving:
self.paintWidget.stopPainting()
class PaintWidget(QWidget):
def __init__(self):
super(PaintWidget, self).__init__()
self.dotRadius = 10
self.dotColor = QColor(255, 100, 100)
self.numberOfDots = 3
self.isMoving = False
self.animation = []
self.createAnimation()
self.dotPosition = [[0, 0], [0, 0], [0, 0]]
def startPainting(self):
for i in range(self.numberOfDots):
self.animation[i].start()
time.sleep(200)
self.isActive = True
def createAnimation(self):
for i in range(self.numberOfDots):
self.animation.append(QVariantAnimation(self, startValue=0, endValue=500, duration=3000))
self.animation[i].valueChanged.connect(self.updatePosition)
@pyqtSlot(QVariant)
def updatePosition(self, position):
self.dotPosition = [position, 0]
self.update()
def paintEvent(self, event):
painter = QPainter(self)
painter.fillRect(self.rect(), Qt.transparent)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setPen(Qt.NoPen)
for i in range(self.numberOfDots):
painter.save()
painter.translate(0, 0)
position = (self.dotPosition[i][0], self.dotPosition[i][1])
color = self.dotColor
painter.setBrush(QBrush(color, Qt.SolidPattern))
painter.drawEllipse(position[0], position[1], self.dotRadius, self.dotRadius)
painter.restore()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
dial = Dialog()
dial.show()
sys.exit(app.exec_())
结果
我知道现在这段代码不起作用,因为我无法检索更新了哪个点的动画,但我相信这里的主要问题是画家之间的干扰。因此,谁能告诉我为什么会发生这种情况并指出一个潜在的解决方案?另外,为了知道更新的点并选择了好的位置,我真的不确定如何做到这一点。