向QPushbutton enterEvent和ExiteEvent添加动画

2024-09-29 21:28:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试向QPushbutton添加自定义动画,而不创建自定义QPushbutton并重写其enterEvent()和leaveEvent()

到目前为止我已经试过了

@staticmethod
def addButtonHoverAnimation(button:QPushButton,currentPos:QPoint):
    '''
    Method to:
    => Add hover animation for provided button
    '''
    enterShift = QPropertyAnimation(button,b'pos',button)
    exitShift = QPropertyAnimation(button,b'pos',button)

    def enterEvent(e):
        pos=button.pos()            
        enterShift.setStartValue(pos)
        enterShift.setEndValue(QPoint(pos.x()+3,pos.y()+3))
        enterShift.setDuration(100)
        enterShift.start()
        Effects.dropShadow(button,1,2)
        

    def leaveEvent(e):
        pos=button.pos()            
        exitShift.setStartValue(pos)
        exitShift.setEndValue(QPoint(pos.x()-3,pos.y()-3))
        exitShift.setDuration(100)
        exitShift.start()
        Effects.dropShadow(button)
    

    button.enterEvent=enterEvent
    button.leaveEvent=leaveEvent

但是当我在动画结束之前快速地将鼠标移入和移出按钮时,按钮开始向西北方向移动

使用动态位置的按钮动画

我发现这是因为在enterEvent()完成之前就触发了leaveEvent(),而且开始值和结束值都是动态的。因此,我尝试提供currentPos作为静态位置,并使用它来代替

@staticmethod
def addButtonHoverAnimation(button:QPushButton,currentPos:QPoint):
    '''
    Method to:
    => Add hover animation for provided button
    '''
    enterShift = QPropertyAnimation(button,b'pos',button)
    enterShift.setStartValue(currentPos)
    enterShift.setEndValue(QPoint(currentPos.x()+3,currentPos.y()+3))
    enterShift.setDuration(100) 
    exitShift = QPropertyAnimation(button,b'pos',button)
    exitShift.setStartValue(QPoint(currentPos.x()-3,currentPos.y()-3))
    exitShift.setEndValue(currentPos)
    exitShift.setDuration(100)  


    def enterEvent(e):  
        button.setProperty(b'pos',exitShift.endValue())
        enterShift.start()
        Effects.dropShadow(button,1,2)
        

    def leaveEvent(e):
        exitShift.start()
        Effects.dropShadow(button)
    

    button.enterEvent=enterEvent
    button.leaveEvent=leaveEvent

在运行时,一旦鼠标进入QPushbutton,它就会移动到其父窗口小部件的左上角,动画开始正常工作。我不明白为什么会这样。但我能够得到,它只发生在我在动画中使用任何静态值时

静态位置的按钮动画:

Button Animation with Static Position

以下是一个例子:

import sys
from PyQt5.QtCore import QEvent, QPoint, QObject, QPropertyAnimation
from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
# This is the same method mentioned above
from styling import addButtonHoverAnimation


class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout=QVBoxLayout()

        button1 = QPushButton("Proceed1", self)
        layout.addWidget(button1)

        button2 = QPushButton("Proceed2", self)
        layout.addWidget(button2)
        self.setLayout(layout)

        self.resize(640, 480)
        addButtonHoverAnimation(button1)
        addButtonHoverAnimation(button2)


def main():
    app = QApplication(sys.argv)

    view = Widget()
    view.show()

    ret = app.exec_()
    sys.exit(ret)


if __name__ == "__main__":
    main()


Tags: posselfdefbutton动画qpointcurrentposqpushbutton
1条回答
网友
1楼 · 发布于 2024-09-29 21:28:04

问题在于,当状态从“进入”更改为“离开”(或反之亦然)时,上一个动画仍然没有结束,因此小部件的位置不是初始或最终位置,因此在启动新动画时,存在累积的偏差。一种可能的解决方案是初始化位置并将其作为参考

另一方面,您不应该执行x.fooMethod = foo_callable,因为许多操作可能会失败,在这种情况下,最好使用eventfilter

import sys
from dataclasses import dataclass
from functools import cached_property

from PyQt5.QtCore import QEvent, QPoint, QObject, QPropertyAnimation
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget


@dataclass
class AnimationManager(QObject):
    widget: QWidget
    delta: QPoint = QPoint(3, 3)
    duration: int = 100

    def __post_init__(self):
        super().__init__(self.widget)
        self._start_value = QPoint()
        self._end_value = QPoint()
        self.widget.installEventFilter(self)
        self.animation.setTargetObject(self.widget)
        self.animation.setPropertyName(b"pos")
        self.reset()

    def reset(self):
        self._start_value = self.widget.pos()
        self._end_value = self._start_value + self.delta
        self.animation.setDuration(self.duration)

    @cached_property
    def animation(self):
        return QPropertyAnimation(self)

    def eventFilter(self, obj, event):
        if obj is self.widget:
            if event.type() == QEvent.Enter:
                self.start_enter_animation()
            elif event.type() == QEvent.Leave:
                self.start_leave_animation()
        return super().eventFilter(obj, event)

    def start_enter_animation(self):
        self.animation.stop()
        self.animation.setStartValue(self.widget.pos())
        self.animation.setEndValue(self._end_value)
        self.animation.start()

    def start_leave_animation(self):
        self.animation.stop()
        self.animation.setStartValue(self.widget.pos())
        self.animation.setEndValue(self._start_value)
        self.animation.start()


class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        button1 = QPushButton("Proceed1", self)
        button1.move(100, 100)

        button2 = QPushButton("Proceed2", self)
        button2.move(200, 200)

        self.resize(640, 480)

        animation_manager1 = AnimationManager(widget=button1)
        animation_manager2 = AnimationManager(widget=button2)


def main():
    app = QApplication(sys.argv)

    view = Widget()
    view.show()

    ret = app.exec_()
    sys.exit(ret)


if __name__ == "__main__":
    main()

184/5000 贸易结果 如果您正在使用布局,则必须重置位置,因为布局不会立即应用位置更改,而只有在父窗口小部件应用更改时才会应用位置更改

class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        button1 = QPushButton("Proceed1")
        button2 = QPushButton("Proceed2")

        lay = QVBoxLayout(self)
        lay.addWidget(button1)
        lay.addWidget(button2)

        self.resize(640, 480)

        self.animation_manager1 = AnimationManager(widget=button1)
        self.animation_manager2 = AnimationManager(widget=button2)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.animation_manager1.reset()
        self.animation_manager2.reset()

相关问题 更多 >

    热门问题