テキストファインダー

QUiLoader を使って .ui ファイルを動的にロードする。

TextFinder の例では、Qt UI Toolsライブラリの一部であるQUiLoader クラスを使って、.ui ファイルを動的に読み込んでセットアップする方法を示しています。

このプログラムでは、ユーザーがテキストの内容から特定の単語を検索することができます。ユーザーインターフェースの視覚的な要素とレイアウトは、プログラムのリソースから実行時にロードされます。

リソース・ファイルのセットアップ

この例に必要なリソースは以下の通りです:

  • textfinder.ui -Qt Widgets Designerで作成されたユーザーインターフェイスファイル。
  • input.txt - に表示されるテキストを含むテキストファイル。QTextEdit

textfinder.ui には、テキスト・ファインダーに必要な オブジェクトがすべて含まれています。 はユーザー入力に、 は の内容を表示するために、 は "Keyword" というテキストを表示するために、 は ボタンに使われます。すべてのウィジェットには、 'が割り当てられています。これらはコード内でウィジェットを識別するために使用されます。QWidget QLineEdit QTextEdit input.txt QLabel QPushButton Find objectName

下のスクリーンショットは、Qt Widgets Designerで取得したプレビューです。

この例では、textfinder.qrc ファイルをインクルードすることで、両方のリソースをアプリケーションの実行ファイルに保存しています。また、ファイルシステムから実行時に読み込むこともできますし、外部のバイナリリソース.rcc ファイルから読み込むこともできます。リソースファイルの詳細については、Qt Resource Systemを参照してください。

textfinder.qrc ファイルには、リソースとして含めるべきすべてのファイルがリストされています:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>forms/textfinder.ui</file>
    <file>forms/input.txt</file>
</qresource>
</RCC>

実行時にフォームを生成するために、サンプルはQt Ui Toolsライブラリとリンクされます。これはtextfinder.pro ファイルで行われます:

QT += widgets uitools

HEADERS = textfinder.h
SOURCES = textfinder.cpp main.cpp
RESOURCES = textfinder.qrc

TextFinder クラス定義

TextFinder クラスはメイン・ユーザー・インターフェースを含んでいます。QPushButtonQTextEditQLineEdit の各要素へのポインタを宣言しています。ユーザー・インターフェースのQLabel は、コードからアクセスする必要がないので、ここでは宣言しません。

class TextFinder : public QWidget
{
    Q_OBJECT

public:
    explicit TextFinder(QWidget *parent = nullptr);

private slots:
    void on_findButton_clicked();

private:
    QPushButton *ui_findButton;
    QTextEdit *ui_textEdit;
    QLineEdit *ui_lineEdit;
};

スロットon_findButton_clicked() は、uic で要求されるAutomatic Connection の命名規則に従って命名されたスロットです。

リソースのロード

QFile 、実行時にプログラム・リソースからデータをロードします。このためのコードは、textfinder.cpp の上にある2つのメソッド、loadUiFileloadTextFile にあります。

loadUiFile 関数は、Qt Widgets Designer で作成したユーザー・インターフェース・ファイルをロードします。まず、textfinder.ui ファイルの内容がリソース・システムからロードされます。次に、QUiLoader インスタンスが作成され、QUiLoader::load() 関数が呼び出されます。第1引数にはオープン・ファイル、第2引数には親として設定するウィジェットのポインタが指定されます。作成されたQWidget が返される。

static QWidget *loadUiFile(QWidget *parent)
{
    QFile file(u":/forms/textfinder.ui"_s);
    file.open(QIODevice::ReadOnly);

    QUiLoader loader;
    return loader.load(&file, parent);
}

同様に、loadTextFile 関数はinput.txt をリソースからロードする。データはQTextStream を使ってQTextStream::readAll() 関数でQString に読み込まれる。QTextStream 、デフォルトでは現在のシステムロケールを使用するため、明示的にエンコーディングをUTF-8に設定しています。最後に、読み込まれたテキストが返されます。

