QT核心模块QtCore功能详细说明,并给出测试代码(四)

目录

一. 核心数据类型 (Core Datatypes)

二. 文件和目录 (File and Directory Handling)

三. 事件系统 (Event System)

QObject

QCoreApplication 

QEventLoop 

QEvent

QTimer

QMetaObject:

运行时类型信息 (RTTI)

信号与槽连接

属性系统

动态方法调用

类型转换

自我检查

四. 多线程和并发 (Multithreading and Concurrency)

五. 国际化和本地化 (Internationalization and Localization)

六. 进程和进程间通信 (Process and Inter-Process Communication - IPC)

七. 插件支持 (Plugin Support)

八. 文本编解码 (Text Codecs)

九. 动态库加载 (Dynamic Library Loading)

十. 全局函数

十一. 其他实用工具


一. 核心数据类型 (Core Datatypes)

请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(一)

二. 文件和目录 (File and Directory Handling)

 请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(二)

三. 事件系统 (Event System)

QObject

  请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(三)

QCoreApplication 

QCoreApplication 是 Qt 应用程序的核心类,负责 管理应用程序的生命周期,并 提供事件循环 (Event Loop)。所有 Qt 程序(无论是 GUI 还是控制台应用)都必须有一个 QCoreApplicationQGuiApplication/QApplication 实例。唯一实例(Singleton)

  • 启动和管理事件循环 (Event Loop): 持续监测过程
    • exec() 方法:启动事件循环
      • 一旦调用 exec(),应用程序就会进入事件循环,开始监听和处理事件。
      • exec() 运行期间,应用程序会保持活动状态,响应各种事件。
    • 事件循环的迭代过程:
      • 等待事件: 事件循环首先会等待新的事件到达。这些事件可能来自操作系统、Qt 内部或其他部分的代码。
      • 获取事件: 当一个或多个事件到达时,事件循环会获取它们。
      • 处理事件: 事件循环会将获取到的事件分发给相应的接收者对象进行处理。
      • 返回: 处理完所有待处理的事件后,事件循环会再次进入等待状态,等待新的事件。
    • 停止事件循环:quit()exit() 方法
      • quit() 方法用于正常地退出事件循环。它会发出 aboutToQuit() 信号,然后将事件循环的退出码设置为 0。
      • exit(int returnCode) 方法也可以用于退出事件循环,并且可以指定一个自定义的退出码。
      • exec() 方法因为调用了 quit()exit() 而结束时,它会返回应用程序的退出码。
  • 应用程序生命周期管理: 控制应用程序
    • 启动 (Startup):
      • 在任何 Qt 应用程序的 main() 函数中,你都需要创建 QCoreApplication(或 QApplication 对于 GUI 程序)的实例。
      • 构造函数会进行一些基本的初始化工作,例如设置应用程序的唯一标识、处理命令行参数等。
    • 初始化 (Initialization):
      • QCoreApplication 会初始化 Qt 的核心功能,例如信号和槽机制、事件系统等。
      • 可以在创建 QCoreApplication 实例之后,但在调用 exec() 之前执行一些应用程序特定的初始化操作。
    • 运行 (Running):
      • 调用 exec() 方法后,应用程序进入事件循环,开始正常运行,响应各种事件。
    • 关闭 (Shutdown):
      • 当调用 quit()exit() 时,事件循环结束。
      • 在事件循环结束之前,QCoreApplication 会发出 aboutToQuit() 信号。
      • main() 函数在 exec() 返回后继续执行,通常会返回 exec() 的返回值作为应用程序的退出码。
  • 处理应用程序级别的信号和槽:【QGuiApplication 或 QApplication】
    • aboutToQuit(): 在事件循环即将结束时发出。这是进行最后清理工作的理想时机。
    • applicationStateChanged(): 当应用程序的状态发生改变时发出。
  • 管理应用程序设置: 允许设置和获取应用程序名称、组织名称、组织域等全局信息。
    • setApplicationName(const QString &name) / applicationName(): 设置或获取应用程序的名称。
    • setApplicationVersion(const QString &version) / applicationVersion(): 设置或获取应用程序的版本号。
    • setOrganizationName(const QString &name) / organizationName(): 设置或获取组织的名称。
    • setOrganizationDomain(const QString &domain) / organizationDomain(): 设置或获取组织的域名。
  • 处理命令行参数:
    • arguments() 返回一个 QStringList,包含应用程序的名称以及所有传递给它的命令行参数。
  • 应用程序状态管理: applicationState()获取【QGuiApplication 或 QApplication
    •  Qt::ApplicationState 枚举值
      • Qt::ApplicationActive,
      • Qt::ApplicationInactive
      • Qt::ApplicationHidden 
  • QCoreApplication 相关的静态函数

    函数 作用
    arguments() 获取命令行参数
    applicationName() / setApplicationName() 获取/设置应用程序名称
    applicationVersion() 获取应用程序版本
    quit() 退出应用程序(安全)
    exit(int code) 退出事件循环
    processEvents() 手动处理事件队列
    postEvent(QObject *receiver, QEvent *event) 向对象发送事件
  • QCoreApplication VS QApplication

    适用场景 特点
    QCoreApplication 控制台程序、非 GUI 程序 只提供 基本事件循环,不支持 GUI
    QGuiApplication 需要 GUI(但无 QWidget) 提供 事件循环 + GUI 相关功能(如 OpenGL, QML)
    QApplication 标准 GUI 应用 提供 完整 GUI 支持(包含 QGuiApplication 的所有功能)

    测试代码-QCoreApplication

#include 
#include 
#include 
#include 

int main(int argc, char *argv[]) {
    // 创建 QCoreApplication 实例
    QCoreApplication app(argc, argv);

    // ======================
    // 1. 实例化 QCoreApplication
    // ======================
    qDebug() << "1. QCoreApplication instance created.";

    // ======================
    // 2. 生命周期管理 - aboutToQuit() 信号
    // ======================
    QObject::connect(&app, &QCoreApplication::aboutToQuit, []() {
        qDebug() << "2. QCoreApplication::aboutToQuit() signal emitted before exiting.";
    });

    // ======================
    // 3. 命令行参数
    // ======================
    qDebug() << "\n3. Command Line Arguments:";
    QStringList args = app.arguments();
    for (int i = 0; i < args.size(); ++i) {
        qDebug() << "   Argument" << i << ":" << args[i];
    }

    // ======================
    // 4. 应用程序名称及其他全局信息
    // ======================
    app.setApplicationName("MyAppTest");
    app.setApplicationVersion("1.0.0");
    app.setOrganizationName("MyOrganization");
    app.setOrganizationDomain("myorganization.com");
    qDebug() << "\n4. Application Info:";
    qDebug() << "   Application Name:" << app.applicationName();
    qDebug() << "   Application Version:" << app.applicationVersion();
    qDebug() << "   Organization Name:" << app.organizationName();
    qDebug() << "   Organization Domain:" << app.organizationDomain();

    // ======================
    // 5. 获取 QCoreApplication 实例
    // ======================
    qDebug() << "\n5. QCoreApplication Instance:";
    QCoreApplication *instancePtr = QCoreApplication::instance();
    qDebug() << "   Address of app object:" << &app;
    qDebug() << "   Address of QCoreApplication::instance():" << instancePtr;
    qDebug() << "   Are they the same instance?" << (&app == instancePtr);

    // ======================
    // 6. 退出应用程序
    // ======================
    qDebug() << "\n6. Exiting the application in 5 seconds...";
    QTimer::singleShot(5000, &app, &QCoreApplication::quit);

    // ======================
    // 7. 启动事件循环
    // ======================
    qDebug() << "\n7. Calling app.exec() to start the event loop...";
    int returnCode = app.exec();
    qDebug() << "8. app.exec() finished with return code:" << returnCode;

    return returnCode;
}



// ======================
// console
// ======================
//1. QCoreApplication instance created.

//3. Command Line Arguments:
//   Argument 0 : "/home/user/QtProj/build-QtCore-Desktop-Debug/QtCore"

//4. Application Info:
//   Application Name: "MyAppTest"
//   Application Version: "1.0.0"
//   Organization Name: "MyOrganization"
//   Organization Domain: "myorganization.com"

//5. QCoreApplication Instance:
//   Address of app object: QCoreApplication(0x7fffffffe120)
//   Address of QCoreApplication::instance(): QCoreApplication(0x7fffffffe120)
//   Are they the same instance? true

//6. Exiting the application in 5 seconds...

//7. Calling app.exec() to start the event loop...
//2. QCoreApplication::aboutToQuit() signal emitted before exiting.
//8. app.exec() finished with return code: 0

QEventLoop 

