python - 使用pyqt5渐进绘画的正确方法

标签 python pyqt pyqt5 qpainter paintevent

我有一个基本上是一个圆圈的小部件。我想逐步绘制它,所以我需要逐步绘制它(imo)。

通过下面的代码,我已经实现了我想要的。然而,有一个问题。我正在将 new 事件 传递给 paintEvent 函数,因为如果我不这样做,图像在一切完成之前都不会更新,所以我什么也得不到通缉。

小部件代码

import sys
import time
from PyQt5.QtCore import Qt, QRect
from PyQt5.QtWidgets import QApplication, QWidget, QCheckBox, QDesktopWidget

from PyQt5.QtGui import QPen, QPainter, QPaintEvent, QConicalGradient, QColor, QBrush

class Circle(QWidget):

    def __init__(self, size, color):
        super().__init__()

        self.loadingAngle = 0
        self.width = 0
        self.color = color
        self.pixmap_opacity = 1

        self.resize(size, size);
        self.center()

        self.initUI()

    def initUI(self):

        self.width = 15
        self.loadingAngle = 0
        self.show()

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def paintEvent(self, qevent):

        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setStyleSheet("background:transparent;")

        drawingRect = QRect()
        drawingRect.setX(qevent.rect().x() + self.width)
        drawingRect.setY(qevent.rect().y() + self.width)
        drawingRect.setWidth(qevent.rect().width() - self.width * 2)
        drawingRect.setHeight(qevent.rect().height() - self.width * 2)

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        gradient = QConicalGradient()
        gradient.setCenter(drawingRect.center())
        gradient.setAngle(90)
        gradient.setColorAt(1, QColor(0,0,0))
        gradient.setColorAt(0, QColor(self.color[0], self.color[1],self.color[2]))

        arcLengthApproximation = self.width + self.width / 3
        pen = QPen(QBrush(gradient), self.width)
        pen.setCapStyle(Qt.RoundCap)
        painter.setPen(pen)
        painter.drawArc(drawingRect, 90 * 16 - arcLengthApproximation, -self.loadingAngle * 16)
        #time.sleep(0.25)

        if self.loadingAngle < 360:
            self.loadingAngle += 1
            #self.paintEvent(QDrawEvent())
            self.paintEvent(QPaintEvent())

有问题的行

self.paintEvent(QPaintEvent())

这一行产生了几个错误,但即使有这些错误,我也做了我想做的事。

  1. 如果我将 qevent 从函数本身传递给这个新调用,图像不会像我之前所说的那样更新。

  2. 如果我创建这个新的QPaintEvent,它确实可以工作。但是,错误是:

Traceback (most recent call last):

File "/home/btc/Escritorio/SinestesiaRCB/Clases/Widget.py", line 68, in paintEvent self.paintEvent(QPaintEvent())

TypeError: arguments did not match any overloaded call: QPaintEvent(QRegion): not enough arguments

QPaintEvent(QRect): not enough arguments

QPaintEvent(QPaintEvent): not enough arguments

QBackingStore::endPaint() called with active painter on backingstore paint device

这些错误可能来自其他行,例如:

qevent.rect().x()

由于新事件是空的。

所以基本上我的问题是,我应该如何正确地做到这一点,这意味着实现我想要的而没有错误

PS。我所说的渐进是什么意思。这已经创建了几个小部件,每个小部件在前一秒后创建。

enter image description here

最佳答案

你不应该直接调用paintEvent,你必须使用update()来间接调用它。另一方面,如果您希望经常被调用,则在这种情况下应该使用 QTimer 或更好的 QTimeLine。

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Circle(QtWidgets.QWidget):
    def __init__(self, size, color):
        super().__init__()
        self._loading_angle = 0
        self.width = 0
        self.color = color
        self.pixmap_opacity = 1
        self.resize(size, size)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setStyleSheet("background:transparent;")
        self.center()
        self.initUI()

        timeline = QtCore.QTimeLine(4000, self)
        timeline.setFrameRange(0, 360)
        timeline.frameChanged.connect(self.setLoadingAngle)
        timeline.start()

    def initUI(self):
        self.width = 15
        self.setLoadingAngle(0)
        self.show()

    def loadingAngle(self):
        return self._loading_angle

    def setLoadingAngle(self, angle):
        self._loading_angle = angle
        self.update()

    loadingAngle = QtCore.pyqtProperty(int, fget=loadingAngle, fset=setLoadingAngle)

    def center(self):
        qr = self.frameGeometry()
        cp = QtWidgets.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        drawingRect  = QtCore.QRect(QtCore.QPoint(), self.rect().size() - 2*self.width*QtCore.QSize(1, 1))
        drawingRect.moveCenter(self.rect().center())

        gradient = QtGui.QConicalGradient()
        gradient.setCenter(drawingRect.center())
        gradient.setAngle(90)
        gradient.setColorAt(1, QtGui.QColor(0,0,0))
        gradient.setColorAt(0, self.color)
        arcLengthApproximation = self.width + self.width / 3
        pen = QtGui.QPen(QtGui.QBrush(gradient), self.width)
        pen.setCapStyle(QtCore.Qt.RoundCap)
        painter.setPen(pen)
        painter.drawArc(drawingRect, 90 * 16 - arcLengthApproximation, -self._loading_angle * 16)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Circle(400, QtGui.QColor("blue"))
    w.show()
    sys.exit(app.exec_())

关于python - 使用pyqt5渐进绘画的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53747154/

相关文章:

python - 如何使用 matplotlib 在线图上叠加散点图?

python - Pyqt获取鼠标点击图片时的像素位置和值

python - 在 QTableView 中使用 QSortFilterProxyModel 对两行进行排序

python - 当一个小部件的可见性改变时,如何防止 pyqt5 应用程序中的窗口和小部件改变大小

python - TypeError:setText(self,str):参数1具有意外类型 'tuple'

qt - 在 TableView 中保持相同的选择颜色,无论它是否处于事件状态

python - 使用串行端口和 MySQL 从 arduino 在 Rpi 上收集数据

python - pika 使用哪种连接形式

python - 如何找到 AWS IAM 用户使用 boto3 处于非事件/空闲状态的天数?

python - PyQt 对话框 - 如何让它在按下按钮后退出?