Qt的QApplication不简单!

描述

一、导读

把焦点回到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[])
{
    QScopedPointer app(createApplication(argc, argv));

    if (qobject_cast(app.data())) {
        // start GUI version...
    } else {
        // start non-GUI version...
    }
    
    return app->exec();
}

 

上述代码演示了如何动态创建适当类型的应用程序,小生从上述代码get到一招和五个知识点......,打住,再写就跑题了。

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分