Afin de pouvoir personnaliser votre classeur sans détruire le classeur sur lequel travaille votre voisin, vous allez tout d'abord aller dans le menu File puis Make a copy.... Renommez le classeur en ajoutant votre nom à la fin du nom de fichier par exemple.

Animation d'un widget

Lien vers la doc

On commence bien sûr par rappeler le lien vers la doc PySide...

https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/index.html

On importe les librairies Qt comme d'habitude

In [ ]:
from PySide.QtCore import *
from PySide.QtGui import *
import sys

Le but de l'activité

Nous avons vu comment personaliser l'affichage d'un widget. Nous allons voir qu'il est possible d'animer le déplacement d'un widget sur une surface. Le mécanisme ressemble un peu à celui que nous avons vu avec QGraphicsAnimation mais diffère en ce sens que nous n'animons plus des items sur une scène mais des widgets. Nous utiliserons la classe QPropertyAnimation qui permet d'animer une proriété quelquonque d'un widget.

Capture

Lorsque l-on clique sur la surface, un widget rectangle rouge est créé et descend en bas de la fenêtre. Le résultat est très semblable à celui que nous avions dans l'activité précédente sur l'animation. C'est juste la nature des objets que nous animons qui diffère : si nous souhaitons animer le déplacement de nos cartes à jouer sur le tapis de jeu par exemple.

Le programme sans plus attendre

In [ ]:
WIDTH,HEIGHT=800,600

class Canvas(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        
        self.listeRects=[]
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), Qt.black)
        self.setPalette(p)
               
    def mousePressEvent(self,e) :
        rect=QWidget(self)
        self.listeRects.append(rect)
        rect.show()
        rect.setAutoFillBackground(True)
        p = rect.palette()
        p.setColor(rect.backgroundRole(), Qt.red)
        rect.setPalette(p)
        rect.setGeometry(QRect(e.x(),e.y(),60,40))
        
        self.animation =  QPropertyAnimation(rect,"geometry");
        self.animation.setDuration(1000);
        self.animation.setStartValue(QRect(e.x(),e.y(),60,40));
        self.animation.setEndValue(QRect(e.x(),HEIGHT-100,60,40));

        self.animation.start();

Analyse de ce programme

La partie intéressante pour l'animation se trouve à la fin :

self.animation =  QPropertyAnimation(rect,"geometry");
self.animation.setDuration(1000);
self.animation.setStartValue(QRect(e.x(),e.y(),60,40));
self.animation.setEndValue(QRect(e.x(),HEIGHT-100,60,40));
self.animation.start();
  • On commence par créer notre objet QPropertyAnimation (RTFM) en indiquant le widget à animer et la propriété qui sera modifée lors de l'animation. Il s'agit ici de geometry qui définit la position et la taille de notre widget.
  • vient ensuite la définition du temps de l'animation. On remarque que'ici, on se passe de timeLine. l'objet QPropertyAnimation n'en a pas besoin.
  • ensuite on définit les valeurs de début et de fin de notre propriété geometry. On voit dans la doc de QWidget que la méthode setGeometry() prend en paramètre un objet QRect. C'est donc cet objet que l'on positionne en paramètre dans *setStartValue() et setEndValue()
  • Il n'y a plus qu'à lancer l'animation et admirer :)

Voici le résultat

In [ ]:
class MainWindow(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        
        self.canvas=Canvas()
        self.canvas.setGeometry(0,0,WIDTH,HEIGHT)        
        self.canvas.setFixedSize(WIDTH,HEIGHT)
               
        self.clearBtn=QPushButton("Effacer")
        self.quitBtn=QPushButton("Quitter")
                
        layout=QVBoxLayout()
        layout.addWidget(self.canvas)
        layout1=QHBoxLayout()
        layout1.addWidget(self.clearBtn)
        layout1.addWidget(self.quitBtn)
        layout.addLayout(layout1)      
        self.setLayout(layout)          
        
        self.quitBtn.clicked.connect(self.Quitter)
        self.clearBtn.clicked.connect(self.clear)
        
        self.setWindowTitle("Dessiner dans une fenêtre")
    
    def clear(self):
        for w in self.canvas.listeRects:
            w.deleteLater()
        self.canvas.listeRects=[]
        
    def Quitter(self):
        self.close()
        app.quit()

Remarquez au passage dans cette classe comment on efface les widgets que l'on a créé dans la méthode clear()

In [ ]:
try:
    app = QApplication(sys.argv)
except RuntimeError:
    app=QApplication.instance()
form = MainWindow()
form.show()
app.exec_()

A vous de jouer

Un petit exercice facile :) On souhaite modifier notre animation pour que les rectangles diminiuent de taille au fur à mesure qu'ils descendent jusqu'à obtenir une taille d'un point en arrivant en bas de la fenêtre.

In [ ]:
# Redéfinissez votre classe Canvas ici

La MainWindow est inchangée, on lance juste l'app pour tester.

In [ ]:
form = MainWindow()
form.show()
app.exec_()
In [ ]: