我正在尝试设置多段线的动画(它必须像波浪一样)。我试过这样做:
from PySide.QtCore import *
from PySide.QtGui import *
import sys, time
class Test(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
def poly(self, pts):
return QPolygonF(map(lambda p: QPointF(*p), pts))
def paintEvent(self, event):
painter = QPainter(self)
pts = [[80, 490], [180, 0], [280, 0], [430, 0], [580, 0], [680, 0], [780, 0]]
for i in pts:
while i[1] < 600:
painter.setPen(QPen(QColor(Qt.darkGreen), 3))
painter.drawPolyline(self.poly(pts))
painter.setBrush(QBrush(QColor(255, 0, 0)))
painter.setPen(QPen(QColor(Qt.black), 1))
for x, y in pts:
painter.drawEllipse(QRectF(x - 4, y - 4, 8, 8))
i[1] += 1
print pts
time.sleep(0.0025)
self.update()
if __name__ == '__main__':
example = QApplication(sys.argv)
test2 = Test()
test2.resize(800, 600)
test2.show()
sys.exit(example.exec_())
但是,它不起作用!程序运行时,屏幕上一片混乱。似乎self.update()
没有更新窗口。
求求你,救命。
显然,这段代码有一些问题。我会列出我注意到的所有事情,然后进行解释:
好吧。绘制事件是小部件想要重画的地方,应该尽可能快。在这种情况下,你不应该做任何递归的事情,或者花费太多的时间,因为这会减慢你的绘制速度。此外,在事件内部调用update()可能是递归的。paint事件的目标应该是响应小部件的当前状态paint和get out。
这是您的代码的一个修改版本。这不是最理想的方法,但我将在下面解释更多。。。
注意,这些点已经移动到成员属性
self.pts
,而paintEvent()
现在只绘制点的当前状态。然后,动画逻辑移动到另一个名为wave()
的方法。在这个方法中,它循环并修改每个点,并调用update()
来触发重绘。注意,我们正在paintEvent之外调用update()
。这一点很重要,因为如果应用程序中发生导致窗口重画(调整大小等)的任何其他事件,paintEvent可能会一直循环。所以我们修改了这个点列表sleep,并添加了一个重要的元素来调用QApplication.processEvents()。通常,当应用程序空闲时(离开当前调用)处理事件。因为您经常调用重新绘制,并将这些事件堆叠起来,所以需要告诉事件循环继续并刷新所有内容。试着注释掉这个
processEvents()
命令,看看会发生什么。在循环完成之前,你的应用程序只是旋转什么也不做,结果行将弹出。现在我建议这并不是最理想的方法,尽管它是一个例子。当前示例在执行wave时阻塞主线程。您应该始终避免阻塞主线程,因为它只是为了响应GUI事件。下面是一些可能的建议:
可以使用
0.0025
动画速度作为超时来创建QTimer。将timeout()信号连接到执行单个步骤并调用update的wave()
方法的版本。这里不再需要睡觉了。一旦您的wave计算结束,您将在wave()
中检查并在计时器上调用stop()。将上面示例中的整个
wave()
循环和初始数据集移动到QThread。这个QThread将emit a custom signal类似于waveUpdate(QPolygonF)
。当您启动这个线程时,它将执行循环,并处理QPolygonF的创建,在每个步骤上,它将发出信号并休眠。您可以将此信号连接到主窗口上的一个方法,该方法将接收新的多边形,将其分配给self._polygon
,然后调用update(),后者将只获取self.\u Polygon并绘制它。这里的想法是将尽可能多的繁重工作转移到线程中,并且只告诉主GUI线程使用新值重新绘制。相关问题 更多 >
编程相关推荐