在PyQt中设置QGridLayout内几何体的动画

2024-09-29 21:25:29 发布

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

如何在QGridLayout中设置几何体更改动画。我有QLabel,它将被放置在QGridlayout中。当鼠标位于QLabel内时,它应展开,当鼠标位于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()

Tags: selfinitdefargscolumna0kwargstile
1条回答
网友
1楼 · 发布于 2024-09-29 21:25:29

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

但还有三个其他问题

  1. 您总是使用当前几何体作为开始值,这可能会成为一个问题:如果您在另一个动画正在进行时输入或离开,则会得到目标几何体的错误参考
  2. 如果你很快进入/离开这个小部件,你将得到两个并发的动画;每次都不停地制作动画,这毫无益处
  3. 小部件不考虑滚动区域的大小调整,这将改变纵横比,并为新定位带来问题

为了避免所有这一切,您必须仅使用一个动画,根据enter/leave事件更改其方向,根据实际几何体更改正确修改开始/结束值,并且在发生外部调整大小时,还必须正确调整到“默认”大小;最后两点仅在动画处于活动状态时执行(因为几何体更改会调用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)

相关问题 更多 >

    热门问题