Sur cette page

Exemple de complétion de modèle arborescent

L'exemple « Tree Model Completer » montre comment fournir des fonctionnalités de complétion pour un modèle hiérarchique, en utilisant un point comme séparateur pour accéder aux objets des niveaux « Child », « GrandChild » et « GrandGrandChild ».

Visualisation d'un modèle arborescent et différentes options pour le « completer »

À l'instar de l'exemple « Completer », nous fournissons des objets « QComboBox » permettant de sélectionner le mode de complétion et la sensibilité à la casse, ainsi qu'un objet « QCheckBox » pour les complétions par enveloppement.

Le fichier de ressources

Le contenu de TreeModelCompleter est lu à partir du fichier treemodel.txt. Ce fichier est intégré au fichier de ressources treemodelcompleter.qrc, qui contient les éléments suivants :

<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
   <file>resources/treemodel.txt</file>
</qresource>
</RCC>

Définition de la classe TreeModelCompleter

La classe ` TreeModelCompleter ` est une sous-classe de ` QCompleter ` dotée de deux constructeurs : l’un prenant ` parent ` en argument, et l’autre prenant ` parent ` et ` model ` en arguments.

class TreeModelCompleter : public QCompleter
{
    Q_OBJECT
    Q_PROPERTY(QString separator READ separator WRITE setSeparator)

public:
    explicit TreeModelCompleter(QObject *parent = nullptr);
    explicit TreeModelCompleter(QAbstractItemModel *model, QObject *parent = nullptr);

    QString separator() const;
public slots:
    void setSeparator(const QString &separator);

protected:
    QStringList splitPath(const QString &path) const override;
    QString pathFromIndex(const QModelIndex &index) const override;

private:
    QString sep;
};

La classe réimplémente les fonctions protégées splitPath() et pathFromIndex() pour s'adapter à un modèle arborescent. Pour plus d'informations sur la personnalisation de QCompleter afin de l'adapter aux modèles arborescents, reportez-vous à Handling Tree Models.

TreeModelCompleter Elle dispose également d'une propriété « separator » déclarée à l'aide de la macro Q_PROPERTY(). Le séparateur possède des attributs READ et WRITE, ainsi que les fonctions correspondantes separator() et setSeparator(). Pour plus d'informations sur Q_PROPERTY(), consultez le système de propriétés de Qt.

Implémentation de la classe TreeModelCompleter

Le premier constructeur crée un objet ` TreeModelCompleter ` avec un parent, tandis que le second constructeur crée un objet avec un parent et une valeur pour ` QAbstractItemModel` et ` model`.

TreeModelCompleter::TreeModelCompleter(QObject *parent)
    : QCompleter(parent)
{
}

TreeModelCompleter::TreeModelCompleter(QAbstractItemModel *model, QObject *parent)
    : QCompleter(model, parent)
{
}

La fonction ` separator() ` est une fonction de récupération qui renvoie la chaîne de séparation.

QString TreeModelCompleter::separator() const
{
    return sep;
}

Comme mentionné précédemment, la fonction ` splitPath() ` est réimplémentée car l’implémentation par défaut est plus adaptée aux modèles de type « QFileSystemModel » ou de liste. Afin que ` QCompleter ` puisse diviser le chemin en une liste de chaînes de caractères correspondant à chaque niveau, nous le divisons à l’aide de ` QString::split()` en utilisant ` sep ` comme séparateur.

QStringList TreeModelCompleter::splitPath(const QString &path) const
{
    return (sep.isNull() ? QCompleter::splitPath(path) : path.split(sep));
}

La fonction pathFromIndex() renvoie les données pour la méthode completionRole() d’un modèle arborescent. Cette fonction est réimplémentée, car son implémentation par défaut est plus adaptée aux modèles de type liste. En l’absence de séparateur, nous utilisons l’implémentation par défaut de QCompleter; dans le cas contraire, nous utilisons la fonction prepend() pour remonter dans l’arborescence et accumuler les données. La fonction renvoie ensuite un objet ` QStringList`, ` dataList`, en utilisant un séparateur pour relier les objets de différents niveaux.

QString TreeModelCompleter::pathFromIndex(const QModelIndex &index) const
{
    if (sep.isNull())
        return QCompleter::pathFromIndex(index);

    // navigate up and accumulate data
    QStringList dataList;
    for (QModelIndex i = index; i.isValid(); i = i.parent())
        dataList.prepend(model()->data(i, completionRole()).toString());

    return dataList.join(sep);
}

Définition de la classe `MainWindow`

La classe ` MainWindow ` est une sous-classe de ` QMainWindow ` et implémente cinq slots personnalisés : ` about()`, ` changeCase()`, ` changeMode()`, ` highlight()` et ` updateContentsLabel()`.

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);

private slots:
    void about();
    void changeCase(int);
    void changeMode(int);
    void highlight(const QModelIndex &index);
    void updateContentsLabel(const QString &sep);

De plus, la classe dispose de deux fonctions privées, createMenu() et modelFromFile(), ainsi que d’instances privées de QTreeView, QComboBox, QLabel, TreeModelCompleter et QLineEdit.

private:
    void createMenu();
    QAbstractItemModel *modelFromFile(const QString &fileName);

    QTreeView *treeView = nullptr;
    QComboBox *caseCombo = nullptr;
    QComboBox *modeCombo = nullptr;
    QLabel *contentsLabel = nullptr;
    TreeModelCompleter *completer = nullptr;
    QLineEdit *lineEdit = nullptr;
};

Implémentation de la classe MainWindow

