ツリーモデル補完の例

ピリオドを区切り文字として使用し、Child、GrandChild、GrandGrandChild レベルのオブジェクトにアクセスします。

Completer Example と同様に、QComboBox オブジェクトを提供し、補完モードと大文字小文字の区別、およびラップ補完のためのQCheckBox を選択できるようにしています。

リソースファイル

TreeModelCompleter の内容はtreemodel.txt から読み込まれます。このファイルはtreemodelcompleter.qrcリソースファイル内に埋め込まれ、以下の内容を含んでいます:

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

TreeModelCompleter クラス定義

TreeModelCompleterQCompleter のサブクラスで、parent を引数とするコンストラクタと、parentmodel を引数とするコンストラクタを持ちます。

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

このクラスは、splitPath() とpathFromIndex() という protected 関数を、ツリー・モデルに合うように再実装しています。ツリー・モデルに合わせてQCompleter をカスタマイズする方法については、Handling Tree Models を参照してください。

TreeModelCompleter また、 () マクロを使用して宣言される separator プロパティもあります。separator には READ 属性と WRITE 属性があり、対応する関数は と です。 () の詳細については、Q_PROPERTY separator() setSeparator() Q_PROPERTYQt の Property System を参照してください。

TreeModelCompleter クラスの実装

最初のコンストラクタは、親を持つTreeModelCompleter オブジェクトを構築し、2 番目のコンストラクタは、親とQAbstractItemModel,model を持つオブジェクトを構築します。

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

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

separator() 関数はセパレーター文字列を返すゲッター関数です。

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

前述のように、splitPath() 関数は再実装されています。これは、デフォルトの実装がQFileSystemModel やリスト・モデルに適しているためです。QCompleter 、パスを各レベルでマッチする文字列のリストに分割するために、sep をセパレーターとして、QString::split() を使って分割しています。

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

pathFromIndex() 関数は、ツリーモデルの completionRole() のデータを返します。この関数は、デフォルトの実装がリストモデルに適しているため、再実装されています。セパレータがない場合は、QCompleter'のデフォルト実装を使用します。そうでない場合は、prepend() 関数を使用して上方に移動し、データを蓄積します。この関数は、セパレータを使用して異なるレベルのオブジェクトを結合し、QStringListdataList を返します。

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

MainWindowクラスの定義

MainWindow クラスはQMainWindow のサブクラスで、5つのカスタム・スロットを実装しています:about() changeCase()changeMode()highlight()updateContentsLabel() の5つのカスタム・スロットを実装しています。

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

さらに、このクラスはcreateMenu()modelFromFile() の2つのプライベート関数と、QTreeViewQComboBoxQLabelTreeModelCompleterQLineEdit のプライベート・インスタンスを持っています。

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

MainWindow クラスの実装

MainWindow のコンストラクタは、親を持つMainWindow オブジェクトを作成し、completerlineEdit を初期化します。createMenu() 関数が呼び出され、"File" メニューと "Help" メニューが設定されます。completer のモデルはmodelFromFile() から取得したQAbstractItemModel に設定され、highlighted() シグナルはMainWindowhighlight() スロットに接続される。

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

QLabel オブジェクトmodelLabelmodeLabelcaseLabel がインスタンス化される。また、QComboBox オブジェクト、modeCombo およびcaseCombo がインスタンス化され、入力される。デフォルトでは、completer のモードは "Filtered Popup "で、大文字と小文字は区別されません。

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

MainWindow にすべてのオブジェクトを配置するためにQGridLayout を使用します。

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

createMenu() 関数は必要なQAction オブジェクトを設定し、「ファイル」メニューと「ヘルプ」メニューに追加します。これらのアクションからのtriggered() シグナルは、それぞれのスロットに接続されます。

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

changeMode() 関数は、ユーザーが選択した完了モードに対応するindex を受け取り、それに応じてcompleter のモードを変更します。

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

about() 関数は、ツリーモデルコンプリターの例に関する簡単な説明を提供する。

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

changeCase() 関数は、cs の値に応じて、Case SensitiveCase Insensitive のモードを交互に切り替えます。

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

main() 関数

main() 関数は、MainWindow をインスタンス化し、show() 関数を呼び出して表示します。

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

プロジェクト例 @ 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.