【问题标题】:Resize widget from center when animating the size property为 size 属性设置动画时从中心调整小部件的大小
【发布时间】:2025-12-26 19:10:07
【问题描述】:

我正在尝试编写一个小部件,它在鼠标悬停时会略微增大,而在鼠标再次离开时会减小。
到目前为止,这是我想出的:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from random import randrange


class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setFixedSize(500, 500)

        cent_widget = QWidget()
        self.setCentralWidget(cent_widget)

        layout = QVBoxLayout()
        cent_widget.setLayout(layout)

        layout.addWidget(MyItem(), Qt.AlignCenter,
                         alignment=Qt.AlignCenter)


class MyItem(QLabel):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setBaseSize(200, 250)
        self.setMinimumSize(self.baseSize())
        self.resize(self.baseSize())

        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        self.setStyleSheet('background: #{:02x}{:02x}{:02x}'.format(
            randrange(255), randrange(255), randrange(255)
        ))

        # Animation
        self._enlarged = False
        self.zoom_factor = 1.2

        self.anim = QPropertyAnimation(self, b'size')
        self.anim.setEasingCurve(QEasingCurve.InOutSine)
        self.anim.setDuration(250)

    def enterEvent(self, event: QEvent) -> None:
        self.resize_anim()
        self._enlarged = True

    def leaveEvent(self, event: QEvent) -> None:
        self.resize_anim()
        self._enlarged = False

    def resize_anim(self):
        if self._enlarged:
            new_size = self.baseSize()
        else:
            new_size = QSize(
                int(self.baseSize().width() * self.zoom_factor),
                int(self.baseSize().height() * self.zoom_factor)
            )
        self.anim.setEndValue(new_size)
        self.anim.start()


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

它几乎按照我想要的方式工作,我唯一的问题是小部件从左上角而不是中心调整大小。
我该如何改变呢?

【问题讨论】:

    标签: python pyqt5 resize qpropertyanimation


    【解决方案1】:

    您应该使用几何属性而不是使用 size 属性设置动画,因为它是相对于父窗口小部件的,因此您可以为其几何设置动画,使中心保持不变。

    from PyQt5.QtCore import (
        QAbstractAnimation,
        QEasingCurve,
        QEvent,
        QPropertyAnimation,
        QRect,
        Qt,
    )
    from PyQt5.QtGui import QColor
    from PyQt5.QtWidgets import (
        QApplication,
        QLabel,
        QMainWindow,
        QSizePolicy,
        QVBoxLayout,
        QWidget,
    )
    
    import random
    
    
    class MainWindow(QMainWindow):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            self.setFixedSize(500, 500)
    
            cent_widget = QWidget()
            self.setCentralWidget(cent_widget)
    
            layout = QVBoxLayout(cent_widget)
            layout.addWidget(MyItem(), alignment=Qt.AlignCenter)
    
    
    class MyItem(QLabel):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            self.setBaseSize(200, 250)
            self.setMinimumSize(self.baseSize())
            self.resize(self.baseSize())
    
            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
    
            self.setStyleSheet(
                "background: {}".format(QColor(*random.sample(range(255), 3)).name())
            )
    
            # Animation
            self.zoom_factor = 1.2
    
            self.anim = QPropertyAnimation(self, b"geometry")
            self.anim.setEasingCurve(QEasingCurve.InOutSine)
            self.anim.setDuration(250)
    
        def enterEvent(self, event: QEvent) -> None:
    
            initial_rect = self.geometry()
            final_rect = QRect(
                0,
                0,
                int(initial_rect.width() * self.zoom_factor),
                int(initial_rect.height() * self.zoom_factor),
            )
            final_rect.moveCenter(initial_rect.center())
    
            self.anim.setStartValue(initial_rect)
            self.anim.setEndValue(final_rect)
            self.anim.setDirection(QAbstractAnimation.Forward)
            self.anim.start()
    
        def leaveEvent(self, event: QEvent) -> None:
            self.anim.setDirection(QAbstractAnimation.Backward)
            self.anim.start()
    
    
    if __name__ == "__main__":
        app = QApplication([])
        window = MainWindow()
        window.show()
        app.exec()
    

    【讨论】: