其实从最开始要学习和分析Qt的Demo时选定的就是calqlatr工程,但是打开源码一看,貌似难度高了点,这才有了上面的几篇基本控件的分析。从这一章开始,我要拿下calqlatr这个Demo项目了。
main.cpp
main.cpp中的代码非常简单:
#include "../../shared/shared.h" DECLARATIVE_EXAMPLE_MAIN(demos/calqlatr/calqlatr)
DECLARATIVE_EXAMPLE_MAIN(NAME)是一个函数宏,其具体实现是在"../../shared/shared.h"头文件中。
其实在之前分析的Demo中也有使用到这个函数宏,只不过当时重点在分析QML代码上,没有对DECLARATIVE_EXAMPLE_MAIN(NAME)函数宏详细展开。这篇文章中就把它详细解开。
#define DECLARATIVE_EXAMPLE_MAIN(NAME) int main(int argc, char* argv[]) { QGuiApplication app(argc,argv); app.setOrganizationName("Qt Project"); app.setOrganizationDomain("qt-project.org"); app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName()); QQuickView view; if (qgetenv("QT_QUICK_CORE_PROFILE").toInt()) { QSurfaceFormat f = view.format(); f.setProfile(QSurfaceFormat::CoreProfile); f.setVersion(4, 4); view.setFormat(f); } view.connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit())); new QQmlFileSelector(view.engine(), &view); view.setSource(QUrl("qrc:///" #NAME ".qml")); view.setResizeMode(QQuickView::SizeRootObjectToView); if (QGuiApplication::platformName() == QLatin1String("qnx") || QGuiApplication::platformName() == QLatin1String("eglfs")) { view.showFullScreen(); } else { view.show(); } return app.exec();}
从宏的实现可以清洗的看出,实际上是一个通用的main()函数实现。
这个main()和我们之前在分析Window Demo程序时的main()函数基本结构都是一致的,但是也有区别之处:在Window的Demo中使用的是QQmlComponent,在这里使用的是QQuickView。
QGuiApplication app
因为这里要创建的是GUI程序,故使用QGuiApplication。但是和之前Window Demo程序时的main()函数中的使用多了以下三行:
app.setOrganizationName("Qt Project"); app.setOrganizationDomain("qt-project.org"); app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName());\
先看一下organizationName和organizationDomain这两个属性的官方说明:
organizationName : QString
This property holds the name of the organization that wrote this application.
The value is used by the QSettings class when it is constructed using the empty constructor.
organizationDomain : QString
This property holds the Internet domain of the organization that wrote this application.
The value is used by the QSettings class when it is constructed using the empty constructor.
看到这里,我们知道organizationName和organizationDomain这两个属性实际上是在QSettings或者其他需要显示app的organizationName和organizationDomain时使用的。
同理,applicationName属性也是在QSettings或其他需要显示app的Name时使用,这里需要明确指出的是,app的title默认值就是使用applicationName的值。
QQuickView view
The QQuickView class provides a window for displaying a Qt Quick user interface.
This is a convenience subclass of QQuickWindow which will automatically load and display a QML scene when given the URL of the main source file. Alternatively, you can instantiate your own objects using QQmlComponent and place them in a manually setup QQuickWindow.
从上面的官方说明上可以看出,QQuickView类是QQuickWindow类的子类,是一种方便的创建Window的方法,不过相对于QQuickWindow还需要使用QQmlComponent来加载Qml的方法,QQuickView则是直接扩展了setSource方法,下面是一个示例:
QQuickView *view = new QQuickView; view->setSource(QUrl::fromLocalFile("myqmlfile.qml")); view->show();
在这里也是通过setSource来指定需要加载的qml文件:
view.setSource(QUrl("qrc:///" #NAME ".qml")); \
上面的#NAME就是DECLARATIVE_EXAMPLE_MAIN(NAME)函数宏的参数。
view.setResizeMode()
代码中设置了resize模式:
view.setResizeMode(QQuickView::SizeRootObjectToView);\
从官方文档来看,有两种resize模式,分别是:
- QQuickView::SizeViewToRootObject: The view resizes with the root item in the QML.
- QQuickView::SizeRootObjectToView: The view will automatically resize the root item to the size of the view.
但是从名字来看,这两个模式一个是从View到RootObject,一个是从RootObject到View,具体什么时候该用哪一个呢?这里的说明比较简单,看一下Detailed Description部分的详细说明:
QQuickView also manages sizing of the view and root object. By default, the resizeMode is SizeViewToRootObject, which will load the component and resize it to the size of the view. Alternatively the resizeMode may be set to SizeRootObjectToView which
will resize the view to the size of the root object.
那么我们可以简单的理解,就是如何自动调节root object和view的大小,只不过这里对于所谓的root object具体是何物,没有详细解释。此处暂留一个TODO:SizeViewToRootObject和SizeRootObjectToView的区别和如何使用它们。
view.show()
在设置完view的属性之后,就可以显示view了,在示例中使用下述代码来显示view:
if (QGuiApplication::platformName() == QLatin1String("qnx") || QGuiApplication::platformName() == QLatin1String("eglfs")) { view.showFullScreen(); } else { view.show(); }\
注意,这里提到了QGuiApplication::platformName(),上面判断的qnx和eglfs对于我们来说比较陌生,但是通过查看文档我们了解到QGuiApplication::platformName()还包括一下几种:
- android
- cocoa is a platform plugin for Mac OS X.
- windows
- ios
- xcb is the X11 plugin used on regular desktop Linux platforms.
- ...
那么我们就可以很方便的判断当前平台是否是OS X、Linux、Window以及Android、IOS等等,至于哪些不常见的一些平台,对于我来讲能力有限不能展开。
在获取了平台信息之后,就可以选择如何显示view了,示例中针对qnx和eglfs进行了全屏显示,其他都是采用平台默认的显示方式。除了上面两种显示方式,还有下面的一些函数用来指定如何显示:
- show(): Shows the window, depending on the platform‘s default behavior for the window type and flags.
- showFullScreen(): Shows the window as fullscreen.
- showMaximized(): Shows the window as maximized.
- showMinimized(): Shows the window as minimized.
- showNormal(): Shows the window as normal, i.e. neither maximized, minimized, nor fullscreen.
QSurfaceFormat
在创建完view之后,还有下述的一段代码:
if (qgetenv("QT_QUICK_CORE_PROFILE").toInt()) { QSurfaceFormat f = view.format(); f.setProfile(QSurfaceFormat::CoreProfile); f.setVersion(4, 4); view.setFormat(f); }\
通过添加打印,发现这里的if根本没有执行到,而且全局搜索QT_QUICK_CORE_PROFILE也没有找到其他有定义该env的地方,故暂不对该部分代码进行分析。
总结
这一章只是把几乎每个Demo工程中都会见到的DECLARATIVE_EXAMPLE_MAIN(NAME)函数宏详细分析了一下。从下一章开始,进入到calqlatr的qml代码中。