Sau*_*igh 6 python pyqt pyqt4 qpainter pyside
我正在尝试为折线设置动画(它必须像波浪一样).我试过这种方式:
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_())
Run Code Online (Sandbox Code Playgroud)
但是,它不起作用!程序运行时,屏幕上会出现乱七八糟的问题.看来,这self.update()
不会更新窗口.请帮忙.
显然,这段代码存在一些问题.我将列出我注意到的所有内容,然后通过解释:
好的.绘制事件是窗口小部件想要重绘的位置,并且应该尽可能快.你不应该在这个事件中做任何递归,或者花太多时间,因为它会减慢你的平局.此外,在事件内部调用update()可能是递归的.paint事件的目标应该是响应窗口小部件的当前状态,绘制和退出.
以下是您的代码的修改版本.它不是最理想的方法,但我会在下面解释更多...
from PySide.QtCore import *
from PySide.QtGui import *
import sys, time
class Test(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.pts = [[80, 490], [180, 0], [280, 0], [430, 0], [580, 0], [680, 0], [780, 0]]
def poly(self, pts):
return QPolygonF(map(lambda p: QPointF(*p), pts))
def paintEvent(self, event):
painter = QPainter(self)
pts = self.pts[:]
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))
# print pts
def wave(self):
for point in self.pts:
while point[1] < 600:
point[1] += 1
self.update()
QApplication.processEvents()
time.sleep(0.0025)
if __name__ == '__main__':
example = QApplication(sys.argv)
test2 = Test()
test2.resize(800, 600)
test2.show()
test2.raise_()
test2.wave()
sys.exit(example.exec_())
Run Code Online (Sandbox Code Playgroud)
请注意,该点已经移动到成员属性,self.pts
和paintEvent()
现在只画了点的当前状态.然后,动画逻辑被移动到另一个名为的方法wave()
.在此方法中,它循环并修改每个点并调用update()
以触发重绘.注意我们update()
在paintEvent之外调用.这很重要,因为如果应用程序中发生任何其他事件导致窗口重绘(调整大小等),那么paintEvent可能会永远循环.
所以我们修改了这个点列表,sleep,以及一个重要的添加它来调用QApplication.processEvents().通常,在应用程序变为空闲时处理事件(离开当前调用).因为你不断地调用重绘,并将这些事件堆叠起来,所以你需要告诉事件循环继续并将所有内容刷新.尝试评论该processEvents()
命令,看看会发生什么.在循环完成之前,您的应用程序只会旋转无效,并且生成的行将弹出到位.
现在,对于我建议的部分,这并不是最理想的方法,尽管它可以作为一个例子.此当前示例在执行wave时阻止主线程.你应该总是避免阻塞主线程,因为它纯粹是为了响应GUI事件.所以这里有一些可能的建议:
您可以使用动画速度创建QTimer0.0025
作为超时.将timeout()信号连接到wave()
执行单个步骤并调用update 的方法版本.这里不再需要睡觉了.一旦你的波浪计算结束,你将检查它wave()
并在计时器上调用stop().
将wave()
上面示例中的整个循环和初始数据集移动到QThread中.这QThread的将发出一个自定义信号一样waveUpdate(QPolygonF)
.当你启动这个线程时,它将执行循环,并处理创建QPolygonF,并在每一步它将发出信号和睡眠.您可以将此信号连接到主窗口上的方法,该方法将接收新的Polygon,将其分配给self._polygon
,并调用update(),然后只需抓取self._polygon并绘制它.这里的想法是尽可能多地将繁重的工作移动到线程中,并且只告诉主GUI线程重新绘制新值.
归档时间: |
|
查看次数: |
6097 次 |
最近记录: |