Search code examples
pythonpython-3.xpyside2qtablewidgetqpropertyanimation

Animation to hide rows in a


I'm trying to create an animation to hide unselected rows in a QTableWidget. I want the height of the rows to decrease until it is 0, for a smoother transition.

I found the following in C++ that does exactly what I'm trying to achieve, but I cannot get the same result in Python: https://forum.qt.io/topic/101437/animate-qtablewidget/4

I noticed they use Q_PROPERTY, but I honestly do not understand how it works...

Here what I came up for now (the animation is not working): `

import sys
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2.QtCore import *

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.resize(600,200)
        self.initUI()

    def initUI(self):
        layout = QHBoxLayout()

        self.table = QTableWidget()
        self.table.setColumnCount(3)
        tableLabels = ["First Name", "Surname", "Age"]
        self.table.setHorizontalHeaderLabels(tableLabels)
        self.table.setRowCount(3)
        self.table.verticalHeader().setMinimumSectionSize(1)

        users = {
                '0': ["peter", "parker", "19"],
                '1': ["bruce", "banner", "42"],
                '2': ["barry", "allen", "35"]
                }
        
        for row, data in users.items():
            for column, value in enumerate(data):
                self.table.setItem(int(row), column, QTableWidgetItem(value))

        button1 = QPushButton("Hide")
        button1.clicked.connect(lambda: self.hide_row())

        layout.addWidget(self.table)
        layout.addWidget(button1)

        self.setLayout(layout)
        self.show()

    def hide_row(self):
        for i in [x for x in range(self.table.rowCount()) if x != self.table.currentRow()]:
            self.rowHeight = QPropertyAnimation(self.table.item(i, 0), b"geometry")
            self.rowHeight.setDuration(400)
            self.rowHeight.setStartValue(QRect(0, 0, 0, self.table.rowHeight(i)))
            self.rowHeight.setEndValue(QRect(0, 0, 0, 0))
            self.rowHeight.start()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

`

Any idea how to achieve this goal in Python?


Solution

  • A Qt animation requires that the parent (or target, in the case of a Property Animation) inherits from QObject, and table widget items do not.

    Also, the geometry property should exist for the target object, and items do not have such a property.

    The solution is to use a QVariantAnimation and use the valueChanged signal to set the row height on the table.

    class Example(QWidget):
    
        def __init__(self):
            super().__init__()
            self.resize(600,200)
            self.initUI()
            self.animation = QVariantAnimation(self)
            self.animation.setDuration(400)
            self.animation.valueChanged.connect(self.animationChanged)
            self.animation.finished.connect(self.finished)
    
        def animationChanged(self, height):
            self.table.setRowHeight(self.currentRow, height)
    
        def finished(self):
            self.table.setRowHidden(self.currentRow, True)
            # reset the height, so that we can use it as a "stored" value in case 
            # we want to show the row again
            self.table.setRowHeight(self.currentRow, self.currentHeight)
    
        def hide_row(self):
            # ignore if the animation is already resizing a row
            if self.animation.state():
                return
            self.currentRow = self.table.currentRow()
            self.currentHeight = self.table.rowHeight(self.currentRow)
            self.animation.setStartValue(self.currentHeight)
            self.animation.setEndValue(1)
            self.animation.start()
    
        # ...