QEventLoop 是 Qt 框架中的一个核心类,用于管理和运行事件循环。它是 QCoreApplication 事件循环机制的基础,提供了灵活的事件处理能力,适用于需要自定义事件循环或局部事件处理的场景。

  • 启动和管理事件循环: 这是 QEventLoop 的核心功能,通过 exec() 方法启动,持续监听和处理事件。
    • 通过 exec() 方法启动一个事件循环,类似于 QCoreApplication::exec() 的底层实现。

    • 调用 exec() 后,线程进入阻塞状态,循环从事件队列中取出事件并分发,事件循环依赖平台特定的事件调度器(如 Linux 的 epoll、Windows 的消息循环)。

    • 可通过信号或手动调用控制循环的启动和停止

  • 处理来自各种来源的事件: 事件被加事件队列
    • 操作系统事件: 在 GUI 应用中,处理窗口事件(如鼠标、键盘)。

    • 定时器事件: QTimer 的 timeout 信号。

    • 信号: 通过 QueuedConnection 传递的跨线程信号。

    • 帖子事件: 通过 QCoreApplication::postEvent() 手动添加的事件。

    • Socket 和 File Notifiers: QSocketNotifier 和 QFileSystemWatcher 的事件。

    • 自定义事件: 继承 QEvent 创建的用户定义事件。

  • 事件过滤: 提供机制在事件到达目标对象之前进行拦截和处理
    • 应用程序级别:使用 QCoreApplication::installEventFilter()。对象级别:使用 QObject::installEventFilter()。

    • 过滤器对象在事件分发前接收事件,可选择处理或忽略。

    • 事件流:产生->创建->投递/发送->检索->过滤->分发->处理->传播 (GUI)->消亡

  • 事件分发: 
    • QEventLoop 将事件分发给目标对象,通常通过调用目标的 event() 方法。

    • 事件队列中的每个事件都有目标 QObject,调用 QObject::event(),由目标对象处理或转发到特定事件处理函数。

    • 可通过重写 event() 方法自定义分发逻辑。

  • 支持嵌套事件循环: 
    •  QEventLoop 支持嵌套运行,即在一个事件循环中启动另一个局部事件循环。

    • 每个 QEventLoop 实例独立管理其退出条件,嵌套循环不会干扰外层循环。

    • 在处理复杂操作(如模态对话框、同步等待)时使用。

  • 提供非阻塞的事件处理: 
    • 通过 processEvents() 方法,QEventLoop 可以在不阻塞线程的情况下处理事件队列。

    • 只处理当前队列中的事件,不会等待新事件。

    • 用于刷新状态或避免 UI 冻结。

    • processEvents事件类型

      • QEventLoop::AllEvents (默认值): 处理所有类型的挂起事件。
      • QEventLoop::ExcludeUserInputEvents: 处理所有挂起的事件,但不包括用户输入事件(例如,鼠标和键盘事件)。
      • QEventLoop::ExcludeSocketNotifiers: 处理所有挂起的事件,但不包括来自套接字通知器的事件。
      • QEventLoop::ExcludeTimers: 处理所有挂起的事件,但不包括定时器事件。
      • QEventLoop::ExcludeDeferredDDeletions: 处理所有挂起的事件,但不包括延迟删除事件(由 deleteLater() 触发)。
      • QEventLoop::ExcludeDeferredUpdates: 处理所有挂起的事件,但不包括延迟样式更新事件。
      • QEventLoop::ExcludeApplicationExiting: 处理所有挂起的事件,但不包括应用程序退出事件。
  • 线程关联性: 
    • 一个 QEventLoop 实例在哪个线程中运行,它就负责处理该线程中的事件。

    • 每个线程可以独立地拥有自己的事件循环。

  • 控制事件循环的生命周期: 
    • quit(): 设置退出标志,返回值为 0。

    • exit(int): 设置退出标志并指定返回值。

  • 唤醒事件循环: 
    • 功能: wakeUp() 方法从其他线程唤醒事件循环,确保处理新事件。

    • 机制: 发送一个唤醒信号给事件循环线程,使其检查队列。

    • 在多线程中通知事件循环处理新加入的事件。

  • QEventLoop 与 QCoreApplication 关系

    • QCoreApplication::exec():启动了应用程序的主事件循环。

    • QCoreApplication 隐式的 创建和管理​​​​​​​QEventLoop

    • QEventLoop 对象是真正处理事件:等待事件、获取事件、事件过滤、事件分发。

    • QEventLoop 的生命周期通常与 QCoreApplicationexec() 调用绑定在一起。

    • 主事件循环由 QCoreApplication::exec() 启动,可添加额外的 QEventLoop 事件循环。

  • QEventLoop 子事件循环常见应用场景

    应用场景 描述
    模态对话框 (QDialog)

    进入子事件循环,阻塞主窗口交互,直到用户关闭对话框:

    QDialog dialog;
    dialog.exec();  // 进入子事件循环,阻塞主事件循环

    等待子线程任务完成

    在主线程等待子线程完成,避免 UI 冻结

    QEventLoop loop;
    QObject::connect(&worker, &Worker::workFinished, &loop, &QEventLoop::quit);
    loop.exec();  // 等待子线程完成

    避免 UI 冻结的耗时任务

    在循环中使用 QEventLoop 处理事件,防止界面卡顿:

    QEventLoop loop;
    QTimer::singleShot(50, &loop, &QEventLoop::quit);
    loop.exec();  // UI 仍然响应

    同步等待网络请求完成

    QEventLoop 等待 QNetworkReply::finished(),避免阻塞

    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();  // 等待网络请求完成

    消息框 (QMessageBox)

    QMessageBox::exec() 进入子事件循环,阻塞主线程

    QMessageBox msgBox;
    msgBox.exec();  // 进入子事件循环

测试代码-事件循环

#include 
#include 
#include 
#include 
#include 
#include 
#include 

// ======================
// CustomEvent 类定义
// ======================
class CustomEvent : public QEvent {
public:
    CustomEvent() : QEvent(QEvent::Type(QEvent::User + 1)) {}
};

// ======================
// EventHandler 类定义
// ======================
class EventHandler : public QObject {
    Q_OBJECT
public:
    EventHandler() {}

protected:
    // 重写 event 方法,处理自定义事件和定时器事件
    bool event(QEvent *e) override {
        if (e->type() == QEvent::Type(QEvent::User + 1)) {
            qDebug() << "Custom event received in event().";
            return true;
        } else if (e->type() == QEvent::Timer) {
            qDebug() << "Timer event handled in event().";
            return true;
        }
        return QObject::event(e);
    }

    // 重写 eventFilter 方法,过滤定时器事件
    bool eventFilter(QObject *obj, QEvent *event) override {
        if (event->type() == QEvent::Timer) {
            qDebug() << "Timer event filtered before reaching target.";
            return true; // 过滤掉定时器事件
        }
        return QObject::eventFilter(obj, event);
    }
};

