Auf dieser Seite

Beispiel für die Vervollständigung eines Baummodells

Das Beispiel „Tree Model Completer“ zeigt, wie man Vervollständigungsfunktionen für ein hierarchisches Modell bereitstellt, wobei ein Punkt als Trennzeichen verwendet wird, um auf Objekte der Ebenen „Child“, „GrandChild“ und „GrandGrandChild“ zuzugreifen.

Visualisierung eines Baummodells und verschiedener Optionen für den Kompleter

Ähnlich wie im „Completer“-Beispiel stellen wir die Objekte „ QComboBox “ bereit, um die Auswahl des Vervollständigungsmodus und der Groß-/Kleinschreibung zu ermöglichen, sowie die „ QCheckBox “ für Zeilenumbruch-Vervollständigungen.

Die Ressourcendatei

Der Inhalt des „TreeModelCompleter“ wird aus der Datei „treemodel.txt“ gelesen. Diese Datei ist in die Ressourcendatei „treemodelcompleter.qrc“ eingebettet, die Folgendes enthält:

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

Klassendefinition von `TreeModelCompleter`

Die Klasse „ TreeModelCompleter “ ist eine Unterklasse von „ QCompleter “ mit zwei Konstruktoren – einem mit „ parent “ als Argument und einem weiteren mit „ parent “ und „ model “ als Argumente.

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;
};

Die Klasse implementiert die geschützten Funktionen ` splitPath()` und ` pathFromIndex()` neu, um sie an ein Baummodell anzupassen. Weitere Informationen zur Anpassung von ` QCompleter ` an Baummodelle finden Sie unter Handling Tree Models.

TreeModelCompleter verfügt außerdem über eine „separator“-Eigenschaft, die mithilfe des Makros Q_PROPERTY() deklariert wird. Der Separator verfügt über die Attribute „READ“ und „WRITE“ sowie die entsprechenden Funktionen separator() und setSeparator(). Weitere Informationen zu Q_PROPERTY() finden Sie im Qt-Eigenschaftssystem.

Implementierung der Klasse `TreeModelCompleter`

Der erste Konstruktor erstellt ein ` TreeModelCompleter `-Objekt mit einem übergeordneten Element, während der zweite Konstruktor ein Objekt mit einem übergeordneten Element sowie einem ` QAbstractItemModel` und einem ` model` erstellt.

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

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

Die Funktion ` separator() ` ist eine Getter-Funktion, die die Trennzeichen-Zeichenkette zurückgibt.

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

Wie bereits erwähnt, wird die Funktion ` splitPath() ` neu implementiert, da die Standardimplementierung eher für ` QFileSystemModel `- oder Listenmodelle geeignet ist. Damit ` QCompleter ` den Pfad in eine Liste von Zeichenfolgen aufteilen kann, die auf jeder Ebene übereinstimmen, teilen wir ihn mithilfe von ` QString::split()` mit ` sep ` als Trennzeichen auf.

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

Die Funktion „ pathFromIndex() “ gibt Daten für die „completionRole()“ eines Baummodells zurück. Diese Funktion wird neu implementiert, da ihre Standardimplementierung besser für Listenmodelle geeignet ist. Wenn kein Trennzeichen vorhanden ist, verwenden wir die Standardimplementierung von „ QCompleter “; andernfalls nutzen wir die Funktion „ prepend()“, um nach oben zu navigieren und die Daten zu sammeln. Die Funktion gibt dann ein ` QStringList` (` dataList`) zurück, wobei ein Trennzeichen verwendet wird, um Objekte verschiedener Ebenen zu verbinden.

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);
}

Definition der Klasse „MainWindow“

Die Klasse „ MainWindow “ ist eine Unterklasse von „ QMainWindow “ und implementiert fünf benutzerdefinierte Slots: „ about() “, „ changeCase() “, „ changeMode() “, „ highlight() “ und „ 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);

Darüber hinaus verfügt die Klasse über zwei private Funktionen, „ createMenu() “ und „ modelFromFile() “, sowie über private Instanzen von „ QTreeView “, „ QComboBox “, „ QLabel “, „ TreeModelCompleter “ und „ 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;
};

Implementierung der MainWindow-Klasse

Der Konstruktor von ` MainWindow` erstellt ein ` MainWindow `-Objekt mit einem übergeordneten Objekt und initialisiert die ` completer ` und ` lineEdit`. Die Funktion ` createMenu() ` wird aufgerufen, um das „Datei“-Menü und das „Hilfe“-Menü einzurichten. Das Modell von ` completer` wird auf das von ` modelFromFile()` bezogene ` QAbstractItemModel ` gesetzt, und das Signal ` highlighted()` wird mit dem Slot ` highlight() ` von ` MainWindow` verbunden.

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);

Die „ QLabel “-Objekte modelLabel, modeLabel und caseLabel werden instanziiert. Außerdem werden die „ QComboBox “-Objekte modeCombo und caseCombo instanziiert und mit Daten gefüllt. Standardmäßig ist der Modus des „ completer “ auf „Filtered Popup“ eingestellt und die Groß-/Kleinschreibung wird nicht berücksichtigt.

    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);

Wir verwenden ein „ QGridLayout “, um alle Objekte in das „ MainWindow “ einzufügen.

    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();
}

Die Funktion „ createMenu() “ richtet die erforderlichen „ QAction “-Objekte ein und fügt sie dem Menü „Datei“ sowie dem Menü „Hilfe“ hinzu. Die Signale „ triggered()“ dieser Aktionen werden mit den entsprechenden Slots verbunden.

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);
}

Die Funktion ` changeMode() ` akzeptiert einen ` index `, der der vom Benutzer gewählten Vervollständigungsart entspricht, und ändert den Modus von ` completer` entsprechend.

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);
}

Die Funktion „ about() “ liefert eine kurze Beschreibung zum Beispiel „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."));
}

Die Funktion „ changeCase() “ wechselt je nach dem Wert von „ cs “ zwischen den Modi „ Case Sensitive “ und „ Case Insensitive “.

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

main() Funktion

Die Funktion „ main() “ instanziiert „ MainWindow “ und ruft die Funktion „ show()“ auf, um es anzuzeigen.

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

Beispielprojekt @ 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.