Tree Model Completer Beispiel

Das Tree Model Completer Beispiel zeigt, wie man Vervollständigungsmöglichkeiten für ein hierarchisches Modell bereitstellt, indem man einen Punkt als Trennzeichen verwendet, um auf Objekte der Ebenen Child, GrandChild und GrandGrandChild zuzugreifen.

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

Die Ressourcendatei

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

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

TreeModelCompleter Klassendefinition

Die Klasse TreeModelCompleter ist eine Unterklasse von QCompleter mit zwei Konstruktoren - einem mit parent als Argument und einem weiteren mit parent und model als Argument.

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 reimplementiert die geschützten Funktionen splitPath() und pathFromIndex(), um sie an ein Baummodell anzupassen. Weitere Informationen zur Anpassung von QCompleter an Baummodelle finden Sie unter Handling Tree Models.

TreeModelCompleter Die Klasse hat auch eine Separator-Eigenschaft, die mit dem Makro Q_PROPERTY() deklariert wird. Das Trennzeichen hat die Attribute READ und WRITE und die entsprechenden Funktionen separator() und setSeparator(). Weitere Informationen zu Q_PROPERTY() finden Sie in Qt's Property System.

TreeModelCompleter Klasse Implementierung

Der erste Konstruktor konstruiert ein TreeModelCompleter Objekt mit einem Parent, während der zweite Konstruktor ein Objekt mit einem Parent und einem QAbstractItemModel, model konstruiert.

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

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

Die Funktion separator() ist eine Getter-Funktion, die die Trennzeichenfolge zurückgibt.

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

Wie bereits erwähnt, wird die Funktion splitPath() neu implementiert, da die Standardimplementierung besser für QFileSystemModel oder Listenmodelle geeignet ist. Damit QCompleter den Pfad in eine Liste von Strings aufteilen kann, die auf jeder Ebene übereinstimmen, teilen wir ihn mit QString::split() und 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() für ein Baummodell zurück. Diese Funktion wird neu implementiert, da ihre Standardimplementierung besser für Listenmodelle geeignet ist. Wenn kein Trennzeichen vorhanden ist, wird die Standardimplementierung von QCompleter verwendet, andernfalls wird die Funktion prepend() verwendet, 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 Klasse MainWindow

Der Konstruktor von MainWindow erstellt ein MainWindow Objekt mit einem Elternteil und initialisiert completer und lineEdit. Die Funktion createMenu() wird aufgerufen, um das Menü "Datei" und das Menü "Hilfe" einzurichten. Das Modell von completer wird auf das von modelFromFile() erhaltene QAbstractItemModel gesetzt, und das Signal highlighted() wird mit dem Steckplatz 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. Auch die Objekte QComboBox, modeCombo und caseCombo, werden instanziiert und mit Daten gefüllt. Standardmäßig ist der Modus von completer"Gefiltertes Popup" und die Groß- und 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 MainWindow zu platzieren.

    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" und dem Menü "Hilfe" hinzu. Die triggered()-Signale dieser Aktionen werden mit ihren jeweiligen 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() nimmt ein index entgegen, das dem vom Benutzer gewählten Abschlussmodus 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 des Tree Model Completer-Beispiels.

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 zwischen den Modi Case Sensitive und Case Insensitive, je nach dem Wert von cs.

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 sie anzuzeigen.

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

Beispielprojekt @ code.qt.io

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