Le constructeur de ` MainWindow` crée un objet ` MainWindow ` avec un parent et initialise les objets ` completer ` et ` lineEdit`. La fonction ` createMenu() ` est appelée pour configurer les menus « Fichier » et « Aide ». Le modèle de ` completer` est défini sur l’objet ` QAbstractItemModel ` obtenu à partir de ` modelFromFile()`, et le signal ` highlighted()` est connecté au slot ` highlight() ` de ` MainWindow`.

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    createMenu();

    completer = new TreeModelCompleter(this);
    completer->setModel(modelFromFile(":/resources/treemodel.txt"));
    completer->setSeparator(QLatin1String("."));
    QObject::connect(completer, QOverload<const QModelIndex &>::of(&TreeModelCompleter::highlighted),
                     this, &MainWindow::highlight);

    QWidget *centralWidget = new QWidget;

    QLabel *modelLabel = new QLabel;
    modelLabel->setText(tr("Tree Model<br>(Double click items to edit)"));

    QLabel *modeLabel = new QLabel;
    modeLabel->setText(tr("Completion Mode"));
    modeCombo = new QComboBox;
    modeCombo->addItem(tr("Inline"));
    modeCombo->addItem(tr("Filtered Popup"));
    modeCombo->addItem(tr("Unfiltered Popup"));
    modeCombo->setCurrentIndex(1);

    QLabel *caseLabel = new QLabel;
    caseLabel->setText(tr("Case Sensitivity"));
    caseCombo = new QComboBox;
    caseCombo->addItem(tr("Case Insensitive"));
    caseCombo->addItem(tr("Case Sensitive"));
    caseCombo->setCurrentIndex(0);

Les objets « QLabel » modelLabel, modeLabel et caseLabel sont instanciés. De même, les objets « QComboBox » modeCombo et caseCombo sont instanciés et renseignés. Par défaut, le mode de l’objet « completer » est « Filtered Popup » et la distinction entre majuscules et minuscules est désactivée.

    QLabel *separatorLabel = new QLabel;
    separatorLabel->setText(tr("Tree Separator"));

    QLineEdit *separatorLineEdit = new QLineEdit;
    separatorLineEdit->setText(completer->separator());
    connect(separatorLineEdit, &QLineEdit::textChanged,
            completer, &TreeModelCompleter::setSeparator);

    QCheckBox *wrapCheckBox = new QCheckBox;
    wrapCheckBox->setText(tr("Wrap around completions"));
    wrapCheckBox->setChecked(completer->wrapAround());
    connect(wrapCheckBox, &QAbstractButton::clicked, completer, &QCompleter::setWrapAround);

    contentsLabel = new QLabel;
    contentsLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    connect(separatorLineEdit, &QLineEdit::textChanged,
            this, &MainWindow::updateContentsLabel);

    treeView = new QTreeView;
    treeView->setModel(completer->model());
    treeView->header()->hide();
    treeView->expandAll();

    connect(modeCombo, &QComboBox::activated,
            this, &MainWindow::changeMode);
    connect(caseCombo, &QComboBox::activated,
            this, &MainWindow::changeMode);

    lineEdit = new QLineEdit;
    lineEdit->setCompleter(completer);

Nous utilisons une QGridLayout pour placer tous les objets dans le MainWindow.

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(modelLabel, 0, 0); layout->addWidget(treeView, 0, 1);
    layout->addWidget(modeLabel, 1, 0);  layout->addWidget(modeCombo, 1, 1);
    layout->addWidget(caseLabel, 2, 0);  layout->addWidget(caseCombo, 2, 1);
    layout->addWidget(separatorLabel, 3, 0); layout->addWidget(separatorLineEdit, 3, 1);
    layout->addWidget(wrapCheckBox, 4, 0);
    layout->addWidget(contentsLabel, 5, 0, 1, 2);
    layout->addWidget(lineEdit, 6, 0, 1, 2);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    changeCase(caseCombo->currentIndex());
    changeMode(modeCombo->currentIndex());

    setWindowTitle(tr("Tree Model Completer"));
    lineEdit->setFocus();
}

La fonction createMenu() configure les objets QAction requis et les ajoute aux menus « Fichier » et « Aide ». Les signaux triggered() générés par ces actions sont connectés à leurs slots respectifs.

void MainWindow::createMenu()
{
    QAction *exitAction = new QAction(tr("Exit"), this);
    QAction *aboutAct = new QAction(tr("About"), this);
    QAction *aboutQtAct = new QAction(tr("About Qt"), this);

    connect(exitAction, &QAction::triggered, qApp, &QApplication::quit);
    connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
    connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);

    QMenu *fileMenu = menuBar()->addMenu(tr("File"));
    fileMenu->addAction(exitAction);

    QMenu *helpMenu = menuBar()->addMenu(tr("About"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
}

La fonction ` changeMode() ` accepte une ` index ` correspondant au mode de complétion choisi par l’utilisateur et modifie le mode de ` completer` en conséquence.

void MainWindow::changeMode(int index)
{
    QCompleter::CompletionMode mode;
    if (index == 0)
        mode = QCompleter::InlineCompletion;
    else if (index == 1)
        mode = QCompleter::PopupCompletion;
    else
        mode = QCompleter::UnfilteredPopupCompletion;

    completer->setCompletionMode(mode);
}

La fonction ` about() ` fournit une brève description de l'exemple « Tree Model Completer ».

void MainWindow::about()
{
    QMessageBox::about(this, tr("About"), tr("This example demonstrates how "
        "to use a QCompleter with a custom tree model."));
}

La fonction ` changeCase() ` alterne entre les modes ` Case Sensitive ` et ` Case Insensitive `, en fonction de la valeur de ` cs`.

void MainWindow::changeCase(int cs)
{
    completer->setCaseSensitivity(cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
}

main() Fonction

La fonction ` main() ` instancie ` MainWindow ` et appelle la fonction ` show()` pour l'afficher.

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
}

Exemple de projet @ code.qt.io

© 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.