QML简介

QML与Qt程序

Qt Declarative UI运行环境

QML文档通过QML运行环境载入并运行. 包含Declarative UI引擎和内置的QML元素, 插件模块, 还提供了访问第三方的QML元素与模块.

QML与Qt

单纯使用QML可以不了解Qt, 但是如果想设计一个数据逻辑和UI分开的结构, 则需要用到Qt;

QML可直接访问的Qt类:

QAction, signal and slot(can be used as function in JavaScript),

QWidget--QDeclarativeView(Qt5使用QQuickView代替, 属于QWindow, 不用QWidget),

Qt Model--QAbstractItemModel

QML Tools

查看和调试QML的工具: qmlviewer

command: qmlviewer.exe filename.qml

将C++类注册成为QML类型

1
2
#include <QtQml>      
qmlRegisterType<MySliderItem>( "com.mycompany.qmlcomponents" , 1, 0,  "Slider" );

使用:

1
2
3
4
import com.mycompany.qmlcomponents 1.0      
Slider {      
     // ...      
}

以C++类创建QML属性

1)inherited from QObject

2)declarate the Marco: Q_OBJECT(meta system), Q_PROPERTY(QML property)

Declarative UI

QDeclarativeView加载QML文件

QDeclarativeView是一个QWidget(QAbstractScrollArea), 可以加载QML文件;

1
2
3
QDeclarativeView view;      
view.setSource(QUrl::fromLocalFile( "app.qml" ));      
view.show();

PRO工程文件

1
QT += gui declarative

QDeclarativeEngine

可以直接加载QML, 创建QObject来进行操作;
每个程序至少需要一个Engine, 可以配置全局设置应用到所有的QML组件中;

QDeclarativeEngine: 提供了一个实例化QML Component的环境;
QDeclarativeComponent: 封装QML Component的一个类;
QDeclarativeContext: 定义了一个通过QML engine工作的context, 可以将数据暴露给QML component;

1
2
3
4
QDeclarativeEngine engine;
QDeclarativeContext *windowContext =  new  QDeclarativeContext(engine.rootContext());
QDeclarativeComponent component(&engine,  "application.qml" );
QObject *window = component.create(windowContext);

Note 对于shadow build, qml文件需要放到build路径中;

加上数据

>背景颜色

1
2
3
QDeclarativeContext *context = view.rootContext();
context->setContextProperty( "backgroundColor" ,QColor(Qt::yellow));
view.setSource(QUrl::fromLocalFile( "main.qml" ));

当不需要QDeclarativeView显示组件时, 可以使用QDeclarativeEngine::rootContext()代替

1
QDeclarativeContext *windowContext =  new  QDeclarativeContext(engine.rootContext());

QDeclarativeContexts是树形结构, 除了root context每个QDeclarativeContexts都有一个父级, 子级QDeclarativeContexts继承父级的context属性.
这样应用程序分隔不同数据导出到不同的QML对象实例有更多自由性.

结构化数据

除了QVariant支持内置数据类型外, QObject的派生类型也可以分配给context;

1
2
3
4
5
6
7
class  CustomPalette :  public  QObject{
     Q_OBJECT
     Q_PROPERTY(QColor background READ background WRITE setBackground NOTIFY backgroundChanged)
     Q_PROPERTY(QColor text READ text WRITE setText NOTIFY textChanged)
...}
//...
view.rootContext()->setContextProperty( "palette" new  CustomPalette);

在QML中;

1
2
Rectangle {
color: palette.background }

在属性改变时, Notify信号会被发出;(需要实现Notify, 在发出信号时注意判断值是否改变)

QML调用C++

public slots或者Q_INVOKEABLE模式下的函数可以被QObject调用;

QML支持的返回值类型: bool; unsigned int, int; float, double, qreal; QString; QUrl; QColor; QDate,QTime,QDateTime; QPoint,QPointF; QSize,QSizeF; QRect,QRectF; QVariant;

1
2
3
4
Q_INVOKABLE  bool  isRunning()  const ;
public  slots:
     void  start();
     void  stop();

作为context导入QML;

1
view.rootContext()->setContextProperty( "stopwatch" , new  Stopwatch);

QML中使用;

1
2
3
4
5
6
onClicked: {
if  (stopwatch.isRunning())
     stopwatch.stop()
else
     stopwatch.start();
}

更有效率的写法:

1
onClicked: stopwatch.running = !stopwatch.running

网络组件

如果QML或图片等是网络资源, QDeclarativeComponent要先获取网络数据, 才可以创建对象.

QDeclarativeComponent::statusChanged()和continueLoading(), 还需要防止组件是缓存中保存的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MyApplication::MyApplication()
{
// ...
     component =  new  QDeclarativeComponent(engine, QUrl( "http://www.example.com/main.qml" ));
if  (component->isLoading())
     QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),  this , SLOT(continueLoading()));