// ======================
// WorkerThread 类定义
// ======================
class WorkerThread : public QThread {
    Q_OBJECT
public:
    WorkerThread() : loop(nullptr) {}
    QEventLoop *loop;

protected:
    // 重写 run 方法,启动线程的事件循环
    void run() override {
        loop = new QEventLoop();
        QTimer timer;
        timer.start(1000);
        QObject::connect(&timer, &QTimer::timeout, []() {
            qDebug() << "Thread timer triggered in:" << QThread::currentThreadId();
        });
        qDebug() << "Thread event loop starting in:" << QThread::currentThreadId();
        loop->exec();
        qDebug() << "Thread event loop exited.";
        delete loop;
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    qDebug() << "Main thread ID:" << QThread::currentThreadId();

    // ======================
    // 1. 启动和管理事件循环
    // ======================
    qDebug() << "\n1. Starting and Managing Event Loop";
    QEventLoop mainLoop;
    QTimer exitTimer;
    exitTimer.setSingleShot(true);
    QObject::connect(&exitTimer, &QTimer::timeout, &mainLoop, &QEventLoop::quit);
    exitTimer.start(10000); // 10秒后退出主循环

    // ======================
    // 2. 处理来自各种来源的事件
    // ======================
    qDebug() << "\n2. Handling Events from Various Sources";
    QTimer timer;
    timer.start(1000); // 定时器事件
    QObject::connect(&timer, &QTimer::timeout, []() {
        qDebug() << "Timer event triggered.";
    });

    QSocketNotifier notifier(STDIN_FILENO, QSocketNotifier::Read); // Socket Notifier 事件
    QObject::connect(¬ifier, &QSocketNotifier::activated, []() {
//        qDebug() << "Input detected on stdin.";
    });

    EventHandler handler;
    QCoreApplication::postEvent(&handler, new CustomEvent()); // 帖子事件(自定义事件)

    // ======================
    // 3. 事件过滤
    // ======================
    qDebug() << "\n3. Event Filtering";
    timer.installEventFilter(&handler); // 安装事件过滤器

    // ======================
    // 4. 事件分发
    // ======================
    qDebug() << "\n4. Event Dispatching";
    // 通过 handler 的 event() 方法处理事件(见上文 CustomEvent)

    // ======================
    // 5. 支持嵌套事件循环
    // ======================
    qDebug() << "\n5. Nested Event Loop";
    QTimer nestedTrigger;
    nestedTrigger.start(2000);
    QObject::connect(&nestedTrigger, &QTimer::timeout, [&mainLoop]() {
        qDebug() << "Starting nested event loop...";
        QEventLoop nestedLoop;
        QTimer nestedTimer;
        nestedTimer.setSingleShot(true);
        QObject::connect(&nestedTimer, &QTimer::timeout, []() {
            qDebug() << "Nested timer triggered.";
        });
        QObject::connect(&nestedTimer, &QTimer::timeout, &nestedLoop, &QEventLoop::quit);
        nestedTimer.start(500);
        nestedLoop.exec();
        qDebug() << "Nested event loop finished.";
    });

    // ======================
    // 6. 非阻塞的事件处理
    // ======================
    qDebug() << "\n6. Non-blocking Event Processing";
    QTimer nonBlockingTimer;
    nonBlockingTimer.start(1500);
    QObject::connect(&nonBlockingTimer, &QTimer::timeout, []() {
        qDebug() << "Non-blocking timer triggered.";
    });
    for (int i = 0; i < 3; ++i) {
        qDebug() << "Processing events non-blocking...";
        mainLoop.processEvents(QEventLoop::AllEvents, 1000); // 处理 1 秒内的事件
    }

    // ======================
    // 7. 线程关联性
    // ======================
    qDebug() << "\n7. Thread Affinity";
    WorkerThread thread;
    thread.start();

    // ======================
    // 8. 控制事件循环的生命周期
    // ======================
    qDebug() << "\n8. Controlling Event Loop Lifecycle";
    QEventLoop controlLoop;
    QTimer controlTimer;
    controlTimer.setSingleShot(true);
    QObject::connect(&controlTimer, &QTimer::timeout, [&controlLoop]() {
        qDebug() << "Exiting control loop with code 42.";
        controlLoop.exit(42);
    });
    controlTimer.start(1000);
    int result = controlLoop.exec();
    qDebug() << "Control loop exited with code:" << result;

    // ======================
    // 9. 唤醒事件循环
    // ======================
    qDebug() << "\n9. Waking Up Event Loop";
    QTimer wakeTimer;
    wakeTimer.setSingleShot(true);
    QObject::connect(&wakeTimer, &QTimer::timeout, [&thread]() {
        if (thread.loop && thread.loop->isRunning()) {
            qDebug() << "Waking up thread event loop...";
            thread.loop->wakeUp();
            QCoreApplication::postEvent(thread.loop, new CustomEvent());
        }
    });
    wakeTimer.start(3000);

    // ======================
    // 启动主事件循环
    // ======================
    qDebug() << "\nStarting main event loop...";
    mainLoop.exec();
    thread.quit();
    thread.wait();

    return 0;
}

#include "main.moc" // 包含 moc 生成的文件



// ======================
// console
// ======================

//Main thread ID: 0x7ffff50757c0

//1. Starting and Managing Event Loop

//2. Handling Events from Various Sources

//3. Event Filtering

//4. Event Dispatching

//5. Nested Event Loop

//6. Non-blocking Event Processing
//Processing events non-blocking...
//Custom event received in event().
//Processing events non-blocking...
//Processing events non-blocking...

//7. Thread Affinity

//8. Controlling Event Loop Lifecycle
//Thread event loop starting in: 0x7ffff5066640
//Timer event filtered before reaching target.
//Exiting control loop with code 42.
//Control loop exited with code: 42

//9. Waking Up Event Loop

//Starting main event loop...
//Thread timer triggered in: 0x7ffff5066640
//Non-blocking timer triggered.
//Starting nested event loop...
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Nested timer triggered.
//Nested event loop finished.
//Non-blocking timer triggered.
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Starting nested event loop...
//Timer event filtered before reaching target.
//Waking up thread event loop...
//Thread timer triggered in: 0x7ffff5066640
//Non-blocking timer triggered.
//Nested timer triggered.
//Nested event loop finished.
//Thread timer triggered in: 0x7ffff5066640
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Starting nested event loop...
//Non-blocking timer triggered.
//Timer event filtered before reaching target.
//Nested timer triggered.
//Nested event loop finished.
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Non-blocking timer triggered.
//Starting nested event loop...
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Nested timer triggered.
//Nested event loop finished.
//Non-blocking timer triggered.
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Starting nested event loop...
//Timer event filtered before reaching target.
//Thread timer triggered in: 0x7ffff5066640
//Non-blocking timer triggered.
//Nested timer triggered.
//Nested event loop finished.
//Thread event loop exited.

QEvent

QEvent 是 Qt 框架中所有事件类的基类。在 Qt 中,事件是代表应用程序内部或由于外部活动而发生的事情的对象。它们是 Qt 应用程序中实现交互性和响应性的核心机制。

  • 基本概念:

    • 事件对象: 当应用程序中发生某些事情时,Qt 会创建一个 QEvent 或其子类的实例来表示该事件。鼠标点击、键盘输入等;
    • 事件类型: 每个事件都有一个与之关联的类型,由 QEvent::Type 枚举定义。进行事件区分处理;
    • 事件目标: 事件会被传递给特定的 QObject 及其子类(通常是窗口部件 QWidget)。这个目标对象负责处理该事件并做出相应的响应。
  • 主要作用:

    • 通知对象: 事件机制用于通知对象应用程序中发生的各种情况。
    • 处理用户交互: 大部分用户与 GUI 应用程序的交互(如鼠标点击、键盘输入)都会生成相应的事件,这些事件被传递给相关的窗口部件进行处理。
    • 系统和应用程序内部通信: 事件不仅用于处理用户交互,还可以用于应用程序内部的组件之间的通信,以及操作系统发出的通知(例如,窗口关闭请求)。
  • 事件处理流程:

    • 事件生成: 当一个事件发生时(例如,用户按下键盘上的一个键),Qt 会创建一个相应的事件对象。
    • 事件传递: Qt 的事件系统会将这个事件对象传递给目标对象。事件传递的机制可以通过以下方式进行:
      • 直接传递 (Directly): 大多数事件通过调用目标对象的 event() 函数来直接传递。
      • 发布 (Posting): 可以使用 QCoreApplication::postEvent() 将事件发布到事件队列中,稍后由主事件循环处理。
      • 发送 (Sending): 可以使用 QCoreApplication::sendEvent() 同步地将事件发送给目标对象,该函数会立即处理事件。
    • 事件处理: 目标对象(通常是一个 QWidget)会接收到事件,并通常在其 event() 函数中进行处理。例如:
      • mousePressEvent() 处理鼠标按下事件 (QMouseEvent).
      • keyPressEvent() 处理键盘按下事件 (QKeyEvent).
      • paintEvent() 处理绘制事件 (QPaintEvent).
      • resizeEvent() 处理窗口大小调整事件 (QResizeEvent).
      • closeEvent() 处理窗口关闭事件 (QCloseEvent). 子类通常会重写这些特定的事件处理函数来响应相应的事件。
    • 事件过滤: Qt 允许使用事件过滤器来拦截和处理发送给其他对象的事件
      • QObject::installEventFilter() 安装事件过滤器。
  • 常见事件

    类名 描述
    QMouseEvent 鼠标事件(按下、释放、移动、双击等)
    QKeyEvent 键盘事件(按下、释放)
    QPaintEvent 窗口部件需要被绘制或重绘的事件
    QResizeEvent 窗口部件大小改变的事件
    QMoveEvent 窗口部件位置移动的事件
    QCloseEvent 窗口部件关闭的事件
    QTimerEvent QTimer 发出的定时器事件
    QFocusEvent 窗口部件获得或失去键盘焦点的事件
    QActionEvent QAction 相关的事件(例如,触发)
    QContextMenuEvent 上下文菜单事件
    QDragEnterEvent 拖放操作相关的事件
    QDragMoveEvent 拖放操作相关的事件
    QDropEvent 拖放操作相关的事件
    QShowEvent 窗口部件显示的事件
    QHideEvent 窗口部件隐藏的事件
    QWindowStateChangeEvent 窗口部件窗口状态改变的事件(例如,最大化、最小化)
    QCustomEvent 用户自定义的事件类型
  • QEvent::Type 常量

