Exemple de délégué « Star »
L'exemple « Star Delegate » montre comment créer un délégué capable de s'afficher lui-même et prenant en charge l'édition.

Lors de l’affichage de données dans un QListView, un QTableView ou un QTreeView, les éléments individuels sont dessinés par un délégué. De plus, lorsque l’utilisateur commence à modifier un élément (par exemple, en double-cliquant dessus), le délégué fournit un widget d’édition qui est placé par-dessus l’élément pendant la modification.
Les délégués sont des sous-classes de ` QAbstractItemDelegate`. Qt fournit ` QStyledItemDelegate`, qui hérite de ` QAbstractItemDelegate ` et gère les types de données les plus courants (notamment ` int ` et ` QString`). Si nous avons besoin de prendre en charge des types de données personnalisés, ou si nous souhaitons personnaliser l’affichage ou la modification de types de données existants, nous pouvons créer une sous-classe de QAbstractItemDelegate ou de QStyledItemDelegate. Consultez la section Classes de délégués pour plus d’informations sur les délégués, et Programmation modèle/vue si vous avez besoin d’une introduction de haut niveau à l’architecture modèle/vue de Qt (y compris les délégués).
Dans cet exemple, nous verrons comment implémenter un délégué personnalisé pour afficher et modifier un type de données « note par étoiles », capable de stocker des valeurs telles que « 1 étoile sur 5 ».
L’exemple se compose des classes suivantes :
StarRatingest le type de données personnalisé. Il stocke une note exprimée en étoiles, telle que « 2 étoiles sur 5 » ou « 5 étoiles sur 6 ».StarDelegatehérite de ` QStyledItemDelegate ` et prend en charge `StarRating` (en plus des types de données déjà gérés par ` QStyledItemDelegate`).StarEditorhérite de ` QWidget ` et est utilisé par `StarDelegate` pour permettre à l’utilisateur de modifier une note par étoiles à l’aide de la souris.
Pour montrer l’ StarDelegate en action, nous allons remplir un QTableWidget avec des données et y installer le délégué.
Définition de la classe StarDelegate
Voici la définition de la classe StarDelegate:
class StarDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override;
private slots:
void commitAndCloseEditor();
};Toutes les fonctions publiques sont des fonctions virtuelles réimplémentées à partir de ` QStyledItemDelegate ` afin de permettre un rendu et une modification personnalisés.
Implémentation de la classe StarDelegate
La fonction paint() est réimplémentée à partir de QStyledItemDelegate et est appelée chaque fois que la vue doit rafraîchir un élément :
void StarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarRating starRating = qvariant_cast<StarRating>(index.data());
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
starRating.paint(painter, option.rect, option.palette,
StarRating::EditMode::ReadOnly);
} else {
QStyledItemDelegate::paint(painter, option, index);
}La fonction est appelée une fois pour chaque élément, représenté par un objet ` QModelIndex ` issu du modèle. Si les données stockées dans l’élément sont de type ` StarRating`, nous le dessinons nous-mêmes ; sinon, nous laissons ` QStyledItemDelegate ` s’en charger. Cela garantit que ` StarDelegate ` peut gérer les types de données les plus courants.
Si l’élément est de type StarRating, nous dessinons l’arrière-plan lorsque l’élément est sélectionné, puis nous dessinons l’élément à l’aide de StarRating::paint(), que nous aborderons plus tard.
StartRatingLes s peuvent être stockés dans un QVariant grâce à la macro Q_DECLARE_METATYPE() qui apparaît dans starrating.h. Nous y reviendrons plus tard.
La fonction createEditor() est appelée lorsque l’utilisateur commence à modifier un élément :
QWidget *StarDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarEditor *editor = new StarEditor(parent);
connect(editor, &StarEditor::editingFinished,
this, &StarDelegate::commitAndCloseEditor);
return editor;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}Si l’élément est un « StarRating », nous créons un « StarEditor » et connectons son signal « editingFinished() » à notre slot « commitAndCloseEditor() », afin de pouvoir mettre à jour le modèle lorsque l’éditeur se ferme.
Voici l’implémentation de ` commitAndCloseEditor()` :
void StarDelegate::commitAndCloseEditor()
{
StarEditor *editor = qobject_cast<StarEditor *>(sender());
emit commitData(editor);
emit closeEditor(editor);
}Lorsque l’utilisateur a terminé ses modifications, nous émettons les événements commitData() et closeEditor() (tous deux déclarés dans QAbstractItemDelegate), afin d’indiquer au modèle que des données ont été modifiées et d’informer la vue que l’éditeur n’est plus nécessaire.
La fonction setEditorData() est appelée lors de la création d’un éditeur afin de l’initialiser avec les données du modèle :
void StarDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarRating starRating = qvariant_cast<StarRating>(index.data());
StarEditor *starEditor = qobject_cast<StarEditor *>(editor);
starEditor->setStarRating(starRating);
} else {
QStyledItemDelegate::setEditorData(editor, index);
}
}Il suffit d’appeler ` setStarRating() ` sur l’éditeur.
La fonction ` setModelData()` est appelée pour valider les données de l’éditeur dans le modèle une fois l’édition terminée :
void StarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarEditor *starEditor = qobject_cast<StarEditor *>(editor);
model->setData(index, QVariant::fromValue(starEditor->starRating()));
} else {
QStyledItemDelegate::setModelData(editor, model, index);
}
}La fonction ` sizeHint() ` renvoie la taille préférée d’un élément :
QSize StarDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarRating starRating = qvariant_cast<StarRating>(index.data());
return starRating.sizeHint();
}
return QStyledItemDelegate::sizeHint(option, index);
}Il suffit de transmettre l’appel à ` StarRating`.
Définition de la classe StarEditor
La classe ` StarEditor ` a été utilisée lors de l’implémentation de ` StarDelegate`. Voici la définition de la classe :
class StarEditor : public QWidget
{
Q_OBJECT
public:
StarEditor(QWidget *parent = nullptr);
QSize sizeHint() const override;
void setStarRating(const StarRating &starRating) {
myStarRating = starRating;
}
StarRating starRating() { return myStarRating; }
signals:
void editingFinished();
protected:
void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
int starAtPosition(int x) const;
StarRating myStarRating;
};Cette classe permet à l’utilisateur de modifier un « StarRating » en déplaçant la souris sur l’éditeur. Elle émet le signal « editingFinished() » lorsque l’utilisateur clique sur l’éditeur.
Les fonctions protégées sont réimplémentées à partir de ` QWidget ` pour gérer les événements de souris et de dessin. La fonction privée ` starAtPosition() ` est une fonction d'aide qui renvoie le numéro de l'étoile située sous le pointeur de la souris.
Implémentation de la classe StarEditor
Commençons par le constructeur :
StarEditor::StarEditor(QWidget *parent)
: QWidget(parent)
{
setMouseTracking(true);
setAutoFillBackground(true);
}Nous activons la fonction ` mouse tracking ` sur le widget afin de pouvoir suivre le curseur même lorsque l’utilisateur ne maintient aucun bouton de souris enfoncé. Nous activons également la fonction ` auto-fill background ` de ` QWidget` pour obtenir un arrière-plan opaque. (Sans cet appel, l’arrière-plan de la vue transparaîtrait à travers l’éditeur.)
La fonction ` paintEvent()` est réimplémentée à partir de ` QWidget` :
void StarEditor::paintEvent(QPaintEvent *)
{
QPainter painter(this);
myStarRating.paint(&painter, rect(), palette(),
StarRating::EditMode::Editable);
}Nous appelons simplement ` StarRating::paint() ` pour dessiner les étoiles, exactement comme nous l’avons fait lors de l’implémentation de ` StarDelegate`.
void StarEditor::mouseMoveEvent(QMouseEvent *event)
{
const int star = starAtPosition(event->position().toPoint().x());
if (star != myStarRating.starCount() && star != -1) {
myStarRating.setStarCount(star);
update();
}
QWidget::mouseMoveEvent(event);
}Dans le gestionnaire d’événement de la souris, nous appelons ` setStarCount() ` sur le membre de données privé ` myStarRating ` pour refléter la position actuelle du curseur, puis nous appelons ` QWidget::update()` pour forcer un rafraîchissement de l’affichage.
void StarEditor::mouseReleaseEvent(QMouseEvent *event)
{
emit editingFinished();
QWidget::mouseReleaseEvent(event);
}Lorsque l’utilisateur relâche un bouton de la souris, nous émettons simplement le signal editingFinished().
int StarEditor::starAtPosition(int x) const
{
const int star = (x / (myStarRating.sizeHint().width()
/ myStarRating.maxStarCount())) + 1;
if (star <= 0 || star > myStarRating.maxStarCount())
return -1;
return star;
}La fonction starAtPosition() utilise des notions élémentaires d’algèbre linéaire pour déterminer quelle étoile se trouve sous le curseur.
Définition de la classe StarRating
class StarRating
{
public:
enum class EditMode { Editable, ReadOnly };
explicit StarRating(int starCount = 1, int maxStarCount = 5);
void paint(QPainter *painter, const QRect &rect,
const QPalette &palette, EditMode mode) const;
QSize sizeHint() const;
int starCount() const { return myStarCount; }
int maxStarCount() const { return myMaxStarCount; }
void setStarCount(int starCount) { myStarCount = starCount; }
void setMaxStarCount(int maxStarCount) { myMaxStarCount = maxStarCount; }
private:
QPolygonF starPolygon;
QPolygonF diamondPolygon;
int myStarCount;
int myMaxStarCount;
};
Q_DECLARE_METATYPE(StarRating)La classe ` StarRating ` représente une note sous forme d’un nombre d’étoiles. Outre le stockage des données, elle est également capable d’afficher les étoiles sur une ` QPaintDevice`, qui, dans cet exemple, est soit une vue, soit un éditeur. La variable membre ` myStarCount ` stocke la note actuelle, et ` myMaxStarCount ` stocke la note maximale possible (généralement 5).
La macro « Q_DECLARE_METATYPE() » indique à « QVariant » le type « StarRating », ce qui permet de stocker les valeurs de « StarRating » dans « QVariant ».
Implémentation de la classe StarRating
Le constructeur initialise ` myStarCount ` et ` myMaxStarCount`, puis configure les polygones utilisés pour dessiner les étoiles et les losanges :
StarRating::StarRating(int starCount, int maxStarCount)
: myStarCount(starCount),
myMaxStarCount(maxStarCount)
{
starPolygon << QPointF(1.0, 0.5);
for (int i = 1; i < 5; ++i)
starPolygon << QPointF(0.5 + 0.5 * std::cos(0.8 * i * 3.14),
0.5 + 0.5 * std::sin(0.8 * i * 3.14));
diamondPolygon << QPointF(0.4, 0.5) << QPointF(0.5, 0.4)
<< QPointF(0.6, 0.5) << QPointF(0.5, 0.6)
<< QPointF(0.4, 0.5);
}La fonction ` paint() ` dessine les étoiles de cet objet ` StarRating ` sur un périphérique de dessin :
void StarRating::paint(QPainter *painter, const QRect &rect,
const QPalette &palette, EditMode mode) const
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setPen(Qt::NoPen);
painter->setBrush(mode == EditMode::Editable ?
palette.highlight() :
palette.windowText());
const int yOffset = (rect.height() - PaintingScaleFactor) / 2;
painter->translate(rect.x(), rect.y() + yOffset);
painter->scale(PaintingScaleFactor, PaintingScaleFactor);
for (int i = 0; i < myMaxStarCount; ++i) {
if (i < myStarCount)
painter->drawPolygon(starPolygon, Qt::WindingFill);
else if (mode == EditMode::Editable)
painter->drawPolygon(diamondPolygon, Qt::WindingFill);
painter->translate(1.0, 0.0);
}
painter->restore();
}Nous définissons d'abord le stylo et le pinceau que nous utiliserons pour le dessin. Le paramètre ` mode ` peut prendre la valeur ` Editable ` ou ` ReadOnly`. Si ` mode ` est modifiable, nous utilisons la couleur ` Highlight ` à la place de la couleur ` WindowText ` pour dessiner les étoiles.
Ensuite, nous dessinons les étoiles. Si nous sommes en mode « Edit », nous dessinons des losanges à la place des étoiles si la note est inférieure à la note maximale.
La fonction sizeHint() renvoie la taille recommandée pour la zone sur laquelle dessiner les étoiles :
La taille recommandée est juste suffisante pour dessiner le nombre maximal d’étoiles. Cette fonction est appelée à la fois par ` StarDelegate::sizeHint() ` et par ` StarEditor::sizeHint()`.
La fonction ` main() `
Voici la fonction ` main() ` du programme :
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget tableWidget(4, 4);
tableWidget.setItemDelegate(new StarDelegate);
tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked
| QAbstractItemView::SelectedClicked);
tableWidget.setSelectionBehavior(QAbstractItemView::SelectRows);
tableWidget.setHorizontalHeaderLabels({"Title", "Genre", "Artist", "Rating"});
populateTableWidget(&tableWidget);
tableWidget.resizeColumnsToContents();
tableWidget.resize(500, 300);
tableWidget.show();
return app.exec();
}La fonction ` main() ` crée un objet ` QTableWidget ` et y définit un ` StarDelegate `. Les propriétés ` DoubleClicked ` et ` SelectedClicked ` sont définies sur ` edit triggers`, de sorte que l'éditeur s'ouvre d'un simple clic lorsque l'élément de notation par étoiles est sélectionné.
La fonction populateTableWidget() remplit l’ QTableWidget avec des données :
void populateTableWidget(QTableWidget *tableWidget)
{
static constexpr struct {
const char *title;
const char *genre;
const char *artist;
int rating;
} staticData[] = {
{ "Mass in B-Minor", "Baroque", "J.S. Bach", 5 },
...
{ nullptr, nullptr, nullptr, 0 }
};
for (int row = 0; staticData[row].title != nullptr; ++row) {
QTableWidgetItem *item0 = new QTableWidgetItem(staticData[row].title);
QTableWidgetItem *item1 = new QTableWidgetItem(staticData[row].genre);
QTableWidgetItem *item2 = new QTableWidgetItem(staticData[row].artist);
QTableWidgetItem *item3 = new QTableWidgetItem;
item3->setData(0,
QVariant::fromValue(StarRating(staticData[row].rating)));
tableWidget->setItem(row, 0, item0);
tableWidget->setItem(row, 1, item1);
tableWidget->setItem(row, 2, item2);
tableWidget->setItem(row, 3, item3);
}
}Notez l’appel à QVariant::fromValue pour convertir une StarRating en une QVariant.
Extensions possibles et suggestions
Il existe de nombreuses façons de personnaliser le framework modèle/vue de Qt. L’approche utilisée dans cet exemple convient à la plupart des délégués et éditeurs personnalisés. Voici quelques exemples de possibilités non utilisées par le délégué « star » et l’éditeur « star » :
- Il est possible d’ouvrir des éditeurs par programmation en appelant ` QAbstractItemView::edit()` (), au lieu de s’appuyer sur des déclencheurs d’édition. Cela pourrait être utilisé pour prendre en charge d’autres déclencheurs d’édition que ceux proposés par l’énumération ` QAbstractItemView::EditTrigger `. Par exemple, dans l’exemple du délégué Star, passer la souris sur un élément pourrait être un moyen pertinent de faire apparaître un éditeur.
- En réimplémentant la méthode ` QAbstractItemDelegate::editorEvent()`, il est possible d’implémenter l’éditeur directement dans le délégué, au lieu de créer une sous-classe distincte de ` QWidget `.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.