このページでは

カスタムコンプリーターの例

「カスタムコンプリーター」の例では、モデルから提供されるデータに基づいて、入力ウィジェットに文字列補完機能を実装する方法を示しています。コンプリーターは、ユーザーが入力した最初の3文字に基づいて候補となる単語を表示し、ユーザーが選択した単語は、QTextCursor を使用してTextEdit に挿入されます。

オートコンプリート機能を備えたテキストエディタ

リソースファイルの設定

「カスタムコンプリーター」の例では、QCompleter が単語の補完を行うのに役立つ単語リストを含むリソースファイル「wordlist.txt」が必要です。このファイルには、以下の内容が記述されています:

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

TextEdit クラスの定義

TextEdit クラスは、QTextEdit のサブクラスであり、カスタムinsertCompletion() スロットを持ち、keyPressEvent()およびfocusInEvent()関数を再実装しています。TextEdit には、プライベート関数textUnderCursor() と、QCompleter のプライベートインスタンスc も含まれています。

class TextEdit : public QTextEdit
{
    Q_OBJECT

public:
    TextEdit(QWidget *parent = nullptr);
    ~TextEdit();

    void setCompleter(QCompleter *c);
    QCompleter *completer() const;

protected:
    void keyPressEvent(QKeyEvent *e) override;
    void focusInEvent(QFocusEvent *e) override;

private slots:
    void insertCompletion(const QString &completion);

private:
    QString textUnderCursor() const;

private:
    QCompleter *c = nullptr;
};

TextEditクラスの実装

TextEdit のコンストラクタは、親を持つTextEdit を構築し、c を初期化します。コンプリーターの使用方法に関する指示は、setPlainText()関数を使用して、TextEdit オブジェクト上に表示されます。

TextEdit::TextEdit(QWidget *parent)
    : QTextEdit(parent)
{
    setPlainText(tr("This TextEdit provides autocompletions for words that have more than"
                    " 3 characters. You can trigger autocompletion using ") +
                    QKeySequence("Ctrl+E").toString(QKeySequence::NativeText));
}

さらに、TextEdit にはデフォルトのデストラクタも含まれています:

TextEdit::~TextEdit()
{
}

setCompleter() 関数はcompleter を受け取り、そのセットアップを行います。if (c) を使用して、c が初期化されているかどうかを確認します。初期化されている場合、QObject::disconnect()関数が呼び出され、スロットからのシグナルが切断されます。これは、以前のコンプリーターオブジェクトがスロットに接続されたままになっていないことを保証するためです。

void TextEdit::setCompleter(QCompleter *completer)
{
    if (c)
        c->disconnect(this);

    c = completer;

    if (!c)
        return;

    c->setWidget(this);
    c->setCompletionMode(QCompleter::PopupCompletion);
    c->setCaseSensitivity(Qt::CaseInsensitive);
    QObject::connect(c, QOverload<const QString &>::of(&QCompleter::activated),
                     this, &TextEdit::insertCompletion);
}

次に、completer を使用してc をインスタンス化し、これをTextEdit のウィジェットとして設定します。さらに、補完モードと大文字小文字の区別設定を行い、activated() シグナルをinsertCompletion() スロットに接続します。

completer() 関数は、c を返すゲッター関数です。

QCompleter *TextEdit::completer() const
{
    return c;
}

コンプリーターは、wordlist.txtの内容に基づいて利用可能な候補を表示しますが、ユーザーが選択した単語に応じて、欠落している文字を埋めるのはテキストカーソルの役割です。

ユーザーが「ACT」と入力し、コンプリーターが提案した「ACTUAL」を受け入れたと仮定します。すると、コンプリーターのactivated()シグナルによって、completion 文字列がinsertCompletion() に送信されます。

insertCompletion() 関数は、QTextCursor オブジェクトであるtc を使用して単語の補完を行う役割を担っています。この関数は、tc を使用して追加の文字を挿入し単語を補完する前に、コンプリーターのウィジェットがTextEdit であることを確認するための検証を行います。

void TextEdit::insertCompletion(const QString &completion)
{
    if (c->widget() != this)
        return;
    QTextCursor tc = textCursor();
    int extra = completion.length() - c->completionPrefix().length();
    tc.movePosition(QTextCursor::Left);
    tc.movePosition(QTextCursor::EndOfWord);
    tc.insertText(completion.right(extra));
    setTextCursor(tc);
}

以下の図はこのプロセスを示しています:

ユーザーが「ACT」と入力した際に、「ACTUAL」という補完候補を表示する

completion.length() = 6

c->completionPrefix().length()=3

これら2つの値の差はextra であり、3となります。これは、右から3文字目である「U」、「A」、「L」が、tc によって挿入されることを意味します。

textUnderCursor() 関数は、QTextCursor であるtc を使用して、カーソルの位置にある単語を選択し、それを返します。