    常量名 描述
    QEvent::None 空事件。
    QEvent::MouseButtonPress 鼠标按键按下。
    QEvent::MouseButtonRelease 鼠标按键释放。
    QEvent::MouseMove 鼠标移动。
    QEvent::KeyPress 键盘按键按下。
    QEvent::KeyRelease 键盘按键释放。
    QEvent::Timer 定时器到期。
    QEvent::Paint 需要重绘部件。
    QEvent::Close 窗口关闭请求。
    QEvent::Resize 部件大小改变。
    QEvent::Move 部件位置移动。
    QEvent::Show 部件显示。
    QEvent::Hide 部件隐藏。
    QEvent::FocusIn 部件获得焦点。
    QEvent::FocusOut 部件失去焦点。
    QEvent::InputMethod 输入法相关事件。
    QEvent::SockAct 套接字活动。
    QEvent::FileOpen 文件打开请求。
    QEvent::Quit 应用程序退出。
    QEvent::User 用户自定义事件类型的起始值。开发者可以定义大于或等于 QEvent::User 的值作为自定义事件类型。

测试代码-QEvent

#include 
#include 
#include 
#include 

// ======================
// 1. 定义自定义事件类型
// ======================
const QEvent::Type CustomEventType = static_cast(QEvent::User + 1);

// ======================
// 2. 定义自定义事件类
// ======================
class MyCustomEvent : public QEvent {
public:
    MyCustomEvent() : QEvent(CustomEventType) {}
    QString message = "Hello from Custom Event!";
};

// ======================
// 3. 自定义对象,用于演示事件处理
// ======================
class EventHandlingObject : public QObject {
    Q_OBJECT
public:
    explicit EventHandlingObject(QObject *parent = nullptr) : QObject(parent) {}

protected:
    // 重写 event 方法,处理自定义事件
    bool event(QEvent *event) override {
        if (event->type() == CustomEventType) {
            MyCustomEvent *customEvent = static_cast(event);
            qDebug() << "EventHandlingObject: Received Custom Event - " << customEvent->message;
            return true;
        }
        return QObject::event(event);
    }

    // 重写 timerEvent 方法,处理定时器事件
    void timerEvent(QTimerEvent *event) override {
        qDebug() << "EventHandlingObject: Timer event with ID:" << event->timerId();
        QObject::timerEvent(event);
    }
};

// ======================
// 4. 应用程序级别事件过滤器
// ======================
class ApplicationEventFilter : public QObject {
protected:
    // 重写 eventFilter 方法,过滤自定义事件和定时器事件
    bool eventFilter(QObject *watched, QEvent *event) override {
        if (event->type() == CustomEventType) {
            qDebug() << "ApplicationEventFilter: Received Custom Event on" << watched;
        } else if (event->type() == QEvent::Timer) {
            QTimerEvent *timerEvent = static_cast(event);
            qDebug() << "ApplicationEventFilter: Timer event on" << watched << " with ID:" << timerEvent->timerId();
        }
        return QObject::eventFilter(watched, event);
    }
};

// ======================
// 5. 对象级别事件过滤器
// ======================
class ObjectEventFilter : public QObject {
    Q_OBJECT
public:
    explicit ObjectEventFilter(EventHandlingObject *target, QObject *parent = nullptr)
        : QObject(parent), targetObj(target) {}

protected:
    // 重写 eventFilter 方法,过滤自定义事件
    bool eventFilter(QObject *watched, QEvent *event) override {
        if (watched == targetObj && event->type() == CustomEventType) {
            qDebug() << "ObjectEventFilter (Handler): Received Custom Event";
        }
        return QObject::eventFilter(watched, event);
    }

private:
    EventHandlingObject *targetObj; // 目标对象
};

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

    // 创建事件处理对象
    EventHandlingObject handler;

    // ======================
    // 安装应用程序级别事件过滤器
    // ======================
    ApplicationEventFilter appFilter;
    a.installEventFilter(&appFilter);

    // ======================
    // 安装对象级别事件过滤器
    // ======================
    ObjectEventFilter *objFilter = new ObjectEventFilter(&handler);
    handler.installEventFilter(objFilter);

    // ======================
    // 创建并启动定时器,定期发送自定义事件
    // ======================
    QTimer customEventTimer;
    QObject::connect(&customEventTimer, &QTimer::timeout, [&handler]() {
        MyCustomEvent *customEvent = new MyCustomEvent();
        QCoreApplication::postEvent(&handler, customEvent);
    });
    customEventTimer.start(2000);

    // ======================
    // 启动另一个定时器,发送标准的 QTimerEvent
    // ======================
    QTimer standardTimer;
    QObject::connect(&standardTimer, &QTimer::timeout, [&]() {
        qDebug() << "main: Timer2 timeout - standard QTimerEvent will be generated.";
    });
    standardTimer.start(3000);

    // ======================
    // 启动应用程序事件循环
    // ======================
    qDebug() << "Starting application event loop...";
    return a.exec();
}

#include "main.moc" // 包含 moc 生成的文件

// ======================
// console
// ======================
//Starting application event loop...
//ApplicationEventFilter: Timer event on QTimer(0x7fffffffe0e0)  with ID: 1
//ApplicationEventFilter: Received Custom Event on EventHandlingObject(0x7fffffffe0c0)
//ObjectEventFilter (Handler): Received Custom Event
//EventHandlingObject: Received Custom Event -  "Hello from Custom Event!"
//ApplicationEventFilter: Timer event on QTimer(0x7fffffffe100)  with ID: 2
//main: Timer2 timeout - standard QTimerEvent will be generated.
//ApplicationEventFilter: Timer event on QTimer(0x7fffffffe0e0)  with ID: 1
//ApplicationEventFilter: Received Custom Event on EventHandlingObject(0x7fffffffe0c0)
//ObjectEventFilter (Handler): Received Custom Event
//EventHandlingObject: Received Custom Event -  "Hello from Custom Event!"
//ApplicationEventFilter: Timer event on QTimer(0x7fffffffe0e0)  with ID: 1
//ApplicationEventFilter: Timer event on QTimer(0x7fffffffe100)  with ID: 2
//main: Timer2 timeout - standard QTimerEvent will be generated.

QTimer

QTimer 类是 Qt 框架中用于实现定时功能的类。它允许您在指定的时间间隔后发出一个信号 (timeout()),从而触发相应的操作。

  • 核心功能与工作原理

    • 定时触发: QTimer 的主要功能是在设定的时间间隔结束后,自动发出 timeout() 信号。
    • 基于事件循环: QTimer 的工作完全依赖于 Qt 的事件循环。
    • 非阻塞: 使用 QTimer 不会阻塞您的应用程序。 
  • 主要方法

    • timeout() 信号: 这是 QTimer 最重要的信号。
    • start(int interval): 启动定时器,并设置时间间隔 interval,单位是毫秒。
    • stop(): 停止定时器。
    • setInterval(int interval): 设置定时器的时间间隔,单位是毫秒。
    • interval() const: 返回当前定时器的时间间隔(毫秒)。
    • isSingleShot() const: 返回一个布尔值,指示定时器是否为单次触发模式。
    • setSingleShot(bool singleShot): 设置定时器是否为单次触发模式。
      • 如果 singleShottrue,定时器在第一次 timeout() 信号发出后会自动停止。
      • 如果 singleShotfalse,调用 stop()停止
    • isActive() const: 返回一个布尔值,指示定时器是否正在运行。
    • 静态方法 singleShot(int msec, const QObject *receiver, const char *member): 这是一个方便的静态函数,用于创建并启动一个单次触发的定时器。
  • 定时器精度: QTimer 的精度取决于操作系统和系统的负载。

  • QThread::sleep() 的区别

    • QTimer (非阻塞): 使用 QTimer 时,您的应用程序仍然可以响应其他事件(例如用户输入),因为定时器的工作依赖于事件循环。
    • QThread::sleep() (阻塞): 调用 QThread::sleep() 会使当前线程暂停执行指定的时间,期间应用程序无法响应任何事件,导致界面冻结。
  • 使用场景

    用途 描述
    周期性更新 UI 例如,每隔一段时间更新显示的时间、动画的帧等。
    延迟执行操作 例如,在用户完成某个操作后延迟一段时间再执行下一步。
    实现超时机制 例如,在等待网络响应时设置一个超时时间。
    轮询数据 例如,定期检查服务器是否有新的数据。
    动画效果 通过定时器不断触发重绘事件来创建动画效果。

测试代码-QTimer

