【问题标题】:animate a QGraphicsPixmapItem动画 QGraphicsPixmapItem
【发布时间】:2019-12-10 04:21:31
【问题描述】:

我正在尝试在 PyQt5 中为 QGraphicsPixmapItem 设置动画。 程序按原样崩溃,没有任何错误消息,删除有关变量“anime”的行使程序正常工作。

这里是 QGraphicsPixMapItem:

class QStone(QGraphicsPixmapItem,QGraphicsObject):
    def __init__(self, color, movable):
        QGraphicsPixmapItem.__init__(self)
        QGraphicsObject.__init__(self)

        if movable:
            self.setFlag(QGraphicsItem.ItemIsMovable)

        white = QPixmap("ressources/white2.png")
        black = QPixmap("ressources/black_stone.png")
        empty = QPixmap("ressources/no_stone.jpg")


        if color == Player.white:
            self.setPixmap(white.scaled(60, 60, Qt.KeepAspectRatio))

        elif color == Player.black:
            self.setPixmap(black.scaled(60, 60, Qt.KeepAspectRatio))

        self.w = self.boundingRect().width()
        self.h = self.boundingRect().height()

    def hoverEnterEvent(self, event):
        self.setCursor(Qt.OpenHandCursor)
        self.setOpacity(0.5)
        event.accept()

    def hoverLeaveEvent(self, event):
        self.setCursor(Qt.ArrowCursor)
        self.setOpacity(1.)
        event.accept()

使用 QPropertyAnimation 似乎需要 QGraphicsObject 继承。

这里是包含这个动画的代码:(这个方法属于一个QGraphicsView的子类):

def display_stone(self, x, y, color=None):
    stone = ""
    # if color is None:
    #     stone = QStone("", True)
    if color == Player.white:
        stone = QStone(Player.white, False)
    elif color == Player.black:
        stone = QStone(Player.black, False)

    stone.setOpacity(0.0)
    anime = QPropertyAnimation(stone, b"opacity",self)
    anime.setDuration(800)
    anime.setStartValue(0.0)
    anime.setEndValue(1.0)
    anime.start()

    stone.setPos(x - stone.w / 2, y - stone.h / 2)
    self.scene.addItem(stone)
    stone.setZValue(10)

有什么想法吗? 谢谢

【问题讨论】:

    标签: python pyqt pyqt5 qgraphicsitem


    【解决方案1】:

    与 Qt C++ API 不同,PyQt 不允许双重继承(例外情况除外(1)),因此您无法实现从 QGraphicsPixmapItem 和 QGraphicsObject 继承的类。

    在这种情况下,有以下选项:

    1.在这种情况下是创建一个处理您要修改的属性的QObject,也就是由QPropertyAnimation处理的对象:

    class OpacityManager(QObject):
        opacityChanged = pyqtSignal(float)
    
        def __init__(self, initial_opacity, parent=None):
            super(OpacityManager, self).__init__(parent)
            self._opacity = initial_opacity
    
        @pyqtProperty(float, notify=opacityChanged)
        def opacity(self):
            return self._opacity
    
        @opacity.setter
        def opacity(self, v):
            if self._opacity != v:
                self._opacity = v
                self.opacityChanged.emit(self._opacity)
    
    
    class QStone(QGraphicsPixmapItem):
        def __init__(self, color, movable=False):
            QGraphicsPixmapItem.__init__(self)
    
            self.manager = OpacityManager(self.opacity())
            self.manager.opacityChanged.connect(self.setOpacity)
    
            if movable:
                self.setFlag(QGraphicsItem.ItemIsMovable)
            # ...
    
    # ...
    anime = QPropertyAnimation(stone.manager, b"opacity", stone.manager)
    # ...
    

    2.另一个选项是QVariantAnimation:

    # ...
    anime = QVariantAnimation(self)
    anime.valueChanged.connect(stone.setOpacity)
    anime.setDuration(800)
    # ...
    

    (1)https://www.riverbankcomputing.com/static/Docs/PyQt5/qt_interfaces.html

    【讨论】:

    • 它有效,谢谢。但是我仍然遇到问题,因为程序继续考虑下一步时会显示棋子,并且会冻结棋子的显示。我会尝试在单独的线程中为它们制作动画。
    • @lolveley 不,不,不......您不能修改用于绘画的属性,例如来自另一个线程的不透明度,因为 Qt 禁止它,因为它不能保证其正确操作,并且在这种情况根本没有帮助。
    • @lolveley 不要滥用线程,它们不是解决任何问题的神奇实体,因为它们有限制,如果你不正确地实现它们,它们可能会与你期望的相反。恕我直言是最后一个选项,我只在任务阻塞事件循环时使用它们,但在你的情况下它不是。我认为您还有其他问题。
    • @lolveley 不要编辑你的问题,用你的新问题创建一个新帖子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 2014-03-06
    相关资源
    最近更新 更多