Mes aventures avec Qt deux ans après¶
Voici une page pour montrer comme j'ai bien progressé ;)
Après avoir réalisé un brouillon de Gimpressive-Qt, je n'étais pas content du tout du design du logiciel : des répétitions faites à coup de copié-collé... des classes mal définies... donc Spaghetti ;-)
En réfléchissant et en mobilisant ce que je savais, je pensais que définir une classe-mère dérivant de QGraphicsRectItem devrait me permettre de créer deux sous-classes une pour afficher les pages d'un PDF et l'autre pour afficher(une par une) les images d'un répertoire. Ça, je sais faire : pas de problème ?
En fait, je ne suis pas encore très content car je dois garder une variable pour savoir si j'affiche un PDF ou des images et donc faire des tests un peu partout. Et si je veux rajouter un affichage pour des .odt ou des .svg ?
Donc je m'endors là-dessus :-D Rien de neuf le matin :-( Bon, je plonge dans ma bible C++ (Penser en C++ Volume 1 de Bruce Eckel traduit en français) . Et là, je tombe sur une phrase qui me ruine !
Si vous n'utilisez pas les fonctions virtuelles, vous ne comprenez pas encore la POO. (Chapitre 15.1 p 379 http://bruce-eckel.developpez.com/livres/cpp/traduction/ticpp2vol1/?page=polymorphisme#L15.1)
Moi qui croyait tout savoir Et la solution est là !
En fait, cela s'appelle le polymorphisme et se met en place grâce aux classes abstraites (et surtout aux fonctions virtuelles plus ou moins pures). La classe mère est une classe d'interface (que les puristes ne me lancent pas la pierre !) dans laquelle les fonctions publiques sont précédées du mot-clé virtual :
public:
virtual bool setDocument(const QString &filePath) = 0;
virtual void setPage(int page = -1){ }
virtual void setScale(qreal scale){ }
J'ai donc une classe mère qui est un QGraphicsPixmapItem (une image à placer sur une QGraphicsView) et deux classes filles ClassePDF et ClasseImages qui en héritent classiquement. Et alors me direz-vous ?
Ceci permet de faire un truc qui peut paraitre bizarre :
initialiser une instance de ClassePDF en faisant :
ClasseMere *monDocument = new ClassePDF(); // upcasting
ou initialiser une instance de ClasseImages de la même manière
ClasseMere *monDocument = new ClasseImages();
Si l'on fait, plus loin dans le code : monDocument->setPage(2); le programme trouve tout seul quel est le type réel de monDocument (ClassePDF ou ClasseImage) et exécute la bonne fonction !!!
C'est magique !
Plus de tests pour savoir quelle est le type de monDocument et si on veut rajouter une classe ClasseSVG, il suffit de la faire hériter de la classeMere et d'implémenter les fonctions de l'interface !
et donc on ne touche pas au code utilisant le QGraphicsPixmapItem produit.
Mon code se réduit d'un bon tiers, est plus lisible, plus générique et moi, je suis content d'avoir appris un truc de plus Je comprends un peu plus la POO !
Pas de code sur la forge aujourd'hui, je garde mes secrets de fabrication (non, tout est en vrac et c'est pas beau)