Comme vous l'aurez sans doute remarqué, nous n'avons jusqu'à présent pas évoqué le dernier aspect à savoir le
Contrôleur. Voici la vérité : Qt n'utilise pas tout à fait une architecture MVC. Ce n'est plus un
C mais désormais un
D. Pour ceux qui n'auraient pas fait le rapprochement, il s'agit d'un
D pour ...
Delegate. Eh oui, maintenant, vous savez tout : Qt utilise en réalité une architecture
model/view entourée d'un delegate.
Présentation du concept
Mais à quoi Diantre ce fameux Delegate sert-il ?
Au contraire d'une architecture MVC classique, l'architecture
model/view instaurée par Qt ne fournit pas de réel composant permettant de gérer les interactions avec l'utilisateur. De ce fait, ceci est géré par la vue elle-même.
Cependant, pour des raisons de flexibilité, l'interaction et les entrées utilisateurs ne sont non pas prises en compte par un composant totalement séparé, à savoir le contrôleur, mais par un composant
interne à la vue : le Delegate. Ce composant est responsable de deux choses :
- Personnaliser l'édition des éléments au moyen d'un editor ;
- Personnaliser le rendu des éléments à l'intérieur d'une vue.
Ainsi, grace à un delegate, il vous est possible de personnaliser la manière dont les entrées utilisateurs seront gérées, ainsi que le rendu des éléments.
Pour exemple, lorsque vous utilisez une QTableView avec un modèle éditable, lorsque vous cliquez sur une cellule de votre table, il vous est possible de modifier la valeur de la cellule, grace à une
LineEdit.
Cela est possible grace au Delegate qui a fourni à la vue un moyen d'éditer les données au travers d'un composant de type
QLineEdit.
Utiliser un Delegate existant
Vous aurez sans douté remarqué, que, par défaut, même si vous n'avez paramétré aucun delegate, votre vue se charge toute seule de fournir un moyen d'éditer vos données. Cela est du au fait que les vues sont déjà dotées d'un delegate par défaut :
QStyledItemDelegate. En effet, de base, Qt fournit deux delegate par défaut :
La seule différence résidant entre ces deux Delegate est que QStyledItemDelegate utilise le style courant pour le rendu des données. Ces deux Delegate héritent cependant de la même classe, à savoir
QAbstractItemDelegate, fournissant une interface de base générique à tous les delegate.
Qt fournit en outre
QSqlRelationalDelegate, permettant d'éditer et afficher des données d'un QSqlRelationalTableModel.
Cependant, même si les vues sont dotés d'un delegate par défaut, il est bien entendu possible de modifier et paramétrer celui-ci grâce à la fonction
void QAbstractItemView::setItemDelegate ( QAbstractItemDelegate * delegate ). Il est aussi possible de récupérer le delegate courant grâce à la fonction
QAbstractItemDelegate * QAbstractItemView::itemDelegate () const
Jetons un coup d'oeil à la mécanique interne
Nous avons dit que le delegate était en partie chargé de fournir à l'utilisateur un moyen d'éditer les données au sein d'une vue, en fournissant un
editor. Cet editor est tout simplement un composant de type
QWidget. Même si précédemment nous avons évoqué l'exemple d'une
QLineEdit, le delegate par défaut ne crée pas
que des QLineEdit. En effet, celui-ci crée le composant adapté au
type de données de la cellule. Par exemple, si la cellule contient un
int, le delegate par défaut créera un composant de type
QSpinBox. Pour un composant de type
double, il s'agira d'un
QDoubleSpinBox.
Regardons le code de %QTDIR%/src/gui/itemviews/qstyleditemdelegate.cpp, et notamment la méthode createEditor :
Code : C++ | QVariant::Type t = static_cast<QVariant::Type>(index.data(Qt::EditRole).userType());
return d->editorFactory()->createEditor(t, parent);
|
Que font ces deux lignes ? Tout d'abord, le
type de la donnée contenue dans la cellule est stoqué dans la variable t. Souvenez-vous, la fonction data() de QAbstractItemModel renvoyant une variable de type
QVariant, celle-ci est capable de gérer de nombreux types de données. La fonction
userType() renvoie ce type sous forme d'un int (ce qui justifie l'emploi de static_cast). Si la variable est de type QString, t serait donc égal à QVariant::String, QVariant::Date pour une variable de type QDate, ... La liste complète étant disponible
ici
La deuxième ligne fait appel à la méthode
createEditor de
editorFactory().
La méthode editorFactory() étant définie comme :
Code : C++ | const QItemEditorFactory *editorFactory() const
{
return factory ? factory : QItemEditorFactory::defaultFactory();
}
|
On y comprend donc que cette méthode retourne la factory par défaut si aucune n'a été définie. Mais qu'est-ce donc que cette fameuse
factory ?
QItemEditorFactory est une classe dite de fabrique (
factory), permettant entre autre de créer l'editor correspondant au type de données que l'on a évoqué plus haut.
Par défaut, voici les composants crées en fonction du type :
| Type | Widget |
|---|
| bool |
QComboBox |
| int / unsigned int |
QSpinBox |
| double |
QDoubleSpinBox |
| QDate |
QDateEdit |
| QDateTime |
QDateTimeEdit |
| QPixmap |
QLabel |
| QString |
QLineEdit |
| QTime |
QTimeEdit |
Le delegate par défaut est donc capable de gérer une grande partie des types de données. Cependant, il se peut que nous ayons besoin d'un comportement autre que celui par défaut. Pour cela, il suffit de créer notre propre delegate, c'est ce que nous allons voir dans le chapitre suivant.