Pyside6 动画矩形问题

Pyside6 Animated Rectangle trouble

我正在尝试制作淡入淡出的环形矩形区域。我使用了 中的基本代码 刚决定扩大它。 它只是闪烁的矩形,但我需要平滑的淡入淡出效果。所以我决定制作一种方法来计算新的不透明度百分比并将其设置为画家。但是不能循环使用

这是我现在的class

class HighlightRect(QFrame):
board_width = 400  # width of frame
board_height = 400  #height of frame

def __init__(self, parent, x, y, width=50, height=50, blink_speed=1000):
    super().__init__(parent)
    self.blink_speed = blink_speed
    self.opacity_timer = self.blink_speed
    self.board_height = self.parent().height()
    self.board_width = self.parent().width()
    self.square_height = height
    self.square_width = width
    self.highlight_x = x
    self.highlight_y = y


    #self.setFocusPolicy(QtCore.Qt.StrongFocus)
    self.timer_draw = QtCore.QTimer(self)
    self.timer_draw.timeout.connect(self.draw)
    self.timer_draw.start(self.blink_speed)

    self.color = QtCore.Qt.red
    self.is_draw = False
    self.x_apple = 0
    self.y_apple = 0
    self.draw()

def blink(self, painter):
    self.color = QtCore.Qt.red
    while self.opacity_timer >= 0:
        self.opacity_timer -= 1 / 10  # просто подбор
        percents = round(int(self.opacity_timer / self.blink_speed * 100)/100, 1)
        print(percents)
        painter.setOpacity(percents)



def paintEvent(self, event):
    painter = QtGui.QPainter(self)

    print ("Paint Event?")
    if self.is_draw == True:
        print ("Draw")
        #self.color = QtCore.Qt.red
        self.blink_thread = threading.Thread(name='background', target=lambda: self.blink(painter))
        self.blink_thread.start()
    else:

        self.opacity_timer = self.blink_speed
        print ("Do not draw")
        self.color = QtCore.Qt.transparent
        threading.SystemExit = SystemExit
    painter.setPen(self.color)
    painter.drawRect(self.rect)

def draw(self):
    self.is_draw = not self.is_draw
    self.rect = QRect(self.highlight_x, self.highlight_y, self.square_width, self.square_height)
    self.update()

闪烁函数内部不透明度的变化,但在 while 循环外部也有效,但它是静态的。没有变化。在循环中更改不透明度是行不通的。 怎么了? 也许这里的某个地方是获得我想要的东西的另一种更正确的方法?

一个可能的解决方案是创建一个处理不透明度的 QProperty,然后使用 QPropertyAnimation 使更改变得平滑。

import random
import sys

from PySide6.QtCore import Property, Signal, QPropertyAnimation, QRect, Qt
from PySide6.QtGui import QPainter
from PySide6.QtWidgets import QFrame, QApplication


class Board(QFrame):
    rect_opacity_changed = Signal(name="rectOpacityChanged")

    def __init__(self, parent=None):
        super(Board, self).__init__(parent)

        self._rect_opacity = 1.0
        self._rect = QRect(0, 0, 50, 50)

        self._opacity_animation = QPropertyAnimation(
            targetObject=self, propertyName=b"rect_opacity", duration=3000
        )
        for p, v in ((0.0, 0.0), (0.3, 1.0), (0.7, 1.0), (1.0, 0.0)):
            self._opacity_animation.setKeyValueAt(p, v)

        self._opacity_animation.finished.connect(self.change)

        self.change()

    @Property(float, notify=rect_opacity_changed)
    def rect_opacity(self):
        return self._rect_opacity

    @rect_opacity.setter
    def rect_opacity(self, opacity):
        self._rect_opacity = opacity
        self.rect_opacity_changed.emit()
        self.update()

    def change(self):
        x = random.randint(0, self.width() - self._rect.width())
        y = random.randint(0, self.height() - self._rect.height())
        self._rect.moveTo(x, y)
        self._opacity_animation.start()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setOpacity(self.rect_opacity)
        painter.setPen(Qt.red)
        painter.drawRect(self._rect)


def main():

    app = QApplication([])
    board = Board()
    board.show()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()