前言
创建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
竟然是个宏,你敢信?不看帮助文档是真的不知道
用于访问当前正在运行的 QApplication
或 QGuiApplication
唯一对象的全局指针。它相当于 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()
的简写。- 它返回指向当前
QApplication
或QGuiApplication
对象的指针。在 Qt 应用程序的任何地方,只要需要访问应用程序对象,都可以使用qApp
。 - 由于
qApp
是一个全局宏,因此它可以在应用程序的任何地方使用,而不需要显式地传递QApplication
对象的指针。
注意事项
- 只有在 GUI 应用程序中创建了
QApplication
或QGuiApplication
对象后,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!";
});
这种方式确保了在应用程序退出之前,有机会执行任何必要的清理工作。
题外话
QApplication
和 QGuiApplication
, QCoreApplication
-
QCoreApplication
:- 是所有 Qt 程序的基础类,处理非图形用户界面的应用程序的主控制流和设置。
- 适用于没有图形界面的应用程序。
-
QGuiApplication
:- 继承自
QCoreApplication
,用于处理有图形用户界面的应用程序,但不涉及小部件 (widgets)。 - 适用于不使用
QWidget
的 GUI 应用程序。
- 继承自
-
QApplication
:- 继承自
QGuiApplication
,是所有涉及QWidget
的应用程序的主类。 - 适用于需要图形用户界面的小部件应用程序。
- 继承自
注意事项
-
唯一实例:一个应用程序中只能有一个
QApplication
实例。多次创建QApplication
对象会导致应用程序的异常行为。 -
事件处理:所有用户事件(如按键、鼠标点击等)都通过
QApplication
进行处理。如果没有进入事件循环(即未调用exec()
),用户界面将不会响应用户输入。 -
资源管理:
QApplication
负责全局资源(如字体、样式)的管理,这些资源在QApplication
对象销毁时会被自动清理。
通过 QApplication
的合理使用,可以有效管理 Qt 应用程序的主流程和资源。