#include 
#include 
#include 

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

    // ======================
    // 单次触发定时器示例
    // ======================
    qDebug() << "--- 单次触发定时器示例 ---";
    QTimer::singleShot(3000, []() {
        qDebug() << "3 秒后执行一次!";
    });
    qDebug() << "单次触发定时器已启动,将在 3 秒后输出消息。";

    // ======================
    // 重复触发定时器示例
    // ======================
    qDebug() << "\n--- 重复触发定时器示例 ---";
    int counter = 0;
    QTimer *repeatingTimer = new QTimer(); // 使用 new 创建,避免局部变量在 lambda 中失效
    QObject::connect(repeatingTimer, &QTimer::timeout, [&]() {
        qDebug() << "每隔 1 秒触发一次,当前计数:" << ++counter;
        if (counter >= 3) {
            repeatingTimer->stop();
            qDebug() << "重复触发定时器已停止。";
            QTimer::singleShot(100, [&]() { // 稍作延迟后退出,确保输出完整
                QCoreApplication::quit();
            });
        }
    });
    repeatingTimer->start(1000); // 设置时间间隔为 1000 毫秒 (1 秒)
    qDebug() << "重复触发定时器已启动,每隔 1 秒输出消息,计数到 3 次后停止。";

    // ======================
    // 启动应用程序事件循环
    // ======================
    return app.exec();
}



// ======================
// console
// ======================

//--- 单次触发定时器示例 ---
//单次触发定时器已启动,将在 3 秒后输出消息。

//--- 重复触发定时器示例 ---
//重复触发定时器已启动,每隔 1 秒输出消息,计数到 3 次后停止。
//每隔 1 秒触发一次,当前计数: 1
//每隔 1 秒触发一次,当前计数: 2
//3 秒后执行一次!
//每隔 1 秒触发一次,当前计数: 3
//重复触发定时器已停止。

QMetaObject:

QMetaObject 类是 Qt 框架中元对象系统的核心组成部分。它提供了对 Qt 类在运行时进行自省的能力,使得 Qt 能够实现诸如信号与槽、属性系统、动态属性、以及对象序列化等高级特性。 

  • 运行时类型信息 (RTTI)

    • 类名 (Class Name)

      • QMetaObject 存储了类的完整名称。
      • 通过 QMetaObject::className() 方法可以获取到这个名称。
    •  父类 (Parent Class)

      • QMetaObject 包含一个指向其直接父类的 QMetaObject 对象的指针。
      • 这形成了类的继承层次结构,允许 Qt 在运行时遍历类的继承链。
      • 通过 QMetaObject::superClass() 方法可以获取到父类的 QMetaObject
    • 3. 信号 (Signals)

      • QMetaObject 存储了以下信息:
        • 信号名称: 不包括参数列表。
        • 参数类型: 每个参数的类型信息。
        • 参数数量: 信号的参数个数。
        • 信号索引: 信号在其信号表中的唯一索引。
        • 信号签名: 包含信号名称和参数类型的完整签名(通常用于连接信号和槽)。
      • 通过下面方法访问:
        • QMetaObject::signalCount(),
        • QMetaObject::signal(int index),
        • QMetaObject::indexOfSignal() 
    • 4. 槽 (Slots)

      • QMetaObject 存储了以下信息:
        • 槽函数名称: 不包括参数列表。
        • 参数类型: 每个参数的类型信息。
        • 参数数量: 槽函数的参数个数。
        • 槽函数索引: 槽函数在其槽表中的唯一索引。
        • 槽函数签名: 包含槽函数名称和参数类型的完整签名。
        • 访问修饰符: 指示槽函数是 publicprotected 还是 private
      • 通过下面方法访问:
        • QMetaObject::slotCount(),
        • QMetaObject::slot(int index),
        • QMetaObject::indexOfSlot() 
    • 属性 (Properties)

      •  Q_PROPERTY 宏声,QMetaObject 存储了以下信息:
        • 属性名称: 属性的名称。
        • 数据类型: 属性的数据类型。
        • 可读性: 指示属性是否可读(通常通过 READ 方法指定)。
        • 可写性: 指示属性是否可写(通常通过 WRITE 方法指定)。
        • Notifier 信号: 如果属性有 NOTIFY 信号,则存储该信号的元方法索引。
        • Designable/Scriptable 标志: 是否可见或是否可以被脚本语言访问。
        • User 属性标志: 指示属性是否为用户可见的属性。
      • 调用方法:
        • QMetaObject::propertyCount()
        • QMetaObject::property(int index)
        • QMetaObject::indexOfProperty() 
    • 方法 (Methods)

      •  Q_INVOKABLEQMetaObject 存储了以下信息:
        • 方法名称: 不包括参数列表。
        • 参数类型: 每个参数的类型信息。
        • 返回值类型: 方法的返回值类型。
        • 方法索引: 方法在其方法表中的唯一索引。
        • 方法签名: 包含方法名称和参数类型的完整签名。
        • 方法类型: 指示方法是信号、槽还是普通的 Q_INVOKABLE 方法。
      • 调用方法
        • ​​​​​​​QMetaObject::methodCount()
        •  QMetaObject::method(int index)
        •  QMetaObject::indexOfMethod()
    • 枚举 (Enums)

      • 使用 enumenum class ,QMetaObject 存储了以下信息:
        • 枚举名称: 枚举类型的名称。
        • 作用域: 指示枚举是类作用域还是全局作用域。
        • 枚举值: 枚举中每个枚举常量的名称及其对应的整数值。
        • 是否为 Flag 类型: 使用了 Q_FLAG 宏标记,一个可以进行位运算的标志类型。
      • 获取方法
        • ​​​​​​​QMetaObject::enumeratorCount(),
        • QMetaObject::enumerator(int index),
        • QMetaObject::indexOfEnumerator()

测试代码-运行时类型信息

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// ======================
// MyClass 类定义
// ======================
class MyClass : public QObject {
    Q_OBJECT
public:
    enum MyEnum {
        Value1 = 1,
        Value2 = 2,
        Value3 = 4
    };
    Q_ENUM(MyEnum)

    Q_PROPERTY(int myProperty READ getMyProperty WRITE setMyProperty NOTIFY myPropertyChanged)

    explicit MyClass(QObject *parent = nullptr) : QObject(parent), m_myProperty(0) {}

    int getMyProperty() const { return m_myProperty; }
    void setMyProperty(int value) {
        if (m_myProperty != value) {
            m_myProperty = value;
            emit myPropertyChanged(m_myProperty);
        }
    }

public slots:
    void mySlot(int value) {
        qDebug() << "MySlot received:" << value;
    }

    void anotherSlot(const QString& text) {
        qDebug() << "AnotherSlot received:" << text;
    }

    void overloadedSlot(int value) {
        qDebug() << "OverloadedSlot (int) received:" << value;
    }

    void overloadedSlot(const QString& text) {
        qDebug() << "OverloadedSlot (QString) received:" << text;
    }

