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 <QCoreApplication>
#include <QDebug>
#include <QStringList>
#include <QTimer>

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 <QCoreApplication>
#include <QEventLoop>
#include <QTimer>
#include <QThread>
#include <QSocketNotifier>
#include <QDebug>
#include <unistd.h>

// ======================
// 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(&notifier, &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窗口部件关闭的事件
    QTimerEventQTimer 发出的定时器事件
    QFocusEvent窗口部件获得或失去键盘焦点的事件
    QActionEventQAction 相关的事件(例如,触发)
    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 <QCoreApplication>
#include <QEvent>
#include <QTimer>
#include <QDebug>

// ======================
// 1. 定义自定义事件类型
// ======================
const QEvent::Type CustomEventType = static_cast<QEvent::Type>(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<MyCustomEvent*>(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<QTimerEvent*>(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 <QCoreApplication>
#include <QTimer>
#include <QDebug>

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 <QCoreApplication>
#include <QObject>
#include <QDebug>
#include <QMetaMethod>
#include <QMetaProperty>
#include <QMetaObject>
#include <QMetaEnum>
#include <QTimer>

// ======================
// 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 <QCoreApplication>
#include <QObject>
#include <QMetaObject>
#include <QMetaProperty>
#include <QDebug>
#include <QTimer>

// ======================
// 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 <QCoreApplication>
#include <QObject>
#include <QDebug>

// ======================
// 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<Base*>(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<Derived*>(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<Derived*>(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

截止时间管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旭唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值