else
     continueLoading();
}
void  MyApplication::continueLoading()
{
if  (component->isError()) {
     qWarning() << component->errors();
}
else  {
     QObject *myObject = component->create();
}
}

Qt资源

qrc是XML格式的文件, 会被rcc工具编译成object文件, 链接到动态库(shared library)中;

格式

1
2
3
4
5
6
7
<!DOCTYPE RCC>
<RCC version= "1.0" >
<qresource prefix= "/mainPage" >
<file>main.qml</file>
<file alias =  "images_bkg.png"  >images/background.png</file>
</qresource>
</RCC>

prefix是内置前缀, 不是实际目录名; alias可以帮助程序员将代码改动限制在qrc内;

1
view.setSource(QUrl( "qrc:/mainPage/main.qml" ));

QML使用:

1
2
3
Image {
     source:  "images_bkg.png" //"images/background.png"
}

Note prefix会被带入到qml内的资源搜索路径中, 定义时需注意;
系统资源不能从QML直接访问, 当QML文件被加载作为资源, 所有的文件指定在QML作为相对路径从系统资源载入.
这种情况下在QML层访问系统资源是完全透明的. 但是当QML文件没有被加载作为资源, QML就无法访问系统资源;

---End---


QML与Qt整合

基于QWidget用户界面(把基于QWidget的程序导向QML不是个好主意)

QDeclaractiveView是QWidget的子类;

1
2
3
4
5
QDeclarativeView *qmlView =  new  QDeclarativeView;
qmlView->setSource(QUrl::fromLocalFile( "myqml.qml" ));
QWidget *widget = myExistingWidget();
QVBoxLayout *layout =  new  QVBoxLayout(widget);
widget->addWidget(qmlView);

>缺点 QdeclarativeView初始化慢, 比QWidget占用更大内存, 如果创建大量QDeclarativeView对象会导致性能下降;
这种情况下需要用QML重写QWidget, 从主QML部件载入qml来代替QDeclarativeView;

QWidget UI是复杂的并且由少数静态页面组成的情况;
QML UI是简单的并且由大量动态元素组成的情况;

基于QGraphicsView的UI

添加QML部件到一个QGraphicsScene; Graphics View Framework;

1
2
3
4
5
QGraphicsScene* scene = myExistingGraphicsScene();
QDeclarativeEngine *engine =  new  QDeclarativeEngine;
QDeclarativeComponent component(engine, QUrl::fromLocalFile( "myqml.qml" ));
QGraphicsObject *object = qobject_cast<QGraphicsObject *>(component.create());
scene->addItem(object);

>使用QDeclarativeComponent创建QGraphicsObject, QGraphicsScene::addItem()放置图形;

Performance选项

QGraphicsView::setOptimizationFlags(QGraphicsView::DontSavePainterState)

QGraphicsView::setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate)

QGraphicsScene::setItemIndexMethod(QGraphicsScene::NoIndex)

QML载入QGraphicsWidget对象

使用qmlRegisterType();

C++写QML扩展

QtDeclarative模块提供API以便C++扩展QML; 添加QML类型, 扩展现有Qt, QML类型, 调用C++函数;

Tips

内置类型的转换: QColor - 字符串"red", QSize - 字符串 800*600

继承自QDeclarativeItem, 覆盖paint()方法; 使用setParentItem()方法指定父级;

qmlRegisterType()注册新的QML类型;

Q_INVOKABLE 声明的方法可以被Qt metaObject系统和QML使用, slot函数也拥有相似的特性;

Qt::transparent可以将颜色变为透明; 

使用update()方法引发repaint;

Q_ENUMS导出枚举类型;

列表属性类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Q_PROPERTY(QDeclarativeListProperty<PieSlice> slices READ slices)
QDeclarativeListProperty<PieSlice> slices();
static void append_slice(QDeclarativeListProperty<PieSlice> *list, PieSlice *slice);
//...
QDeclarativeListProperty<PieSlice> PieChart::slices()
{
     return  QDeclarativeListProperty<PieSlice>( this , 0, &PieChart::append_slice);
}
void PieChart::append_slice(QDeclarativeListProperty<PieSlice> *list, PieSlice *slice)
{
     PieChart *chart = qobject_cast<PieChart *>(list->object);
     if  (chart) {
         slice->setParentItem(chart);
         chart->m_slices.append(slice);
     }
}

QML

1
2
3
4
5
6
7
8
9
10
11
slices: [
PieSlice {
     anchors.fill: parent
     color:  "red"
     fromAngle: 0; angleSpan: 110
},
PieSlice {
     anchors.fill: parent
     color:  "black"
     fromAngle: 110; angleSpan: 50}
]

插件Plugin 

作为QDeclarativeExtensionPlugin子类; Q_EXPORT_PLUGIN2宏定义;
工程文件: 

1
CONFIG += qt plugin;

qmldir文件会被自动解析, 通知插件引擎载入; 

1
plugin project-plugins lib

---End---


refer to <QtQuick 中文手册>

你可能感兴趣的:(QML简介)