    Q_INVOKABLE void myMethod(bool flag) {
        qDebug() << "MyMethod called with flag:" << flag;
    }

signals:
    void mySignal(QString message);
    void anotherSignal(int code, bool status);
    void myPropertyChanged(int newValue);

private:
    int m_myProperty; // 属性值
};

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

    // 实例化 MyClass
    MyClass obj;

    const QMetaObject *metaObject = obj.metaObject(); // 使用实例的 metaObject

    // ======================
    // 1. 类名
    // ======================
    qDebug() << "--- 类名 ---";
    qDebug() << "Class Name:" << metaObject->className();

    // ======================
    // 2. 父类
    // ======================
    qDebug() << "\n--- 父类 ---";
    if (metaObject->superClass()) {
        qDebug() << "Super Class Name:" << metaObject->superClass()->className();
    } else {
        qDebug() << "No super class.";
    }

    // ======================
    // 3. 信号列表 Qt 4
    // ======================
    qDebug() << "\n--- 信号列表 ---";
    int signalCount = 0;
    for (int i = 0; i < metaObject->methodCount(); ++i) {
        if (metaObject->method(i).methodType() == QMetaMethod::Signal) {
            signalCount++;
        }
    }
    qDebug() << "Number of Signals:" << signalCount;
    for (int i = 0; i < metaObject->methodCount(); ++i) {
        QMetaMethod method = metaObject->method(i);
        if (method.methodType() == QMetaMethod::Signal) {
            qDebug() << "  Index:" << i << ", Name:" << method.name() << ", Signature:" << method.methodSignature();
        }
    }

    // ======================
    // 4. 槽列表
    // ======================
    int slotCount = 0;
    for (int i = 0; i < metaObject->methodCount(); ++i) {
        if (metaObject->method(i).methodType() == QMetaMethod::Slot) {
            slotCount++;
        }
    }
    qDebug() << "Number of Slots:" << slotCount;
    for (int i = 0; i < metaObject->methodCount(); ++i) {
        QMetaMethod method = metaObject->method(i);
        if (method.methodType() == QMetaMethod::Slot) {
            qDebug() << "  Index:" << i << ", Name:" << method.name() << ", Signature:" << method.methodSignature();
        }
    }

    // ======================
    // 5. 属性列表
    // ======================
    qDebug() << "\n--- 属性列表 ---";
    int propertyCount = metaObject->propertyCount();
    qDebug() << "Number of Properties:" << propertyCount;
    for (int i = 0; i < propertyCount; ++i) {
        QMetaProperty property = metaObject->property(i);
        qDebug() << "  Index:" << i << ", Name:" << property.name() << ", Type:" << property.typeName()
                 << ", Readable:" << property.isReadable() << ", Writable:" << property.isWritable();
    }

    // ======================
    // 6. 方法列表
    // ======================
    qDebug() << "\n--- 方法列表 ---";
    int methodCount = metaObject->methodCount();
    qDebug() << "Number of Methods:" << methodCount;
    for (int i = 0; i < methodCount; ++i) {
        QMetaMethod method = metaObject->method(i);
        QString type;
//      if (method.methodType() == QMetaMethod::Method)
        {
            qDebug() << "  Index:" << i << ", Type:" << method.methodType() << ", Name:" << method.name() << ", Signature:" << method.methodSignature();
        }
    }

    // ======================
    // 7. 枚举列表
    // ======================
    qDebug() << "\n--- 枚举列表 ---";
    int enumCount = metaObject->enumeratorCount();
    qDebug() << "Number of Enums:" << enumCount;
    for (int i = 0; i < enumCount; ++i) {
        QMetaEnum metaEnum = metaObject->enumerator(i);
        qDebug() << "  Name:" << metaEnum.name() << ", Scope:" << metaEnum.scope();
        qDebug() << "    Keys and Values:";
        for (int j = 0; j < metaEnum.keyCount(); ++j) {
            qDebug() << "      " << metaEnum.key(j) << "=" << metaEnum.value(j);
        }
    }

    // ======================
    // 8. 测试功能
    // ======================
    qDebug() << "\n--- 测试功能 ---";
    obj.setMyProperty(42); // 测试属性
    QObject::connect(&obj, &MyClass::mySignal, &obj, &MyClass::anotherSlot);
    emit obj.mySignal("Test Signal"); // 测试信号和槽

    QTimer::singleShot(1000, [&obj]() {
        obj.myMethod(true); // 测试 Q_INVOKABLE 方法
        QCoreApplication::quit(); // 1 秒后退出
    });

    // ======================
    // 启动应用程序事件循环
    // ======================
    return a.exec();
}

#include "main.moc" // 包含 moc 生成的文件


// ======================
// console
// ======================
//--- 类名 ---
//Class Name: MyClass

//--- 父类 ---
//Super Class Name: QObject

//--- 信号列表 ---
//Number of Signals: 6
//  Index: 0 , Name: "destroyed" , Signature: "destroyed(QObject*)"
//  Index: 1 , Name: "destroyed" , Signature: "destroyed()"
//  Index: 2 , Name: "objectNameChanged" , Signature: "objectNameChanged(QString)"
//  Index: 5 , Name: "mySignal" , Signature: "mySignal(QString)"
//  Index: 6 , Name: "anotherSignal" , Signature: "anotherSignal(int,bool)"
//  Index: 7 , Name: "myPropertyChanged" , Signature: "myPropertyChanged(int)"
//Number of Slots: 7
//  Index: 3 , Name: "deleteLater" , Signature: "deleteLater()"
//  Index: 4 , Name: "_q_reregisterTimers" , Signature: "_q_reregisterTimers(void*)"
//  Index: 8 , Name: "mySlot" , Signature: "mySlot(int)"
//  Index: 9 , Name: "anotherSlot" , Signature: "anotherSlot(QString)"
//  Index: 10 , Name: "overloadedSlot" , Signature: "overloadedSlot(int)"
//  Index: 11 , Name: "overloadedSlot" , Signature: "overloadedSlot(QString)"
//  Index: 12 , Name: "myMethod" , Signature: "myMethod(bool)"

//--- 属性列表 ---
//Number of Properties: 2
//  Index: 0 , Name: objectName , Type: QString , Readable: true , Writable: true
//  Index: 1 , Name: myProperty , Type: int , Readable: true , Writable: true

//--- 方法列表 ---
//Number of Methods: 13
//  Index: 0 , Type: 1 , Name: "destroyed" , Signature: "destroyed(QObject*)"
//  Index: 1 , Type: 1 , Name: "destroyed" , Signature: "destroyed()"
//  Index: 2 , Type: 1 , Name: "objectNameChanged" , Signature: "objectNameChanged(QString)"
//  Index: 3 , Type: 2 , Name: "deleteLater" , Signature: "deleteLater()"
//  Index: 4 , Type: 2 , Name: "_q_reregisterTimers" , Signature: "_q_reregisterTimers(void*)"
//  Index: 5 , Type: 1 , Name: "mySignal" , Signature: "mySignal(QString)"
//  Index: 6 , Type: 1 , Name: "anotherSignal" , Signature: "anotherSignal(int,bool)"
//  Index: 7 , Type: 1 , Name: "myPropertyChanged" , Signature: "myPropertyChanged(int)"
//  Index: 8 , Type: 2 , Name: "mySlot" , Signature: "mySlot(int)"
//  Index: 9 , Type: 2 , Name: "anotherSlot" , Signature: "anotherSlot(QString)"
//  Index: 10 , Type: 2 , Name: "overloadedSlot" , Signature: "overloadedSlot(int)"
//  Index: 11 , Type: 2 , Name: "overloadedSlot" , Signature: "overloadedSlot(QString)"
//  Index: 12 , Type: 2 , Name: "myMethod" , Signature: "myMethod(bool)"

//--- 枚举列表 ---
//Number of Enums: 1
//  Name: MyEnum , Scope: MyClass
//    Keys and Values:
//       Value1 = 1
//       Value2 = 2
//       Value3 = 4

//--- 测试功能 ---
//AnotherSlot received: "Test Signal"
//MyMethod called with flag: true
  • 信号与槽连接

    • 运行时通过名称连接信号和槽

      • 建立连接记录: 如果信号和槽被成功找到且类型匹配,Qt 会在内部维护一个连接记录,将发送者对象的特定信号与接收者对象的特定槽函数关联起来。
      • 类型匹配: QMetaObject 包含了信号和槽的参数类型信息。connect() 会在运行时检查信号的参数类型是否与槽的参数类型兼容。
      • 查找信号和槽: connect() 函数会获取发送者和接收者的 QMetaObject 对象。
    • 支持跨线程的队列连接​​​​​​​
      • 线程亲缘性 (Thread Affinity): 每个 QObject 都有一个线程亲缘性,它属于创建它的线程,或者通过 moveToThread() 移动到的线程。
      • 信号发射: 当一个信号被发射时,Qt 会检查信号的发送者和接收者是否位于同一个线程。
      • 队列连接的触发: 如果发送者和接收者位于不同的线程,并且连接类型是 Qt::QueuedConnection,Qt 就不会直接调用槽函数。
      • 事件的创建: 相反,Qt 会使用 QMetaObject 中存储的关于信号的信息(包括信号的名称和参数类型),将信号的参数值封装成一个事件 (event)。
      • 事件的投递: 这个事件会被投递 (posted) 到接收者对象所关联的线程的事件队列 (event queue) 中。通常通过 QCoreApplication::postEvent() 完成。
      • 事件循环的检索: 接收者对象所在的线程必须运行着一个事件循环 (QEventLoop)。
      • 事件的分发和处理: 当接收者线程的事件循环检索到之前投递的 QMetaCallEvent 时,它会使用接收者对象的 QMetaObject 中的信息,找到对应的槽函数,并在接收者线程的上下文中执行 (invoke) 该槽函数,并将事件中携带的参数传递给槽函数。
  • 属性系统

    • Q_PROPERTY 宏声明属性
      • DataType: 属性的数据类型。
      • Name: 属性的名称,在运行时通过这个名称访问属性。
      • READ getterMethod: 指定用于获取属性值的成员函数(通常是 const 的)。
      • WRITE setterMethod (可选): 指定用于设置属性值的成员函数。
      • NOTIFY signal (可选): 指定当属性值改变时会发出的信号。
      • 其他关键字 (可选): 这些关键字提供了关于属性的额外元信息。
    • 运行时通过名称访问和修改属性
      • QObject::property(const char *name) const:

        • 接收一个属性名称的字符串作为参数。
        • QMetaObject 会查找具有该名称的属性的元数据。
        • 调用该属性声明中指定的 READ 方法(getter)来获取属性的当前值。
        • 返回一个 QVariant 对象,该对象封装了属性的值。
      • QObject::setProperty(const char *name, const QVariant &value):

        • 接收一个属性名称的字符串和一个 QVariant 对象作为参数。
        • QMetaObject 会查找具有该名称的属性的元数据。
        • 如果找到,它会检查 value 的类型是否与属性的类型兼容。
        • 调用该属性声明中指定的 WRITE 方法(setter)来设置属性的新值。
        • 如果属性声明了 NOTIFY 信号,setProperty 方法通常会在成功设置属性值后发出该信号,通知其他对象属性已发生更改。
        • 返回一个布尔值,指示属性是否成功设置。
    • 属性元数据的访问​​​​​​​
      • QObject::metaObject() 获取对象的 QMetaObject
      • QMetaObject::propertyCount() 获取属性的总数。
      • QMetaObject::property(int index) 获取指定索引的 QMetaProperty 对象,该对象包含了属性的名称、类型、是否可读写等信息。
      • QMetaObject::indexOfProperty(const char *name) 获取指定名称属性的索引
      • QMetaProperty 提供方法:
        • name(): 属性名。
        • typeName(): 类型名。
        • isReadable(): 是否可读。
        • isWritable(): 是否可写。
        • read(QObject*): 读取属性值。
        • write(QObject*, QVariant): 设置属性值。
        • notifySignal(): 获取通知信号。

