我对PyQt完全陌生。我想使用PyQt5做动画,这是我正在做的简单测试,所以我只是试图将矩形从窗口的顶部移到底部。这是我要实现这一目标的要旨。
import sys
import random
from PyQt5.QtWidgets import ( QApplication, QWidget, QToolTip, QMainWindow)
from PyQt5.QtGui import QPainter, QBrush, QPen, QColor, QFont
from PyQt5.QtCore import Qt, QDateTime
class rain_animation(QMainWindow):
def __init__(self):
super().__init__()
self.painter = QPainter()
""" Variables for the Window """
self.x = 50
self.y = 50
self.width = 500
self.height = 500
"""Variables for the rain"""
self.rain_x = self.width/2
self.rain_y = 0
self.rain_width = 5
self.rain_height = 30
self.rain_vel_x = 0
self.rain_vel_y = 5
self.start()
self.loop()
def paintEvent(self, a0):
self.painter.begin(self)
# Draw a White Background
self.painter.setPen(QPen(Qt.white, 5, Qt.SolidLine))
self.painter.setBrush(QBrush(Qt.white, Qt.SolidPattern))
self.painter.drawRect(0, 0, self.width, self.height)
#Draw the rain
self.painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine))
self.painter.setBrush(QBrush(Qt.blue, Qt.SolidPattern))
self.painter.drawRect(self.rain_x, self.rain_y, self.rain_width, self.rain_height)
self.painter.end(self)
def update(self, diff):
self.rain_x += self.rain_vel_x
self.rain_y += self.rain_vel_y
def start(self):
self.setWindowTitle("Rain Animation")
self.setGeometry(self.x, self.y, self.width, self.height)
self.show()
def loop(self):
start = QDateTime.currentDateTime()
while True :
diff = start.msecsTo(QDateTime.currentDateTime())
if diff >= 100 :
print("time : {0} ms rain_x : {1} rain_y : {2}".format(diff, self.rain_x, self.rain_y))
start = QDateTime.currentDateTime()
self.update(diff)
self.repaint()
if __name__ == "__main__":
app = QApplication(sys.argv)
animation = rain_animation()
sys.exit(app.exec_())
我应该看到的是一个从窗口顶部移动到屏幕底部的矩形,但是我所看到的只是一个黑色背景的窗口。
loop()函数似乎正常工作,因为我正在打印的数据表明变量每100毫秒进行更新。
尽管问题似乎出在loop()函数中,因为删除self.loop()后,我可以在窗口顶部看到带有白色背景的蓝色框的静态图片。
答案 0 :(得分:1)
具有连续循环不允许GUI执行绘画,与OS交互等任务。每个GUI提供一种制作动画的方式,且不会阻塞窗口。
Qt提供了各种类,可让您将动画实现为:
另一方面,建议:
考虑到上述情况,最好使用QPropertyAnimation:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class RainAnimation(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Rain Animation")
self.setGeometry(50, 50, 500, 500)
self.m_rect_rain = QtCore.QRect()
animation = QtCore.QPropertyAnimation(
self,
b"rect_rain",
parent=self,
startValue=QtCore.QRect(self.width() / 2, 0, 5, 30),
endValue=QtCore.QRect(self.width() / 2, self.height() - 30, 5, 30),
duration=5 * 1000,
)
animation.start()
def paintEvent(self, a0):
painter = QtGui.QPainter(self)
# Draw a White Background
painter.setPen(QtGui.QPen(QtCore.Qt.white, 5, QtCore.Qt.SolidLine))
painter.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
painter.drawRect(self.rect())
#Draw the rain
painter.setPen(QtGui.QPen(QtCore.Qt.blue, 1, QtCore.Qt.SolidLine))
painter.setBrush(QtGui.QBrush(QtCore.Qt.blue, QtCore.Qt.SolidPattern))
painter.drawRect(self.rect_rain)
@QtCore.pyqtProperty(QtCore.QRect)
def rect_rain(self):
return self.m_rect_rain
@rect_rain.setter
def rect_rain(self, r):
self.m_rect_rain = r
self.update()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = RainAnimation()
w.show()
sys.exit(app.exec_())
另一个选择是使用QVarianAnimation:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class RainAnimation(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Rain Animation")
self.setGeometry(50, 50, 500, 500)
self.m_rect_rain = QtCore.QRect()
animation = QtCore.QVariantAnimation(
parent=self,
startValue=QtCore.QRect(self.width() / 2, 0, 5, 30),
endValue=QtCore.QRect(self.width() / 2, self.height() - 30, 5, 30),
duration=5 * 1000,
valueChanged=self.set_rect_rain,
)
animation.start()
def paintEvent(self, a0):
painter = QtGui.QPainter(self)
# Draw a White Background
painter.setPen(QtGui.QPen(QtCore.Qt.white, 5, QtCore.Qt.SolidLine))
painter.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
painter.drawRect(self.rect())
# Draw the rain
painter.setPen(QtGui.QPen(QtCore.Qt.blue, 1, QtCore.Qt.SolidLine))
painter.setBrush(QtGui.QBrush(QtCore.Qt.blue, QtCore.Qt.SolidPattern))
painter.drawRect(self.m_rect_rain)
@QtCore.pyqtSlot(QtCore.QVariant)
def set_rect_rain(self, r):
self.m_rect_rain = r
self.update()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = RainAnimation()
w.show()
sys.exit(app.exec_())
以下示例使用您的逻辑,但使用了QTimer:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class RainAnimation(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Rain Animation")
self.setGeometry(50, 50, 500, 500)
self.m_rect_rain = QtCore.QRect(self.width() / 2, 0, 5, 30)
timer = QtCore.QTimer(self, timeout=self.update_rain, interval=100)
timer.start()
def paintEvent(self, a0):
painter = QtGui.QPainter(self)
# Draw a White Background
painter.setPen(QtGui.QPen(QtCore.Qt.white, 5, QtCore.Qt.SolidLine))
painter.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
painter.drawRect(self.rect())
# Draw the rain
painter.setPen(QtGui.QPen(QtCore.Qt.blue, 1, QtCore.Qt.SolidLine))
painter.setBrush(QtGui.QBrush(QtCore.Qt.blue, QtCore.Qt.SolidPattern))
painter.drawRect(self.m_rect_rain)
@QtCore.pyqtSlot()
def update_rain(self):
self.m_rect_rain.moveTop(self.m_rect_rain.top() + 5)
self.update()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = RainAnimation()
w.show()
sys.exit(app.exec_())