このページでは

ツリーモデル補完機能の例

「ツリーモデル補完機能」の例では、ピリオドを区切り文字として使用し、Child、GrandChild、GrandGrandChild レベルのオブジェクトにアクセスすることで、階層モデルに対して補完機能を提供する方法を示しています。

ツリーモデルの可視化と、コンプリーターのさまざまなオプション

「コンプリータの例」と同様に、補完モードや大文字と小文字の区別に関する選択を可能にするためにQComboBox オブジェクトを用意し、また、行をまたいだ補完を行うためのQCheckBox も用意しています。

リソースファイル

TreeModelCompleter の内容はtreemodel.txt から読み込まれます。このファイルはtreemodelcompleter.qrcリソースファイル内に埋め込まれており、その内容は以下の通りです。

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

TreeModelCompleter クラスの定義

TreeModelCompleter はQCompleter のサブクラスであり、2つのコンストラクタを持っています。1つは引数としてparent を、もう1つはparent およびmodel を引数として受け取ります。

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()` を再実装しています。ツリーモデルに合わせて `QCompleter ` をカスタマイズする方法の詳細については、Handling Tree Models を参照してください。

TreeModelCompleter また、Q_PROPERTY() マクロを使用して宣言される separator プロパティも備えています。この separator には READ および WRITE 属性があり、対応する関数としてseparator() およびsetSeparator() があります。Q_PROPERTY() に関する詳細については、Qt のプロパティシステムを参照してください。

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()関数を使用して上方向に移動し、データを蓄積します。 その後、この関数は、セパレータを使用して異なるレベルのオブジェクトを結合し、QStringList (dataList )を返します。

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 のサブクラスであり、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 つのプライベート関数に加え、QTreeView 、QComboBox 、QLabel 、TreeModelCompleter 、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;
};

MainWindow クラスの実装

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

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 オブジェクトであるmodelLabel 、modeLabel 、およびcaseLabel がインスタンス化されます。また、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);

QGridLayout を使用して、すべてのオブジェクトを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();
}

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() 関数については、「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."));
}

changeCase() 関数は、cs の値に応じて、Case Sensitive モードとCase 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

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