测试代码-属性系统

#include 
#include 
#include 
#include 
#include 
#include 

// ======================
// MyClass 类定义
// ======================
class MyClass : public QObject {
    Q_OBJECT
    // 定义属性
    Q_PROPERTY(int age READ getAge WRITE setAge NOTIFY ageChanged)
    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(double score READ getScore WRITE setScore) // 无通知信号

public:
    explicit MyClass(QObject *parent = nullptr) : QObject(parent), m_age(0), m_score(0.0) {}

    // age 属性
    int getAge() const { return m_age; }
    void setAge(int value) {
        if (m_age != value) {
            m_age = value;
            emit ageChanged(m_age);
        }
    }

    // name 属性
    QString getName() const { return m_name; }
    void setName(const QString &value) {
        if (m_name != value) {
            m_name = value;
            emit nameChanged(m_name);
        }
    }

    // score 属性
    double getScore() const { return m_score; }
    void setScore(double value) { m_score = value; }

signals:
    void ageChanged(int newAge);
    void nameChanged(const QString &newName);

private:
    int m_age;       // 年龄属性
    QString m_name;  // 姓名属性
    double m_score;  // 分数属性
};

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

    // 创建对象
    MyClass obj;

    // 获取元对象
    const QMetaObject *metaObject = obj.metaObject();

    // ======================
    // 1. 打印属性信息
    // ======================
    qDebug() << "--- 属性列表 ---";
    int propertyCount = metaObject->propertyCount();
    qDebug() << "Number of Properties:" << propertyCount;
    for (int i = 0; i < propertyCount; ++i) {
        QMetaProperty property = metaObject->property(i);
        qDebug() << "  Index:" << i
                 << ", Name:" << property.name()
                 << ", Type:" << property.typeName()
                 << ", Readable:" << property.isReadable()
                 << ", Writable:" << property.isWritable()
                 << ", Has Notify:" << property.hasNotifySignal();
        if (property.hasNotifySignal()) {
            qDebug() << "    Notify Signal:" << property.notifySignal().methodSignature();
        }
    }

    // ======================
    // 2. 测试属性读写
    // ======================
    qDebug() << "\n--- 测试属性读写 ---";
    // 设置初始值
    obj.setAge(25);
    obj.setName("Alice");
    obj.setScore(95.5);

    // 通过 QMetaProperty 读取属性
    QMetaProperty ageProp = metaObject->property(metaObject->indexOfProperty("age"));
    QMetaProperty nameProp = metaObject->property(metaObject->indexOfProperty("name"));
    QMetaProperty scoreProp = metaObject->property(metaObject->indexOfProperty("score"));

    qDebug() << "Initial Values:";
    qDebug() << "  Age:" << ageProp.read(&obj).toInt();
    qDebug() << "  Name:" << nameProp.read(&obj).toString();
    qDebug() << "  Score:" << scoreProp.read(&obj).toDouble();

    // 通过 QMetaProperty 修改属性
    ageProp.write(&obj, 30);
    nameProp.write(&obj, "Bob");
    scoreProp.write(&obj, 88.0);

    qDebug() << "After Modification:";
    qDebug() << "  Age:" << ageProp.read(&obj).toInt();
    qDebug() << "  Name:" << nameProp.read(&obj).toString();
    qDebug() << "  Score:" << scoreProp.read(&obj).toDouble();

    // ======================
    // 3. 测试通知信号
    // ======================
    qDebug() << "\n--- 测试通知信号 ---";
    QObject::connect(&obj, &MyClass::ageChanged, [](int newAge) {
        qDebug() << "Signal: ageChanged emitted with value:" << newAge;
    });
    QObject::connect(&obj, &MyClass::nameChanged, [](const QString &newName) {
        qDebug() << "Signal: nameChanged emitted with value:" << newName;
    });

    obj.setAge(35); // 触发 ageChanged 信号
    obj.setName("Charlie"); // 触发 nameChanged 信号
    obj.setScore(99.0); // 无信号

    // ======================
    // 退出程序
    // ======================
    QTimer::singleShot(1000, &app, &QCoreApplication::quit);
    return app.exec();
}

#include "main.moc" // 包含 moc 生成的文件


// ======================
// console
// ======================
//--- 属性列表 ---
//Number of Properties: 4
//  Index: 0 , Name: objectName , Type: QString , Readable: true , Writable: true , Has Notify: true
//    Notify Signal: "objectNameChanged(QString)"
//  Index: 1 , Name: age , Type: int , Readable: true , Writable: true , Has Notify: true
//    Notify Signal: "ageChanged(int)"
//  Index: 2 , Name: name , Type: QString , Readable: true , Writable: true , Has Notify: true
//    Notify Signal: "nameChanged(QString)"
//  Index: 3 , Name: score , Type: double , Readable: true , Writable: true , Has Notify: false

//--- 测试属性读写 ---
//Initial Values:
//  Age: 25
//  Name: "Alice"
//  Score: 95.5
//After Modification:
//  Age: 30
//  Name: "Bob"
//  Score: 88

//--- 测试通知信号 ---
//Signal: ageChanged emitted with value: 35
//Signal: nameChanged emitted with value: "Charlie"
  • 动态方法调用

    • QMetaObject::invokeMethod() 函数
      • object (QObject):* 指向要调用方法的对象。
      • method (const char):* 要调用的方法的名称。
      • type (Qt::ConnectionType): 指定调用类型:
        • Qt::AutoConnection:自动选择
        • Qt::DirectConnection: 立即在调用者的线程中执行。
        • Qt::QueuedConnection: 跨线程队列。
        • Qt::BlockingQueuedConnection: 阻塞调用
        • Qt::UniqueConnection: 唯一的连接。
      • ret (QGenericReturnArgument): 用于接收方法返回值的参数。
      • returnVal (QVariant): 接受 QVariant 类型的返回值。
      • val0val9 (QGenericArgument 或 QVariant): 最多可以传递 10 个参数。
      • 函数返回 true 如果方法被成功调用,否则返回 false

    • QMetaObject::invokeMethod() 工作流程

      • 获取 QMetaObject 对象。
      • 查找方法:。
      • 类型转换和参数准备。
      • 方法调用。
      • 返回值处理。
  • 类型转换

    • 方法 static T QMetaObject::cast(QObject *obj) ​​​​​​​
      • T: 目标指针类型,您希望将 obj 转换成的类型。
      • obj: 要进行类型转换的 QObject 指针。
      • 返回指向该对象的 T 类型指针或返回 nullptr
    • QMetaObject::cast() 的工作原理​​​​​​​
      • 获取目标类型 TQMetaObject 对象(通常通过 T::staticMetaObject)。
      • 从要转换的 QObject 指针 obj 获取其 QMetaObject 对象 (obj->metaObject()).
      • 遍历 objQMetaObject 继承链(通过 superClass() 方法),检查在链中是否存在与目标类型 TQMetaObject 相同的对象。
      • 如果找到匹配的 QMetaObject,则说明 obj 指向的对象是类型 T 或其派生类的一个实例,可以安全地转换为 T*
      • 如果没有找到匹配的 QMetaObject,则转换是不安全的,cast() 返回 nullptr
    • 上转型 (Upcasting) 和下转型 (Downcasting)

      • 上转型 (Derived to Base): 将派生类指针转换为基类指针是安全的。
      • 下转型 (Base to Derived): 将基类指针转换为派生类指针是不安全的。

测试代码-类型转换

#include 
#include 
#include 

