Le modèle OpenGL : représentation interne

| Witold Wysota | Traducteur : Thibaut Cuvelier |

Dans la partie précédente de l'article, on a défini la structure et les attributs que le modèle encapsule. Maintenant, il est temps de rendre possible le stockage de données dans une structure arborescente.

Il y a deux méthodes pour le faire : la dure et la facile. La méthode la plus difficile est d'implémenter toutes les structures de données depuis zéro, alors que la plus facile dérive de QStandardItemModel et réutilise ses méthodes de stockage de données. Dans la plupart des cas, cette dernière méthode devrait fonctionner (cela fonctionne pour tout modèle dont les données sont stockées dans un QVariant), mais cela n'apprend pas grand-chose, on utilisera donc la méthode difficile, qui consiste à créer des structures de données et des méthodes personnalisées pour les utiliser.

Commentez

- Titre : Le modèle OpenGL : représentation interne

- Auteurs : Witold Wysota, Traducteur : Thibaut Cuvelier

- Parution : 6 avril 2011

- Mise à jour : 2 mai 2011

- Licence : Copyright ® 2006 Witold Wysota. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. L'article original

- II. Travailler sur un arbre

- III. Les données spécifiques à GLModel

- IV. La classe QwwGLModelNode

- V. Types d'items

- VI. Tests

- VII. Remerciements

I - L'article original

Cet article est la traduction de l'article Internal representation de Witold Wysota.

II - Travailler sur un arbre

La première chose à faire est de créer l'infrastructure nécessaire pour opérer sur la structure et sa hiérarchie. Comme on veut une structure arborescente, chaque nœud doit stocker une liste de ses enfants et un pointeur au nœud parent, ainsi que quelques méthodes.

QwwGLModelNode *_parent;                       // parent item
QList<QwwGLModelNode> _children;               // child items
void setParent(QwwGLModelNode*);               // set as parent
QwwGLModelNode* parent() const;                // get the parent
const QList<QwwGLModelNode>& children() const; // get list of children
int addChild(QwwGLModelNode*);                 // add a child

Il est aussi pratique de récupérer un enfant particulier et de savoir combien d'ancêtres il a (il sera donc plus facile, a posteriori, de fournir le nombre de lignes pour les index).

QwwGLModelNode* child(uint n);                 // return a child
uint row();                                    // return row number

Finalement, il est bon d'être à même de créer des items et, pour simplifier, on va fournir une manière de créer l'arbre en même temps.

QwwGLModelNode(QwwGLModelNode *p=0);           // create item

III - Les données spécifiques à GLModel

Après ça, on peut ajouter toutes les choses que l'on veut explicitement pour le modèle de données - le type des items et ses attributs, identifiés par des noms. Aussi, des accesseurs en écriture et en lecture doivent être implémentés.

QwwGLModelType _type;                              // item type
QMap<QString> _attributes;                         // attribute list
QwwGLModelType type() const;                       // get the type
void setType(QwwGLModelType);                      // set a type
void setAttribute(const QString &name,             // set an attribute
const QVariant &value);
QVariant attribute(const QString &name);           // get a single attribute
const QMap<QString> &attributes() const;           // get attribute list

L'implémentation de ces méthodes est triviale et ne sera donc pas commentée.

IV - La classe QwwGLModelNode

Au final, on obtient une classe du genre :

class QwwGLModelNode {
public:
QwwGLModelNode(QwwGLModelNode *p=0) {
setParent(p);
if(p)
_parent->addChild(this);
}
~QwwGLModelNode(){
qDeleteAll(_children);          // delete all child items
}
QwwGLModelNode *child(uint n) {
return _children.at(n);
}
uint row(){
Q_ASSERT(_parent);              // make sure we have a parent
return _parent->children().indexOf(this);
}
void setParent(QwwGLModelNode *p) {
_parent = p;
}
QwwGLModelNode* parent() const {
return _parent;
}
const QList<QwwGLModelNode*>& children() const {
return _children;
}
int addChild(QwwGLModelNode *ch) {
_children << ch;
return _children.size()-1;
}
QwwGLModelType type() const {
return _type;
}
void setType(QwwGLModelType t) {
_type = t;
}
void setAttribute(const QString &name, const QVariant &value) {
_attributes[name] = value;
}
QVariant attribute(const QString &name) {
if(!_attributes.contains(name)) // if attribute doesn't exist
return QVariant();          // return an empty value
return _attributes[name];
}
const QMap<QString> &attributes() const {
return _attributes;
}
private:
QwwGLModelNode *_parent;
QList<QwwGLModelNode*> _children;
QwwGLModelType _type;
QMap<QString> _attributes;
};

V - Types d'items

Maintenant, il faut décider comment créer les différents items. Il y a deux approches possibles. La première est de fournir des méthodes pour créer les différents types d'item et, en utilisant les méthodes existantes, remplir les données requises. L'autre est de dériver le nœud pour créer autant de classes enfant que de types d'item à utiliser. Une méthode plus rapide se passe de cette dérivation, mais les méthodes virtuelles pourraient se révéler très utiles plus tard, en fonction de ce qu'on veut faire avec le modèle. Comme ceci n'est qu'un exemple, évitons de créer trop de classes.

VI - Tests

Maintenant, on devrait pouvoir compiler et tester la classe. Un simple main() devrait faire l'affaire.

typedef int QwwGLModelType;
#include "qwwglmodelnode.h"
int main(){
QwwGLModelNode *n = new QwwGLModelNode();
for(int i=0;i<10;i++){
QwwGLModelNode *cn = new QwwGLModelNode(n);
for(int i=0;i<3;i++){
new QwwGLModelNode(cn);
}
}
delete n;
return 0;
}

Si tout se passe bien, le code devrait compiler et se lancer sans de souci.

La prochaine fois, on décrira la manière d'implémenter la partie de lecture du modèle lui-même. À ce point, on pourra le voir en action.

VII - Remerciements

Merci à Louis du Verdier et à Claude Leloup pour leur relecture !