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 中文手册>