static QString loadTextFile()
{
    QFile inputFile(u":/forms/input.txt"_s);
    inputFile.open(QIODevice::ReadOnly);
    QTextStream in(&inputFile);
    return in.readAll();
}

TextFinder クラスの実装

TextFinder クラスのコンストラクタは、子ウィジェットを直接インスタンス化しません。代わりにloadUiFile() 関数を呼び出し、QObject::findChild() を使って、作成されたQWidgetをオブジェクト名で探します。

TextFinder::TextFinder(QWidget *parent)
    : QWidget(parent)
{
    QWidget *formWidget = loadUiFile(this);

    ui_findButton = findChild<QPushButton*>("findButton");
    ui_textEdit = findChild<QTextEdit*>("textEdit");
    ui_lineEdit = findChild<QLineEdit*>("lineEdit");

次に、QMetaObject::connectSlotsByName() を使用して、on_findButton_clicked() スロットを自動的に呼び出せるようにします。

    QMetaObject::connectSlotsByName(this);

loadTextFile 関数を呼び出して、QTextEdit に表示するテキストを取得します。

    ui_textEdit->setText(loadTextFile());

これで、formWidget の動的にロードされるユーザーインターフェイスが適切にセットアップされました。次に、QVBoxLayout を使ってformWidget を埋め込みます。

    auto *layout = new QVBoxLayout(this);
    layout->addWidget(formWidget);

コンストラクタの最後に、ウィンドウのタイトルを設定します。

    setWindowTitle(tr("Text Finder"));
}

on_findButton_clicked() 関数はui_findButtonclicked() シグナルに接続されるスロットです。searchStringui_lineEdit から抽出され、documentui_textEdit から抽出される。空のsearchString があれば、QMessageBox が使用され、ユーザーに単語の入力を要求する。そうでない場合は、ui_textEdit の単語を走査し、searchString のすべての出現箇所を強調表示します。2 つの QTextCursor オブジェクトが使用されます:1つはline の単語を走査するため、もう1つは編集ブロックを追跡するためです。

void TextFinder::on_findButton_clicked()
{
    QString searchString = ui_lineEdit->text();
    QTextDocument *document = ui_textEdit->document();

    bool found = false;

    // undo previous change (if any)
    document->undo();

    if (searchString.isEmpty()) {
        QMessageBox::information(this, tr("Empty Search Field"),
                                 tr("The search field is empty. "
                                    "Please enter a word and click Find."));
    } else {
        QTextCursor highlightCursor(document);
        QTextCursor cursor(document);

        cursor.beginEditBlock();

        QTextCharFormat plainFormat(highlightCursor.charFormat());
        QTextCharFormat colorFormat = plainFormat;
        colorFormat.setForeground(Qt::red);

        while (!highlightCursor.isNull() && !highlightCursor.atEnd()) {
            highlightCursor = document->find(searchString, highlightCursor,
                                             QTextDocument::FindWholeWords);

            if (!highlightCursor.isNull()) {
                found = true;
                highlightCursor.movePosition(QTextCursor::WordRight,
                                             QTextCursor::KeepAnchor);
                highlightCursor.mergeCharFormat(colorFormat);
            }
        }

        cursor.endEditBlock();

searchStringui_textEdit のコンテンツ内で見つかったかどうかを示すために、found フラグが使用されます。 見つからなかった場合は、QMessageBox が使用されてユーザーに通知されます。

        if (found == false) {
            QMessageBox::information(this, tr("Word Not Found"),
                                     tr("Sorry, the word cannot be found."));
        }
    }
}

main() 関数

main() 関数はTextFinder をインスタンス化して表示します。

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    TextFinder textFinder;
    textFinder.show();

    return app.exec();
}

アプリケーションにフォームを含めるには様々なアプローチがあります。QUILoaderの使用はその1つに過ぎません。利用可能な他のアプローチの詳細については、「アプリケーションでデザイナーUIファイルを使用する」を参照してください。

サンプルプロジェクト @ code.qt.io

Calculator Builderも参照して ください。

©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は各所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。