En esta página

Ejemplo de completador de modelo de árbol

El ejemplo de completador de modelo de árbol muestra cómo proporcionar facilidades de completado para un modelo jerárquico, utilizando un punto como separador para acceder a objetos de nivel Hijo, HijoNieto y HijoNietoAbuelo.

Visualización de un modelo de árbol y diversas opciones para el completador

Al igual que en el ejemplo de cumplimentación, proporcionamos objetos QComboBox para permitir la selección del modo de cumplimentación y la distinción entre mayúsculas y minúsculas, así como un QCheckBox para cumplimentaciones envolventes.

El archivo de recursos

El contenido del TreeModelCompleter se lee de treemodel.txt. Este archivo está incrustado en el archivo de recursos treemodelcompleter.qrc, que contiene lo siguiente:

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

Definición de la clase TreeModelCompleter

TreeModelCompleter es una subclase de QCompleter con dos constructores - uno con parent como argumento y otro con parent y model como argumentos.

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 clase reimplementa las funciones protegidas splitPath() y pathFromIndex() para adaptarlas a un modelo de árbol. Para obtener más información sobre la personalización de QCompleter para adaptarse a modelos de árbol, consulte Handling Tree Models.

TreeModelCompleter también tiene una propiedad separator que se declara utilizando la macro Q_PROPERTY(). El separador tiene atributos READ y WRITE y las funciones correspondientes separator() y setSeparator(). Para más información sobre Q_PROPERTY(), consulte Sistema de propiedades de Qt.

Implementación de la Clase TreeModelCompleter

El primer constructor construye un objeto TreeModelCompleter con un padre mientras que el segundo constructor construye un objeto con un padre y un QAbstractItemModel, model.

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

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

La función separator() es una función getter que devuelve la cadena separadora.

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

Como se ha mencionado anteriormente, la función splitPath() se reimplementa porque la implementación por defecto es más adecuada para QFileSystemModel o modelos de lista. Para que QCompleter divida la ruta en una lista de cadenas que coincidan en cada nivel, la dividimos utilizando QString::split() con sep como separador.

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

La función pathFromIndex() devuelve datos para la función completionRole() de un modelo de árbol. Esta función se reimplementa ya que su implementación por defecto es más adecuada para los modelos de lista. Si no hay separador, utilizamos la implementación por defecto de QCompleter, de lo contrario utilizamos la función prepend() para navegar hacia arriba y acumular los datos. La función devuelve entonces un QStringList, dataList, utilizando un separador para unir objetos de diferentes niveles.

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

Definición de la clase MainWindow

La clase MainWindow es una subclase de QMainWindow e implementa cinco ranuras personalizadas: about(), changeCase(), changeMode(), highlight(), y 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);

Además, la clase tiene dos funciones privadas, createMenu() y modelFromFile(), así como instancias privadas de QTreeView, QComboBox, QLabel, TreeModelCompleter y 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;
};

Implementación de la clase MainWindow

El constructor MainWindow crea un objeto MainWindow con un padre e inicializa los objetos completer y lineEdit. La función createMenu() se invoca para configurar los menús "Archivo" y "Ayuda". El modelo de completer se establece en QAbstractItemModel obtenido de modelFromFile(), y la señal highlighted() se conecta a la ranura 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);

Los objetos QLabel modelLabel , modeLabel y caseLabel se instancian. Además, los objetos QComboBox, modeCombo y caseCombo, son instanciados y poblados. Por defecto, el modo de completer es "Filtered Popup" y no se distingue entre mayúsculas y minúsculas.

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

Utilizamos un QGridLayout para colocar todos los objetos en el 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 función createMenu() configura los objetos QAction necesarios y los añade al menú "Archivo" y al menú "Ayuda". Las señales triggered() de estas acciones se conectan a sus respectivas ranuras.

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 función changeMode() acepta un index correspondiente al modo de finalización elegido por el usuario y cambia el modo de completer en consecuencia.

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 función about() proporciona una breve descripción del ejemplo 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 función changeCase() alterna entre los modos Case Sensitive y Case Insensitive, dependiendo del valor de cs.

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

main() Función

La función main() instancia MainWindow e invoca la función show() para mostrarla.

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

Proyecto de ejemplo @ 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.