每天研究一个Qt类之QApplication

前言

创建Qt App项目的时候,我们总能在main函数里面见到
在这里插入图片描述
正好最近想写博客,所以正好去研究一下这个类的源码

正文

这里可以看到它继承自QGuiApplication,而QGuiApplication又继承自QCoreApplication
在这里插入图片描述
这里是它的属性
在这里插入图片描述

剩下的我就挑一些重要的来说

notify()

它是一个虚函数,重载了QGuiApplication中的notify函数

1. 作用
  • notify 函数负责将事件(如鼠标点击、键盘输入、窗口大小改变等)分发给对应的接收对象(通常是 QObject 或其子类)。当一个事件发生时,Qt 框架会通过 QApplication::notify 将该事件传递给目标对象。
2. 函数原型
virtual bool notify(QObject *receiver, QEvent *event) override;
  • receiver:这是指向事件的目标对象的指针,即事件的接收者。
  • event:这是指向要发送的事件的指针。
3. 返回值
  • 返回 true 表示事件已被处理。
  • 返回 false 表示事件未被处理,通常意味着事件会继续被传递给其他可能的处理者,或者被忽略。
4. 典型用途
  • 事件拦截和自定义处理:通过继承 QApplication 并重写 notify 方法,可以在事件分发之前拦截事件,做一些自定义处理。例如,你可以在应用程序中实现全局的事件过滤、日志记录、异常捕获、调试信息输出等。

    class MyApplication : public QApplication
    {
    public:
        MyApplication(int &argc, char **argv)
            : QApplication(argc, argv) {}
    
        bool notify(QObject *receiver, QEvent *event) override
        {
            // 处理或记录事件
            if (event->type() == QEvent::MouseButtonPress) {
                qDebug() << "Mouse button pressed!";
            }
    
            // 调用基类的 notify 方法,继续正常的事件分发
            return QApplication::notify(receiver, event);
        }
    };
    
  • 全局异常处理:可以在 notify 函数中捕获异常,防止程序因为未捕获的异常而崩溃。这样可以增加程序的稳定性和健壮性。

    bool MyApplication::notify(QObject *receiver, QEvent *event) {
        try {
            return QApplication::notify(receiver, event);
        } catch (std::exception &e) {
            qCritical() << "Exception caught:" << e.what();
            return false;
        }
    }
    
5. 注意事项
  • 性能影响:因为 notify 是事件处理的核心函数,重写时应谨慎处理,避免引入大量计算或复杂逻辑,这可能会影响整个应用程序的性能。

  • 调用基类方法:在重写 notify 函数时,通常需要调用基类的 QApplication::notify 方法,以确保事件能够被正常分发到目标对象,除非你有特殊需要阻止事件的传递。

  • 线程安全notify 可能会在多个线程中被调用,因此在重写 notify 时,确保代码是线程安全的。

exec()

int QApplication::exec()QApplication 类的一个成员函数,它是启动 Qt 事件循环的核心函数。exec() 函数将阻塞,直到应用程序退出为止,因此通常是应用程序的最后一个函数调用。

1. 作用
  • exec() 函数启动了 Qt 的事件循环。这意味着在调用此函数后,应用程序将开始处理各种事件,如用户输入、窗口事件、定时器事件等。
  • 事件循环一直运行,直到应用程序调用 QApplication::quit() 或关闭所有窗口。
2. 函数原型
int exec();
3. 返回值
  • exec() 的返回值是一个整数,通常表示应用程序的退出状态。返回的整数值通常是从 QApplication::quit(int returnCode) 中的 returnCode 参数传递的。如果没有明确指定,通常会返回 0,表示正常退出。
4. 使用示例
#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    QPushButton button("Hello, World!");
    button.show();
    
    return app.exec();  // 启动事件循环
}

在这个例子中,app.exec() 会启动事件循环,使按钮能够响应用户的点击事件。当用户关闭窗口或应用程序时,事件循环将结束,并返回一个退出状态码。

5. 内部机制
  • 事件循环:当 exec() 被调用时,它会进入一个无限循环,等待和分发来自操作系统的事件,例如鼠标点击、键盘输入和窗口管理事件。事件循环会不断检查事件队列,并将事件分发到目标对象进行处理。

  • 退出条件:事件循环通常会在以下情况下退出:

    • 调用了 QApplication::quit()
    • 所有的顶级窗口(例如主窗口)都被关闭时,默认情况下也会退出事件循环。
6. 注意事项
  • 阻塞操作exec() 函数是一个阻塞函数,这意味着在调用它之后,控制权不会返回,直到事件循环退出。这就是为什么 exec() 通常是 main() 函数中的最后一个调用。

  • 单实例:在一个应用程序中,通常只能有一个 QApplication 实例,且只能调用一次 exec() 函数。

7. 总结

int QApplication::exec() 是启动 Qt 应用程序事件循环的核心函数。通过调用它,应用程序开始处理用户交互、定时器事件和其他系统事件。它是 Qt 应用程序的核心运行机制,确保 GUI 界面能够正常工作和响应。