QString TextEdit::textUnderCursor() const
{
    QTextCursor tc = textCursor();
    tc.select(QTextCursor::WordUnderCursor);
    return tc.selectedText();
}

TextEdit クラスは、focusInEvent()関数を再実装しています。これは、ウィジェットのキーボードフォーカスイベントを受け取るために使用されるイベントハンドラです。

void TextEdit::focusInEvent(QFocusEvent *e)
{
    if (c)
        c->setWidget(this);
    QTextEdit::focusInEvent(e);
}

keyPressEvent() は、Qt::Key_Enter 、Qt::Key_Return 、Qt::Key_Escape 、Qt::Key_Tab 、Qt::Key_Backtab などのキーイベントを無視するように再実装されており、これによりコンプリータがこれらのイベントを処理できるようになっています。

コンプリーターがアクティブな場合、ショートカット「Ctrl+E」を処理することはできません。

void TextEdit::keyPressEvent(QKeyEvent *e)
{
    if (c && c->popup()->isVisible()) {
        // The following keys are forwarded by the completer to the widget
       switch (e->key()) {
       case Qt::Key_Enter:
       case Qt::Key_Return:
       case Qt::Key_Escape:
       case Qt::Key_Tab:
       case Qt::Key_Backtab:
            e->ignore();
            return; // let the completer do default behavior
       default:
           break;
       }
    }

    const bool isShortcut = (e->modifiers().testFlag(Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
    if (!c || !isShortcut) // do not process the shortcut when we have a completer
        QTextEdit::keyPressEvent(e);

また、コンプリーターに反応させたくないその他の修飾キーやショートカットについても処理を行います。

    const bool ctrlOrShift = e->modifiers().testFlag(Qt::ControlModifier) ||
                             e->modifiers().testFlag(Qt::ShiftModifier);
    if (!c || (ctrlOrShift && e->text().isEmpty()))
        return;

    static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
    const bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
    QString completionPrefix = textUnderCursor();

    if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 3
                      || eow.contains(e->text().right(1)))) {
        c->popup()->hide();
        return;
    }

    if (completionPrefix != c->completionPrefix()) {
        c->setCompletionPrefix(completionPrefix);
        c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
    }
    QRect cr = cursorRect();
    cr.setWidth(c->popup()->sizeHintForColumn(0)
                + c->popup()->verticalScrollBar()->sizeHint().width());
    c->complete(cr); // popup it up!
}

最後に、コンプリータをポップアップ表示します。

MainWindow クラスの定義

MainWindow クラスはQMainWindow のサブクラスであり、プライベートスロットabout() を実装しています。また、このクラスにはcreateMenu() およびmodelFromFile() という 2 つのプライベート関数と、QCompleter およびTextEdit のプライベートインスタンスがあります。

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);

private slots:
    void about();

private:
    void createMenu();
    QAbstractItemModel *modelFromFile(const QString& fileName);

    QCompleter *completer = nullptr;
    TextEdit *completingTextEdit;
};

MainWindow クラスの実装

コンストラクタは、親を持つMainWindow を生成し、completer を初期化します。また、TextEdit をインスタンス化し、そのコンプリーターを設定します。modelFromFile() から取得したQStringListModel を使用して、completer にデータを格納します。MainWindow の中央ウィジェットはTextEdit に設定され、そのサイズは500×300に設定されます。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    createMenu();

    completingTextEdit = new TextEdit;
    completer = new QCompleter(this);
    completer->setModel(modelFromFile(":/resources/wordlist.txt"));
    completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
    completer->setCaseSensitivity(Qt::CaseInsensitive);
    completer->setWrapAround(false);
    completingTextEdit->setCompleter(completer);

    setCentralWidget(completingTextEdit);
    resize(500, 300);
    setWindowTitle(tr("Completer"));
}

createMenu() 関数は、「File」および「Help」メニューに必要なQAction オブジェクトを作成し、それらのtriggered()シグナルを、それぞれquit() 、about() 、およびaboutQt() のスロットに接続します。

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

modelFromFile() 関数はfileName を受け取り、このファイルの内容をQStringListModel に抽出しようと試みます。QStringList やwords にデータを入力する際にはQt::WaitCursor を表示し、処理が完了したらマウスカーソルを元に戻します。

QAbstractItemModel *MainWindow::modelFromFile(const QString& fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly))
        return new QStringListModel(completer);

#ifndef QT_NO_CURSOR
    QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
#endif
    QStringList words;

    while (!file.atEnd()) {
        QByteArray line = file.readLine();
        if (!line.isEmpty())
            words << QString::fromUtf8(line.trimmed());
    }

#ifndef QT_NO_CURSOR
    QGuiApplication::restoreOverrideCursor();
#endif
    return new QStringListModel(words, completer);
}

about() 関数は、Custom Completerのサンプルに関する簡単な説明を提供します。

void MainWindow::about()
{
    QMessageBox::about(this, tr("About"), tr("This example demonstrates the "
        "different features of the QCompleter class."));
}

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.