【问题标题】:Animate Geometry inside QGridLayout in PyQtPyQt中QGridLayout内的动画几何
【发布时间】:2021-05-18 23:11:01
【问题描述】:

如何在 QGridLayout 中动画几何变化。我有 QLabel,它将被放置在 QGridlayout 中。当鼠标在 QLabel 内时,它应该展开,而在外面时,它应该收缩回正常状态。我设法制作了动画,但是它并没有从所有四个方面扩展。相反,它会远离网格。

MRE:

import sys
from PyQt5 import QtWidgets, QtCore


class Tile(QtWidgets.QLabel):

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

        # p = self.palette()
        # p.setColor(self.backgroundRole(), QtCore.Qt.red)
        # self.setPalette(p)
        self.setText("hello")
        self.setMinimumSize(100, 100)
        self.setMaximumSize(125, 125)

    def enterEvent(self, a0: QtCore.QEvent) -> None:
        super(Tile, self).enterEvent(a0)

        self.animation = QtCore.QPropertyAnimation(self, b"geometry")
        self.animation.setStartValue(QtCore.QRect(self.geometry()))
        self.animation.setEndValue(QtCore.QRect(self.geometry().adjusted(-25, -25, 25, 25)))
        self.animation.setDuration(150)
        self.animation.start(QtCore.QPropertyAnimation.DeleteWhenStopped)

    def leaveEvent(self, a0: QtCore.QEvent) -> None:
        super(Tile, self).leaveEvent(a0)

        self.animation = QtCore.QPropertyAnimation(self, b"geometry")
        self.animation.setStartValue(QtCore.QRect(self.geometry()))
        self.animation.setEndValue(QtCore.QRect(self.geometry().adjusted(25, 25, -25, -25)))
        self.animation.setDuration(150)
        self.animation.start(QtCore.QPropertyAnimation.DeleteWhenStopped)


class ScrollView(QtWidgets.QWidget):

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

        self.setStyleSheet('border: 1px solid black')

        self.setLayout(QtWidgets.QVBoxLayout())

        widget = QtWidgets.QWidget()

        self.grid_layout = QtWidgets.QGridLayout(widget)

        self.scrollArea = QtWidgets.QScrollArea()
        self.scrollArea.setWidget(widget)
        self.scrollArea.setWidgetResizable(True)

        self.grid_layout.setSpacing(50)

        self.row_width = 4

        self._row = 0
        self._column = 0

        self.layout().addWidget(self.scrollArea)

    def addTile(self):

        self.grid_layout.addWidget(Tile(), self._row, self._column)

        if self._column == 3:
            self._row += 1
            self._column = 0

        else:
            self._column += 1


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

    win = ScrollView()

    for x in range(30):
        win.addTile()

    win.show()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python pyqt pyqt5


    【解决方案1】:

    主要问题是您设置的最大尺寸小于 比结束值:如果您有一个大小为 100x100 的起始矩形,并且您将其每边扩展 25 个像素,它将变为 150x150,而不是 125x125。由于您已经设置了最大值,一旦几何体达到 125x125,它只会在保持最大尺寸的同时更改坐标。

    但还有其他三个问题。

    1. 您总是使用 当前 几何体作为起始值,这可能会成为一个问题:如果您进入或离开 另一个动画正在进行,您会得到目标几何的错误参考;
    2. 如果您非常快地进入/离开小部件,您最终会同时出现两个动画;每次都持续创建动画实际上没有任何好处;
    3. 小部件不考虑调整滚动区域的大小,这会改变纵横比并为新定位带来问题;

    为了避免这一切,你必须只使用一个动画,根据进入/离开事件改变其方向,根据实际几何变化适当修改开始/结束值,当发生 external 调整大小时,还可以正确调整为“默认”大小;最后两点只有如果动画是活动的(因为moveEvent和resizeEvent被几何变化调用)。

    class Tile(QtWidgets.QLabel):
    
        def __init__(self, *args, **kwargs):
            super(Tile, self).__init__(*args, **kwargs)
    
            self.setText("hello")
            self.setMinimumSize(100, 100)
            self.setMaximumSize(150, 150)
            self.animation = QtCore.QPropertyAnimation(self, b"geometry")
            self.animation.setDuration(150)
    
        def animate(self, expand):
            if expand:
                self.animation.setDirection(self.animation.Forward)
            else:
                self.animation.setDirection(self.animation.Backward)
            self.animation.start()
    
        def enterEvent(self, a0: QtCore.QEvent) -> None:
            super(Tile, self).enterEvent(a0)
            self.animate(True)
    
        def leaveEvent(self, a0: QtCore.QEvent) -> None:
            super(Tile, self).leaveEvent(a0)
            self.animate(False)
    
        def updateAnimation(self):
            if not self.animation.state():
                center = self.geometry().center()
                start = QtCore.QRect(QtCore.QPoint(), self.minimumSize())
                start.moveCenter(center)
                self.animation.setStartValue(start)
                end = QtCore.QRect(QtCore.QPoint(), self.maximumSize())
                end.moveCenter(center)
                self.animation.setEndValue(end)
    
        def moveEvent(self, event):
            self.updateAnimation()
    
        def resizeEvent(self, event):
            self.updateAnimation()
            if not self.animation.state():
                rect = QtCore.QRect(QtCore.QPoint(), 
                    self.maximumSize() if self.underMouse() else self.minimumSize())
                rect.moveCenter(self.geometry().center())
                self.setGeometry(rect)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-11
      • 1970-01-01
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多