使用pyqt5渐进式绘画的正确方法
Correct way to paint progressively with pyqt5
我有一个基本上是圆形的小部件。我想逐步绘制它,所以我需要逐步绘制它(imo)。
通过下面的代码,我达到了我想要的效果。但是,有一个问题。我正在将 new event 传递给 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())
这一行产生了几个错误,但即使有这些错误,我也照我想的去做。
如果我将 qevent
从函数本身传递给这个新调用,图像不会像我之前所说的那样更新。
如果我创建这个新的 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。我的意思是渐进。这已经完成创建几个小部件,每个小部件后一秒。
你不应该直接调用 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_())
我有一个基本上是圆形的小部件。我想逐步绘制它,所以我需要逐步绘制它(imo)。
通过下面的代码,我达到了我想要的效果。但是,有一个问题。我正在将 new event 传递给 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())
这一行产生了几个错误,但即使有这些错误,我也照我想的去做。
如果我将
qevent
从函数本身传递给这个新调用,图像不会像我之前所说的那样更新。如果我创建这个新的
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。我的意思是渐进。这已经完成创建几个小部件,每个小部件后一秒。
你不应该直接调用 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_())