一、导读
把焦点回到Qt应用开发中,一般情况下,Qt应用程序的本体由main.cpp文件中的main()函数中内容描述:
#include#include "mainwindow.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow window; window.show(); return app.exec(); }
在上述代码中,创建了一个QApplication实例和MainWindow实例,MainWindow实例表示主窗体应用,QApplication正是本文的描述对象,她是QWidget的“地基”。QApplication是专门的QGuiApplication,它具有一些基于QWidget应用程序需要的功能:处理小部件特定的初始化和销毁操作。文档中对她是这样描述的:
该类继承自QGuiApplication类,文档中对QGuiApplication是这样描述的:
从上图可知,QGuiApplication继承自QCoreApplication,又来看看QCoreApplication类:
从上述描述可知,QApplication、QGuiApplication、QCoreApplication这三个类是“父-子”包含关系,那么在实际开发中,该如何选择呢?
对于任何基于QWidget的GUI应用程序来说(注意是基于QWidget的),无论该应用程序在任何时间有多少个窗口,都只有一个QApplication对象;如果不是基于QWidget的GUI应用程序,应该使用QGuiApplication,例如QtQuick应用,而对于不需要QWidget或者GUI的Qt应用程序来说,应该使用QCoreApplcation,该类不依赖于QtWidgets库。在不需要GUI的应用程序中,使用QCoreApplication,该类可以避免对图形用户界面所需的资源进行不必要的初始化。
二、再谈QApplication
在文本开始处贴出的代码中,main函数传入的参数argc、argv在创建QApplication实例的时候传了进去,因为在QApplication初始过程中需要用argv中的argc命令行参数构造应用程序对象,从源码角度看,在QApplication的构造函数中会进行如下操作:
上图中,Q_D是一个宏定义,用于创建一个指向ApplicationPrivate的指针,定义如下:
#define Q_D(Class) Class##Private * const d = d_func()
ApplicationPrivate类的存在用于描述QApplication的私有数据,她的存在是为了Qt源码而设计的。回到QApplication的构造函数中,最后会调用init(),该函数实现如下(/qtbase/src/widgets/kernel目录中):
void QApplicationPrivate::init() { #if defined(Q_OS_MACOS) QMacAutoReleasePool pool; #endif //初始化QGuiApplication的私有数据。 QGuiApplicationPrivate::init(); //初始化资源。 initResources(); qt_is_gui_used = (application_type != QApplicationPrivate::Tty); //处理命令行参数。 process_cmdline(); // Must be called before initialize() QColormap::initialize(); //初始化QColormap initializeWidgetPalettesFromTheme(); qt_init_tooltip_palette(); //初始化QApplication的私有数据 QApplicationPrivate::initializeWidgetFontHash(); //初始化QApplication对象,重磅函数 initialize(); eventDispatcher->startingUp(); #ifndef QT_NO_ACCESSIBILITY // factory for accessible interfaces for widgets shipped with Qt QAccessible::installFactory(&qAccessibleFactory); #endif }
从源码角度,可以清楚地看到QApplication的构造过程和功能,主要用于初始化与GUI相关的的资源,创建QApplication对象,有如下行为:
(1)使用我们的桌面设置(如palette()、font()和doubleClickInterval())来初始化应用程序。并跟踪这些属性,以防止我们全局地更改桌面,例如:通过某种控制面板。
(2)执行事件处理,它从底层窗口系统接收事件并将它们分派到相关的小部件(可理解成一个事件中转站)。通过使用sendEvent()和postEvent(),可以将自己的事件发送到小部件。
(3)解析常用的命令行参数并相应地设置其内部状态。
(4)定义应用程序的外观,并封装在QStyle对象中。当然可以在运行时使用setStyle()进行更改。
(5)提供了通过translate()创建可见字符串的本地化操作。
(6)提供一些方便快捷的对象,便于在开发中使用,例如desktop()和clipboard()。
(7)管理应用程序的窗口。我们可以使用widgetAt()来询问哪个小部件位于某个位置,获取topLevelWidgets()和closeAllWindows()的列表等。
(8)管理应用程序的鼠标指针处理。
在实际开发中,可以通过instance()函数访问QApplication对象,该函数返回一个与全局qApp指针等价的指针。(qApp引用是应用程序对象的唯一全局指针。它等价于QCoreApplication::instance(),但转换为指向QApplication的指针,因此仅当唯一的应用程序对象是QApplication时才有效),Qt源码中qApp定义如下:
#define qApp (static_cast(QCoreApplication::instance()))
三、结尾
QApplication就像QWidget的地基一样,GUI中的界面控件就如同“砖块”一样码在上面了。
最后,贴出参考文档中给出的一份代码,其实现背后的知识值得学习:
QCoreApplication* createApplication(int &argc, char *argv[]) { for (int i = 1; i < argc; ++i) if (!qstrcmp(argv[i], "-no-gui")) return new QCoreApplication(argc, argv); return new QApplication(argc, argv); } int main(int argc, char* argv[]) { QScopedPointerapp(createApplication(argc, argv)); if (qobject_cast (app.data())) { // start GUI version... } else { // start non-GUI version... } return app->exec(); }
上述代码演示了如何动态创建适当类型的应用程序,小生从上述代码get到一招和五个知识点......,打住,再写就跑题了。
全部0条评论
快来发表一下你的评论吧 !