文本查找

使用 QUiLoader 动态加载 .ui 文件。

TextFinder 示例展示了如何使用 Qt UI Tools 库中的 QUiLoader 类动态加载和设置 .ui 文件。

程序允许用户在文本内容中查找特定的词汇。用户界面的视觉元素和布局在运行时从程序资源加载。

资源文件的设置

示例所需的资源包括

  • textfinder.ui - 在 Qt Designer 中创建的用户界面文件
  • input.txt - 包含要显示在 QTextEdit 中的文本的文本文件

textfinder.ui 包含 Text Finder 所需的所有 QWidget 对象。一个 QLineEdit 用于用户输入,一个 QTextEdit 用于显示 input.txt 的内容,一个 QLabel 用于显示文本 "关键字",一个 QPushButton 用于 查找 按钮。注意,所有小部件都指定了有意义的 objectName。这些在代码中用于识别它们。

以下截图显示了在 Qt Designer 中获得的预览。

在这个示例中,我们通过包含 textfinder.qrc 文件将资源存储在应用程序的可执行文件中。作为备选方案,这些文件也可以在运行时从文件系统或外部二进制资源 .rcc 文件加载。有关资源文件的更多信息,请参阅 The 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 需要的 自动连接 命名约定命名的槽。

加载资源

我们使用QFile在运行时从程序资源加载数据。这段代码在textfinder.cpp的顶部两个方法中:loadUiFileloadTextFile

loadUiFile函数加载先在Qt Designer中创建的用户界面文件。首先,从资源系统加载textfinder.ui文件的内容。然后创建一个QUiLoader实例,并调用QUiLoader::load()函数,第一个参数是打开的文件,第二个参数是要设置为父级的指向该小部件的指针。返回创建的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中。我们显式设置编码为UTF-8,因为默认QTextStream使用当前系统区域设置。最后,返回加载的文本。

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_findButton's clicked()信号连接的槽。从ui_lineEdit中提取searchString,从ui_textEdit中提取document。如果searchString为空,则使用QMessageBox请求用户输入单词。否则,我们在ui_textEdit中的单词中遍历,并突出显示所有searchString的出现。使用两个QTextCursor对象:一个用于遍历line中的单词,另一个用于跟踪编辑块。

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

使用found标志来指示是否在ui_textEdit的内容中找到了searchString。如果没有找到,则使用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只是其中之一。有关其他方法的更多信息,请参见在您的应用程序中使用Designer UI文件

示例项目 @ code.qt.io

另请参阅 计算器构建器

© 2024 Qt公司有限公司。本文档中包含的贡献文档均为各自所有者的版权。本提供的文档根据自由软件基金会发布的GNU自由文档许可证的第1.3版条款授权使用。GNU自由文档许可证。Qt及其相关标志是Qt公司在芬兰和/或全球其他国家的商标。所有其他商标均为各自所有者的财产。