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

Python 在PyQt中设置QGridLayout内几何体的动画,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,如何在QGridLayout中设置几何体更改动画。我有QLabel,它将被放置在QGridlayout中。当鼠标位于QLabel内时,它应展开,当鼠标位于QLabel外时,它应收缩回正常状态。我设法制作了动画,但它并没有从四面八方展开。相反,它会远离网格 MRE: 主要问题是设置的最大大小小于结束值:如果有一个大小为100x100的起始矩形,并将其每侧扩展25个像素,则它将变为150x150,而不是125x125。因为您已经设置了该最大值,一旦几何体达到125x125,它将只更改坐标,同时保持最

如何在QGridLayout中设置几何体更改动画。我有QLabel,它将被放置在QGridlayout中。当鼠标位于QLabel内时,它应展开,当鼠标位于QLabel外时,它应收缩回正常状态。我设法制作了动画,但它并没有从四面八方展开。相反,它会远离网格

MRE:


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

但还有三个其他问题

  • 您总是使用当前几何体作为开始值,这可能会成为一个问题:如果您在其他动画正在进行时输入或离开,则会得到目标几何体的错误参考
  • 如果你很快进入/离开这个小部件,你将得到两个并发的动画;每次都不停地制作动画,这毫无益处
  • 小部件不考虑滚动区域的大小调整,这将改变纵横比,并为新定位带来问题 为了避免所有这些,您必须仅使用一个动画,根据enter/leave事件更改其方向,根据实际几何体更改正确修改开始/结束值,并在外部调整大小时正确调整为“默认”大小;仅当动画未处于活动状态时,才会执行最后两点(因为几何体更改会调用moveEvent和resizeEvent)

    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()
    
    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)