// ======================
// Base 类定义
// ======================
class Base : public QObject {
    Q_OBJECT
public:
    explicit Base(QObject *parent = nullptr) : QObject(parent) {}
    virtual void baseFunction() {
        qDebug() << "Base: baseFunction called";
    }
};

// ======================
// Derived 类定义
// ======================
class Derived : public Base {
    Q_OBJECT
public:
    explicit Derived(QObject *parent = nullptr) : Base(parent) {}
    void derivedFunction() {
        qDebug() << "Derived: derivedFunction called";
    }
    void baseFunction() override {
        qDebug() << "Derived: baseFunction (overridden) called";
    }
};

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

    // 创建基类和派生类对象
    Base baseObj;
    Derived derivedObj;

    // ======================
    // 1. 上转型 (Derived* -> Base*) - 总是安全的
    // ======================
    Derived *derivedPtr = &derivedObj;
    Base *upcastedPtr = qobject_cast(derivedPtr);

    qDebug() << "--- Upcasting ---";
    qDebug() << "Derived pointer:" << derivedPtr;
    if (upcastedPtr) {
        qDebug() << "Upcasting successful. Base pointer:" << upcastedPtr;
        upcastedPtr->baseFunction(); // 调用重写后的方法(多态性)
    } else {
        qDebug() << "Upcasting failed (should not happen).";
    }

    // ======================
    // 2. 下转型 (Base* -> Derived*) - 成功的情况
    // ======================
    Base *basePtr1 = &derivedObj; // 基类指针指向派生类对象
    Derived *downcastedPtr1 = qobject_cast(basePtr1);

    qDebug() << "\n--- Downcasting (Successful) ---";
    qDebug() << "Base pointer:" << basePtr1;
    if (downcastedPtr1) {
        qDebug() << "Downcasting successful. Derived pointer:" << downcastedPtr1;
        downcastedPtr1->derivedFunction(); // 调用派生类特有方法
        downcastedPtr1->baseFunction();    // 调用重写后的方法
    } else {
        qDebug() << "Downcasting failed.";
    }

    // ======================
    // 3. 下转型 (Base* -> Derived*) - 失败的情况
    // ======================
    Base *basePtr2 = &baseObj; // 基类指针指向基类对象
    Derived *downcastedPtr2 = qobject_cast(basePtr2);

    qDebug() << "\n--- Downcasting (Failed) ---";
    qDebug() << "Base pointer:" << basePtr2;
    if (downcastedPtr2) {
        qDebug() << "Downcasting successful (should not happen). Derived pointer:" << downcastedPtr2;
        downcastedPtr2->derivedFunction();
    } else {
        qDebug() << "Downcasting failed (as expected).";
    }

    return 0; // 无需事件循环,直接退出
}

#include "main.moc" // 包含 moc 生成的文件



// ======================
// console
// ======================
//--- Upcasting ---
//Derived pointer: Derived(0x7fffffffe130)
//Upcasting successful. Base pointer: Derived(0x7fffffffe130)
//Derived: baseFunction (overridden) called

//--- Downcasting (Successful) ---
//Base pointer: Derived(0x7fffffffe130)
//Downcasting successful. Derived pointer: Derived(0x7fffffffe130)
//Derived: derivedFunction called
//Derived: baseFunction (overridden) called

//--- Downcasting (Failed) ---
//Base pointer: Base(0x7fffffffe120)
//Downcasting failed (as expected).
  • 自我检查

    • 获取 QMetaObject 对象
      • 通过对象实例: 可以使用 obj->metaObject() 方法来获取指向该对象所属类的 QMetaObject 的指针。
      • 通过类名: 可以使用静态成员 ClassName::staticMetaObject 来获取该类的 QMetaObject 对象。
    • 获取类名:使用 className() 方法获取类的名称(返回 const char*):

    • 获取信号列表(Qt 4

      • 获取信号数量: 使用 signalCount() 方法获取类中定义的信号总数。
      • 遍历信号: 使用 signal(int index) 方法获取指定索引处的信号的元数据,返回一个 QMetaMethod 对象。
      • 获取信号名称和签名: 可以使用 name() 方法获取信号的名称, methodSignature() 方法获取包含参数类型的完整签名。
      • 查找特定信号的索引: 使用 indexOfSignal(const QByteArray &signalSignature) 方法可以通过信号签名查找其索引。
    • 获取槽列表(Qt 4

      • 获取槽数量: 使用 slotCount() 方法获取类中定义的槽函数总数。
      • 遍历槽: 使用 slot(int index) 方法获取指定索引处的槽函数的元数据,返回一个 QMetaMethod 对象。
      • 获取槽名称和签名: 可以使用 name() 方法获取槽函数的名称, methodSignature() 方法获取包含参数类型的完整签名。
      • 查找特定槽的索引: 使用 indexOfSlot(const QByteArray &slotSignature) 方法可以通过槽函数签名查找其索引。
    • 获取方法列表 (包括信号和槽)

      • 获取方法总数: 使用 methodCount() 方法获取类中定义的所有方法(包括信号、槽和普通的 Q_INVOKABLE 方法)的总数。
      • 遍历方法: 使用 method(int index) 方法获取指定索引处的方法的元数据,返回一个 QMetaMethod 对象。
      • 获取方法名称和类型: 可以使用 name() 方法获取方法的名称,使用 methodType() 方法获取方法的类型(QMetaMethod::Signal, QMetaMethod::Slot, QMetaMethod::Method)。

       

                注:部分接口可能有更新!!!

四. 多线程和并发 (Multithreading and Concurrency)

  • QThread
    QThread 提供了线程管理的功能,允许开发者创建和管理线程。

  • 同步工具QMutex、QReadWriteLock、QSemaphore、QWaitCondition

        QMutex:互斥锁,确保线程安全。

        QReadWriteLock:读写锁,适用于多读少写场景。

        QSemaphore:信号量,控制资源访问。

        QWaitCondition:线程等待条件。

  • QThreadPool 和 QRunnable

        线程池管理。

  • 原子操作

        QAtomicInt 和 QAtomicPointer 提供线程安全的原子操作。

  • QtConcurrent
    QtConcurrent 提供了对并行计算的高层次抽象。它允许开发者简洁地进行多线程任务处理,如并行遍历、过滤等操作。

五. 国际化和本地化 (Internationalization and Localization)

  • QLocale
    QLocale 类用于管理语言、区域设置等本地化信息,能够根据不同的区域设置显示日期、时间、数字等格式。

  • QTranslator
    QTranslator 用于加载翻译文件,以便将应用程序界面翻译成不同的语言。

六. 进程和进程间通信 (Process and Inter-Process Communication - IPC)

  • QProcess
    QProcess 类用于启动外部进程并与其进行交互,支持进程输入输出流的管理。

  • QLocalSocket, QLocalServer

    • QLocalSocket: 本地套接字,用于与本地进程进行通信。

    • QLocalServer: 本地服务器,用于监听来自其他进程的连接请求。

  • QSharedMemory
    QSharedMemory 提供了进程间共享内存的访问,允许多个进程共享同一块内存区域。

七. 插件支持 (Plugin Support)

  • QPluginLoader
    QPluginLoader 用于加载动态插件,使得应用程序能够在运行时加载和卸载插件。

  • QFactoryInterface
    QFactoryInterface 是插件接口,插件可以实现特定功能,并通过该接口供应用程序使用。

八. 文本编解码 (Text Codecs)

  • QTextCodec
    QTextCodec 用于文本编码和解码,支持多种字符集,如 UTF-8、GBK、ISO-8859-1 等。

九. 动态库加载 (Dynamic Library Loading)

  • QLibrary
    QLibrary 用于加载动态链接库,并提供访问其导出函数的能力,支持跨平台的动态库管理。

十. 全局函数

  • qAbs

        计算绝对值。

  • qDebug、qWarning、qCritical

        调试和日志输出。

  • qInstallMsgHandler

        安装消息处理程序。

  • qVersion

返回 Qt 版本。

  • qRegisterResourceData 和 qUnregisterResourceData:

资源数据管理。

十一. 其他实用工具

  • QUrl

URL 解析和生成。

  • QRandomGenerator

线程安全的随机数生成。

  • QCryptographicHas

加密哈希类(如 MD5、SHA-256)。

  • QJsonDocument、QJsonArray、QJsonObject、QJsonValue

JSON 处理:

  • QRegularExpression

Perl 兼容的正则表达式。

  • QSettings

跨平台应用设置存储。

  • QStandardPaths

返回标准目录路径。

  • QDebug

调试输出工具。

  • QCalendar

支持多种日历系统。

  • QDeadlineTimer

截止时间管理。

你可能感兴趣的:(qt,QtCore,Qt事件系统,QMetaObject元对象)