qApp

qApp竟然是个宏,你敢信?不看帮助文档是真的不知道
用于访问当前正在运行的 QApplicationQGuiApplication 唯一对象的全局指针。它相当于 QCoreApplication::instance (),它允许方便地访问应用程序对象而无需显式地传递指针。

#define qApp QCoreApplication::instance()
qApp 的用法和示例

通常在 Qt 应用程序中,你可以使用 qApp 来执行与应用程序全局状态相关的操作。例如:

#include <QApplication>
#include <QMessageBox>

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

    // 使用 qApp 访问 QApplication 对象
    QMessageBox::information(nullptr, "App Info", QString("Application Name: %1").arg(qApp->applicationName()));
    
    return qApp->exec();
}

在这个例子中,qApp 被用来访问 QApplication 对象并获取应用程序的名称。

qApp 的介绍
  • qApp 是一个宏,它实际上是对 QApplication::instance() 的简写。
  • 它返回指向当前 QApplicationQGuiApplication 对象的指针。在 Qt 应用程序的任何地方,只要需要访问应用程序对象,都可以使用 qApp
  • 由于 qApp 是一个全局宏,因此它可以在应用程序的任何地方使用,而不需要显式地传递 QApplication 对象的指针。
注意事项
  • 只有在 GUI 应用程序中创建了 QApplicationQGuiApplication 对象后,qApp 才能使用。否则,使用 qApp 可能会导致访问空指针的错误。
  • 对于非 GUI 应用程序(如控制台应用程序),应使用 QCoreApplication,此时 qApp 也可以指向 QCoreApplication 对象。

quit()与exit()

我们在 Qt 应用程序中,在关闭程序的时候可以通过 QApplication 提供的 exit()quit() 方法来退出应用程,也经常在别人的代码中看到运用。这两个方法都是QCoreApplication的函数,QApplication 只是继承了这些函数

1. QApplication::exit(int returnCode = 0)

exit() 方法用于终止应用程序的事件循环,并返回一个整数值作为退出代码。默认情况下,返回代码为 0,表示正常退出。

#include <QApplication>
#include <QPushButton>

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

    QPushButton button("Exit Application");
    QObject::connect(&button, &QPushButton::clicked, [&]() {
    	// 终止事件循环并返回0
    	// 本质上和QCoreApplication::exit(0)一样
        QApplication::exit(0); 
    });
    button.show();

    return app.exec();
}
2. QApplication::quit()

quit() 方法相对简单,它实际上调用了 exit(0),即终止事件循环并返回 0 作为退出代码。

#include <QApplication>
#include <QPushButton>

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

    QPushButton button("Quit Application");
    QObject::connect(&button, &QPushButton::clicked, &QApplication::quit); // 终止事件循环并返回0
    button.show();

    return app.exec();
}
区别
  • exit(int returnCode):允许你指定返回代码,这对于需要传递退出状态的应用程序比较有用。
  • quit():等同于 exit(0),更简洁,当你不需要指定退出代码时可以使用它。
调用时机

无论使用 exit() 还是 quit(),都只能在 QApplication::exec() 已经启动并正在运行事件循环时调用,否则不会有任何效果。

注意事项
  • quit()exit() 会退出事件循环,但它们不会立即终止应用程序,而是会等待所有的事件处理完毕后再退出。
  • 在某些情况下,调用 quit()exit() 后,可能需要进行一些清理工作,这时可以连接到 QApplication::aboutToQuit() 信号进行处理。
QObject::connect(&app, &QApplication::aboutToQuit, [](){
    // 在应用程序退出前执行一些清理操作
    qDebug() << "Application is about to quit!";
});

这种方式确保了在应用程序退出之前,有机会执行任何必要的清理工作。

题外话

QApplicationQGuiApplication, QCoreApplication

  • QCoreApplication

    • 是所有 Qt 程序的基础类,处理非图形用户界面的应用程序的主控制流和设置。
    • 适用于没有图形界面的应用程序。
  • QGuiApplication

    • 继承自 QCoreApplication,用于处理有图形用户界面的应用程序,但不涉及小部件 (widgets)。
    • 适用于不使用 QWidget 的 GUI 应用程序。
  • QApplication

    • 继承自 QGuiApplication,是所有涉及 QWidget 的应用程序的主类。
    • 适用于需要图形用户界面的小部件应用程序。

注意事项

  • 唯一实例:一个应用程序中只能有一个 QApplication 实例。多次创建 QApplication 对象会导致应用程序的异常行为。

  • 事件处理:所有用户事件(如按键、鼠标点击等)都通过 QApplication 进行处理。如果没有进入事件循环(即未调用 exec()),用户界面将不会响应用户输入。

  • 资源管理QApplication 负责全局资源(如字体、样式)的管理,这些资源在 QApplication 对象销毁时会被自动清理。

通过 QApplication 的合理使用,可以有效管理 Qt 应用程序的主流程和资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值