在循环中调用repaint()时,pyqt5中的qpaiter不绘制任何内容。我怎么解决这个问题?

2024-05-13 08:50:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我对PyQt完全陌生。我想用PyQt5做动画,这是一个简单的测试,所以我只想把一个矩形从窗口的顶部移到底部。这里有一个要点,我正在做什么来实现这一点。在

    1。我把我想画的东西放在paintEvent()方法中。我用变量而不是常量值绘制了矩形
    2。我还创建了一个update()函数来更新所有变量
    3。我创建了一个循环函数自我更新()和自行重新喷漆()每100毫秒
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()函数中,因为在删除自循环()我可以看到一张蓝色盒子的静态图片,它的背景是白色的,在窗口的顶部。在


Tags: 函数importselfloopdefdiffqtwidth
1条回答
网友
1楼 · 发布于 2024-05-13 08:50:08

问题:

有一个连续的循环不允许GUI执行诸如绘制、与操作系统交互等任务。每个GUI都提供了一种以不阻塞窗口的方式制作动画的方法。在


Qt提供了各种类,允许您将动画实现为:

  • 第四次
  • Q时间线
  • QVariantimation公司
  • Q属性动画。在

另一方面,建议:

  • 如果qpaintevent将负责GUI绘制,请不要在paintEvent之外创建qpaiter。在
  • 使用update()方法(不是您的方法,而是提供Qt的方法)而不是重绘,以防重绘有时会强制窗口不必要地绘制,而update()将在必要时执行此操作,请记住,绘制是以屏幕的刷新率(60赫兹)完成的。例如,如果您在20毫秒内调用repaint 5次,则paintEvent()将被调用3次,但屏幕上的绘制是每16.6毫秒一次,因此您只需要1次绘制,如果考虑update()的话。在

考虑到上述情况,最好使用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_())

另一个选项是使用qvarianimation:

^{pr2}$

以下示例使用您的逻辑,但带有一个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_())

相关问题 更多 >