簡體   English   中英

pyside/pyqt 如何簡單地制作弧形動畫?

[英]pyside/pyqt how to animate an arc simply?

我正在尋找一個解決方案,從 0 - 360° 為這個弧線制作動畫。 我是 Pyside/Pyqt 的新手,我找不到這么簡單的解決方案(只有初學者“unfriedly”)。 我也用 while 循環試過,但它不起作用。 目前我不明白這個 animation 系統,但我想繼續努力。

import sys

from PySide6 import QtCore
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import Qt
from PySide6.QtGui import QBrush, QPen, QPainter


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("AnimateArc")
        self.setGeometry(100, 100, 600, 600)

    def paintEvent(self, event):
        self.anim = QtCore.QPropertyAnimation(self, b"width", duration=1000) #<- is there a documentation for b"width", b"geometry"?
        self.anim.setStartValue(0)
        start = 0
        painter = QPainter(self)
        painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
        painter.drawArc(100, 100, 400, 400, 90 * 16, start * 16)    # I want to make the change dynamicly

        self.anim.setEndValue(360)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec()

感謝@musicamante關於使用QAnimationProperty動畫弧的解決方案

修改@musicmante代碼以創建加載效果猜測這將幫助開發人員並可能節省他們嘗試使用Qt制作加載效果的時間

來源

#!/usr/bin/env python3.10

import sys
import string
import random

from PySide6.QtWidgets import (QMainWindow, QPushButton, QVBoxLayout, 
        QApplication, QWidget)
from PySide6.QtCore import (Qt, QVariantAnimation)
from PySide6.QtGui import (QPen, QPainter, QColor)

class Arc:
    colors = list(string.ascii_lowercase[0:6]+string.digits)

    shades_of_blue = ["#7CB9E8","#00308F","#72A0C1", "#F0F8FF",
            "#007FFF", "#6CB4EE", "#002D62", "#5072A7", 
            "#002244", "#B2FFFF", "#6F00FF", "#7DF9FF","#007791",
            "#ADD8E6", "#E0FFFF", "#005f69", "#76ABDF",
            "#6A5ACD", "#008080", "#1da1f2", "#1a1f71", "#0C2340"]

    shades_of_green = ['#32CD32', '#CAE00D', '#9EFD38', '#568203', '#93C572',
            '#8DB600', '#708238', '#556B2F', '#014421', '#98FB98', '#7CFC00',
            '#4F7942', '#009E60', '#00FF7F', '#00FA9A', '#177245', '#2E8B57', 
            '#3CB371', '#A7F432', '#123524', '#5E8C31', '#90EE90', '#03C03C',
            '#66FF00', '#006600', '#D9E650']

    def __init__(self):
        self.diameter = random.randint(100, 600)

        #cols = list(Arc.colors)
        #random.shuffle(cols)
        #_col = "#"+''.join(cols[:6])
        #print(f"{_col=}")
        #self.color = QColor(_col)

        #self.color = QColor(Arc.shades_of_blue[random.randint(0, len(Arc.shades_of_blue)-1)])
        self.color = QColor(Arc.shades_of_green[random.randint(0, len(Arc.shades_of_green)-1)])
        #print(f"{self.color=}")
        self.span = random.randint(40, 150)
        self.direction = 1 if random.randint(10, 15)%2 == 0 else -1
        self.startAngle = random.randint(40, 200)
        self.step = random.randint(100, 300)

class ArcWidget(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.arcs = [Arc() for i in range(random.randint(10, 20))]
        self.startAnime()

    def initUI(self):
        #self.setAutoFillBackground(True)
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.setStyleSheet("background-color:black;")

    def startAnime(self):

        self.anim = QVariantAnimation(self, duration = 2000)
        self.anim.setStartValue(0)
        self.anim.setEndValue(360)
        self.anim.valueChanged.connect(self.update)
        self.anim.start()


    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        #painter.setPen(QPen(QColor("#b6faec"), 5, Qt.SolidLine))
        #painter.drawArc(
        #        100, 100, 400, 400, 90*16, 
        #        self.anim.currentValue() * 16)
        #width = 400
        #height = 400
        #painter.drawArc(self.width()/2 -width/2, self.height()/2 - height/2, 400, 400, self.anim.currentValue()*16, 45*16)
        for arc in self.arcs:
            painter.setPen(QPen(arc.color, 6, Qt.SolidLine))
            painter.drawArc(self.width()/2 - arc.diameter/2,
                    self.height()/2 - arc.diameter/2, arc.diameter, 
                    arc.diameter, self.anim.currentValue()*16*arc.direction+arc.startAngle*100, arc.span*16) 
            #print(f"currentValue : {self.anim.currentValue()}")
            #arc.startAngle = random.randint(50, 200)
        if self.anim.currentValue() == 360:
            #print("360")
            self.startAnime()

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Animate Arc")
        self.setGeometry(100, 100, 600, 600)
        self.arcWidget = ArcWidget()
        self.setCentralWidget(self.arcWidget)

if __name__ == "__main__":
    app = QApplication(sys.argv)

    mainWindow = MainWindow()
    mainWindow.show()

    app.exec()

output:

$ ./arc_widget.py 

載入.gif

QPropertyAnimation 用於為任何 QObject 的Qt 屬性設置動畫。 如果引用self (QMainWindow 的當前實例),則可以為 QMainWindow 的所有屬性和所有繼承的屬性設置動畫(QMainWindow 繼承自 QWidget,因此您也可以為所有QWidget 屬性設置動畫)。
在您的情況下,您正在嘗試為 window 的width屬性設置動畫,這當然不是您想要做的。

由於您要更改的值不是 window 的屬性,因此您不能使用 QPropertyAnimation(除非您使用@Property裝飾器創建 Qt 屬性),而應該使用 QVariantAnimation。

然后,每次要繪制小部件時,Qt 都會調用一個paintEvent(這可能會經常發生),因此您不能在那里創建 animation,否則您最終可能會遇到遞歸:因為 Z6F1C25ED1523962F1BBF9DEEpaint 需要 a55BZ9每次以前需要更新時,您都會創建一個新的 animation。

最后,考慮到通常不鼓勵在 QMainWindow 上繪畫,因為 Qt 主 window 是一種特殊的 QWidget,旨在用於高級功能(菜單、狀態欄等),並使用中央小部件來顯示實際內容。
正確的方法是創建和設置一個中央小部件,並在該小部件上實現繪畫。

這是您的代碼的修訂版和工作版:

class ArcWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.anim = QtCore.QVariantAnimation(self, duration=1000)
        self.anim.setStartValue(0)
        self.anim.setEndValue(360)
        self.anim.valueChanged.connect(self.update)
        self.anim.start()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
        painter.drawArc(
            100, 100, 400, 400, 90 * 16, self.anim.currentValue() * 16)


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("AnimateArc")
        self.setGeometry(100, 100, 600, 600)
        self.arcWidget = ArcWidget()
        self.setCentralWidget(self.arcWidget)

valueChanged連接確保每次值更改時,小部件都會安排更新(因此只要事件隊列允許就調用paintEvent ),然后您可以使用 animation 的當前值來繪制實際的弧線。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM