Qt Quick 译04 - 针对QT开发者的QML
QML for Qt Programmers
Overview
虽然使用QML不需要Qt的知识,但是在学习和使用QML过程中,如果你熟悉Qt,你的很多知识都与之有直接关系。当然,一个使用QML定义UI的应用程序,也能使用Qt完成所有的非UI方面的逻辑。
Familiar Concepts
对Qt中的下列内容,QML可以直接访问:
- QAction - the action type
- QObject signals and slots - available as functions to call in JavaScript
- QObject properties - available as variables in JavaScript
- QWidget - QDeclarativeView is a QML-displaying widget
- Qt models - used directly in data binding (QAbstractItemModel)
Extending QML in C++和Integrating QML with existing Qt UI code的知识也是必需的。
QML Items compared with QWidgets
QML的项与QWidget里的非常相似:它们都定义了UI的look and feel。(注意虽然QWidget还没有被传统的用来定义view的代理的look and feel,QML的项已经可以做到了。)
QWidget有三种结构上不同的类型:
- 不被作为父亲使用的简单widget (QLabel, QCheckBox, QToolButton, 等等)
- 通常座位其他Widget的父亲的Widgets(QGroupBox, QStackedWidget, QTabWidget, 等等)
- 由内部子Widget租车的那个的复合Widget (QComboBox, QSpinBox, QFileDialog, QTabWidget, 等等)
QML的项也可以达到相同的目标,下面分类讨论:
Simple Widgets
C++中实现一个新的QDeclarativeItem需要记住的最重要的一条是,不能包含任何look and feel的策略——交给QML。
举个例子,假设你需要一个可重用的Button。如果像QToolBox继承QWidget一样,你决定写一个QDeclarativeItem子类来实现这个button,根据上面的条款,你的QDeclarativeButton不会有任何外观——仅有enabled,triggering等其他概念。
但是在Qt里已经有一个对象实现这个了,QAction。
QAction是QPushButton、QCheckBox、QMenu items、QToolBox和其他通常绑定到QAction上的可视widget的UI不可知论的精髓(UI-agnostic essence)。
因此,QML中实现checkbox抽象的工作已经做完了,就是QAction。一个action的look and feel——button的外观、状态之间的变换以及它怎样响应鼠标、按键或者触摸输入,都应该留给QML来定义。
作为例证,我们注意到QDeclarativeTextEdit是建立在QTextControl基础上的,QDeclarativeWebView是建立在QWebPage基础上,ListView用到QAbstractItemModel,正如QTextEidt,QWebView,QListView都建立在它们相同的UI未知的组件上。
QWidget提供的look and feel的封装非常重要,QML中component的概念也为同一个目的而生。如果你正在生成一个具有一致的look and feel的完整的应用程序,你应该生成一套可重用的组件,来实现你想要的look and feel。
Parent Widgets
父widgets提供了一种一般的方式与其他任意一个或多个widget交互。QTabWidget提供了一个多页面的接口,任何时间其中一个页面必是可见的。同时也有一套机制从这些页面中选择一个(QTabBar)。QScrollArea提供了scrollbar,将一个widget包围起来,使其足够显示在可用空间。
几乎所有这样的component都可以在QML中直接创建。只有几种情况下需要很特殊的事件处理,比如Flickable,需要C++来实现。
举例而言,假设你决定制作一个整个应用程序集中都能使用的通用的tab widget item,你知道的信息仅仅是它需要分成多个页面。
作为parent widget,QML相对QWidget而言,一个巨大的不同点在于,当子项相对于parent改变位置的时候,它们不需要完全包含(剪切)在parent中(尽管当需要时,cipped属性允许子项这么做)。这个差异具有颇深渊的影响,例如:
- 环绕在widget周围的阴影或者高亮可以成为这个widget的子项。
- 可以在生成粒子的对象周围产生流动的粒子效果。(Particle effects can flow outside the object where they originate. )
- 过渡动画可以将通过将子项移出屏幕外来隐藏它们。
Compound Widgets
一些widget具有整合其他widget作为实现细节的功能,提供了整合所用到的高层API。QSpinBox是一个line edit,并且有一些button来增加/减少被编辑的值。QFileDialog利用一套众多的widget为用户提供了查找和选择一个文件名的功能。
当开发可重用的QML item时,你可能做出相同的选择:采用组合的方式,使用已经定义好的item生成一个新的item。
这么做需要注意的唯一一点是需要考虑到组合item的用户可能用到的动画和渐变效果。例如,一个spinbox可能需要从一个任意的Text item或者Text item上的字符做平滑的渐变效果,因此你的spinbox需要有很大的灵活性,以支持这种动画效果。
QML Items Compared With QGraphicsWidgets
QML items和QGraphicsWidgets主要的不同点在于我们打算怎样使用它们。技术上的实现细节大致相同,但在实际应用中则另当别论。因为QML items是因陈述或组合用途而生,但QGraphicsWidgets却是为了必要和更综合性的用途。QML items和QGraphicsWidgets都继承自QGraphicsObject,且可以共存。不同点是布局系统和与其他components的交互。注意:QGraphicsWidgets更倾向于作为多合一的packages,一个对等的QGraphicsWidget可能由不同QML文件中的多个QML items组成,但在C++中它仍然可以作为一个单独的QGraphicsObject加载和使用。
QGraphicsWidgets通常使用QGraphicsLayouts来进行布局。由于Qt的布局不能很好的融合动画和流动的UI,所以QML不适用QGraphicsLayouts。因此,几何接口也是一个很大的不同。当写QML 元素时,你得允许设计者使用绝对位置,绑定或者锚点(所有的设置都由你在继承QDeclarativeItem时而定)来放置他们带边界框的矩形,并且你不能使用布局或者size hints。如果有合适的size hints,你要把它们放到QML文档中,以便设计者知道如何最好的使用这个元素,尽管如此,开发者仍然需要对look and feel的完整控制。
另外一个主要的不同是QGraphicsWidget倾向于follow widget model ,这样它们可以成为独立的UI和逻辑包。相对来讲,QML的模型通常只有一个简单的目的,它们自己无法实现一个use case,但是可以组成QML文件中一个Widget的对等物。因此当写QML items时,尽量避免在items中实现UI逻辑或者组合可见元素。相反,要尽量写具有更多通用目的的原型,这样可以在QML中写出look and feel(包含UI逻辑的)。
两种不同都因不同的交互方式而起。同为QGraphicsObject的子类,使用QGraphicsWidget可以更简单地在C++中开发流动的UI,而QDeclarativeItem是在QML中。因此,这个不同基本上要么是暴露的接口,要么是随之而来的items(在QML中,这些items指的是陈述性的原型,但在QGraphicsWidget中没有,因为你需要在子类里自己实现UI逻辑)的设计。
如果你希望同时使用QML和C++写UI,例如为了减轻过渡期,推荐使用QDeclarativeItem的子类(尽管你也可以使用QGraphicsWidgets)。为了在C++中使用起来更简单,让每一个C++组件的根item成为一个LayoutItem,并且为了替换单独的QGraphicsWidgets,应该每次都加载QML(很可能由多个文件组成,并且包含独立的UI和逻辑包)中单独的widgets到你的场景中。