QT之巧用对象充当信号接收者

发布于:2025-05-24 ⋅ 阅读:(19) ⋅ 点赞:(0)

备注:以下仅为演示不代表合理性,适合简单任务,逻辑简单、临时使用,可保持代码简洁,对于复杂的任务应创建一个专门的类来管理信号和线程池任务.

FileScanner类继承QObject和QRunnable,扫描指定目录下的文件获取文件列表,逐个发出fileFound信号;

FileHasher:继承QObject和QRunnable,计算文件的SHA1值,发出hashResult信号;

1、使用新建临时对象 

#include <QCoreApplication>
#include <QThreadPool>
#include "global_threadpool_example.h"

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

    // 创建协调对象,处理信号
    QObject coordinator;

    // 启动文件扫描任务
    FileScanner *scanner = new FileScanner("/path/to/your/directory"); // 替换为实际目录
    QObject::connect(scanner, &FileScanner::fileFound, &coordinator, [&coordinator](const QString &filePath) {
        // 为每个找到的文件启动SHA1计算任务
        FileHasher *hasher = new FileHasher(filePath);
        QObject::connect(hasher, &FileHasher::hashResult, &coordinator, [](const QString &filePath, const QString &hash) {
            qDebug() << "File:" << filePath << "SHA1:" << hash;
        });
        QThreadPool::globalInstance()->start(hasher);
    });
    QObject::connect(scanner, &FileScanner::finished, &coordinator, []() {
        qDebug() << "Scanning finished.";
        // 可选:等待所有任务完成
        QThreadPool::globalInstance()->waitForDone();
        qDebug() << "All tasks completed.";
    });

    // 提交扫描任务到全局线程池
    QThreadPool::globalInstance()->start(scanner);

    return app.exec();
}
  • Qt 的信号槽机制要求信号的接收者是一个 QObject 或其派生类的实例。coordinator 是一个 QObject 实例,用于连接 FileScanner 和 FileHasher 发出的信号(如 fileFound 和 hashResult)。
  • 它充当信号的“中转站”,将任务的异步结果(例如找到的文件路径或计算的 SHA1 值)传递到处理逻辑中。
  • 它可以避免在 main 函数中创建额外的类或全局对象,保持代码简洁。

  • coordinator 是 main 函数的局部变量,其生命周期持续到程序退出。这足以处理所有信号,因为线程池任务的信号在事件循环中处理。

2、使用QCoreApplication对象

#include <QCoreApplication>
#include <QThreadPool>
#include "global_threadpool_example.h"

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

    // 启动文件扫描任务
    FileScanner *scanner = new FileScanner("/path/to/your/directory"); // 替换为实际目录
    QObject::connect(scanner, &FileScanner::fileFound, &app, [&app](const QString &filePath) {
        FileHasher *hasher = new FileHasher(filePath);
        QObject::connect(hasher, &FileHasher::hashResult, &app, [](const QString &filePath, const QString &hash) {
            qDebug() << "File:" << filePath << "SHA1:" << hash;
        });
        QThreadPool::globalInstance()->start(hasher);
    });
    QObject::connect(scanner, &FileScanner::finished, &app, []() {
        qDebug() << "Scanning finished.";
        QThreadPool::globalInstance()->waitForDone();
        qDebug() << "All tasks completed.";
    });

    // 提交扫描任务到全局线程池
    QThreadPool::globalInstance()->start(scanner);

    return app.exec();
}

QCoreApplication 是 Qt 应用程序的主对象,无需额外创建 QObject,app存在于整个程序生命周期,也可以直接用作信号槽连接的接收者,也适合信号槽逻辑简单、临时使用的场景。

缺点:语义上不够清晰,因为 QCoreApplication 的主要职责是管理应用程序,而不是任务协调,如果程序中有多个模块使用 app 处理信号,可能会导致信号槽逻辑混杂,这种方式并不推荐。

3、使用 lambda 表达式

#include <QCoreApplication>
#include <QThreadPool>
#include "global_threadpool_example.h"

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

    // 启动文件扫描任务
    FileScanner *scanner = new FileScanner("/path/to/your/directory"); // 替换为实际目录
    QObject::connect(scanner, &FileScanner::fileFound, [=](const QString &filePath) {
        FileHasher *hasher = new FileHasher(filePath);
        QObject::connect(hasher, &FileHasher::hashResult, [](const QString &filePath, const QString &hash) {
            qDebug() << "File:" << filePath << "SHA1:" << hash;
        });
        QThreadPool::globalInstance()->start(hasher);
    });
    QObject::connect(scanner, &FileScanner::finished, []() {
        qDebug() << "Scanning finished.";
        QThreadPool::globalInstance()->waitForDone();
        qDebug() << "All tasks completed.";
    });

    // 提交扫描任务到全局线程池
    QThreadPool::globalInstance()->start(scanner);

    return app.exec();
}

Qt 允许在信号连接中使用 lambda 表达式直接处理逻辑,无需显式的接收者对象。这种方式将信号处理逻辑直接嵌入 lambda 函数中。适合信号槽逻辑简单、临时使用的场景。

  • 代码更简洁,无需创建额外的 QObject,逻辑集中在 lambda 函数中,易于理解。
  • lambda 表达式无法像 QObject 那样方便地管理多个信号槽连接(例如断开连接),而且如果 lambda 中捕获了变量(如 [=]),特别需要注意捕获变量的生命周期。

4、使用静态函数或全局函数处理信号

#include <QCoreApplication>
#include <QThreadPool>
#include "global_threadpool_example.h"

// 静态函数处理信号
static void handleFileFound(const QString &filePath) {
    FileHasher *hasher = new FileHasher(filePath);
    QObject::connect(hasher, &FileHasher::hashResult, [](const QString &filePath, const QString &hash) {
        qDebug() << "File:" << filePath << "SHA1:" << hash;
    });
    QThreadPool::globalInstance()->start(hasher);
}

static void handleFinished() {
    qDebug() << "Scanning finished.";
    QThreadPool::globalInstance()->waitForDone();
    qDebug() << "All tasks completed.";
}

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

    // 启动文件扫描任务
    FileScanner *scanner = new FileScanner("/path/to/your/directory"); // 替换为实际目录
    QObject::connect(scanner, &FileScanner::fileFound, handleFileFound);
    QObject::connect(scanner, &FileScanner::finished, handleFinished);

    // 提交扫描任务到全局线程池
    QThreadPool::globalInstance()->start(scanner);

    return app.exec();
}

 定义静态函数 handleFileFound 和 handleFinished,直接连接到信号,不需要 QObject 接收者。但这种方式,静态函数无法方便地存储状态(如任务列表、结果收集),不易扩展,维护性较差,仅适合信号处理逻辑非常简单的情况。


网站公告

今日签到

点亮在社区的每一天
去签到