Qt Quick杂记
一、简介
QtQuick 是Qt 提供的一种高级用户界面技术,使用它可轻松地为移动和嵌入式设备创建流畅的用户界面。QtQuick本身主要包含了QML、JavaScript、Qt C++三种技术。
QML是对 JavaScript 的一种扩展,是一种说明性语言,用来描述基于Qt对象系统的用户界面。QML的主要作用我理解就是将界面设计与程序逻辑解耦,通常来说前端需求的变动远超过后台逻辑,因此界面与逻辑分离不仅有利于开发人员之间的分工,也提供了更快速的迭代速度的可能性,也会大大降低程序的后期维护成本。QML和JavaScript主导UI的创建,后台图形绘制采用C++。高效,灵活,可扩展性强。Qt Quick 作为 QML 的标准库,提供了很多基本元素和控件来帮助我们构建Qt Quick 应用。如果拿C++ 来比拟, QML 就相当于C++ 语言本身,而 Qt Quick 相当于 STL 。
要使用QML进行界面的布局,首先需要理解QML元素的层次结构。QML的层次结构很简单,是一个树形结构,最外层必须有一个根元素,根元素里面可以嵌套一个或多个子元素,子元素里面还可以包含子元素。QML的坐标系采用的屏幕坐标系,原点在屏幕左上角,x轴从左向右增大,y轴从上到下增大,z轴从屏幕向外增大。子元素从父元素上继承了坐标系统,它的x,y总是相对于它的父元素坐标系。
复杂的应用,使用QML 快速构建界面,使用 C++ 完成关键算法和逻辑。
二、属性
对象要用一对花括号来描述,在花括号之间,是对象的属性描述。属性是以"property:value" 形式指定的。qml中的 property 的作用是动态为对象添加属性,并且添加的属性可以进行跟踪(值被修改了就会发出信号)。
FullFeatureId
var vals=fullFeatureId.split("_");
if (vals.length== 3)
{
updateRegion=vals[0];
tileID=vals[1];
featureID=vals[2];
}
propertystring fullFeatureId:""//这是一个属性
属性自带一个信号就是属性变化会触发一个信号,它的槽只要写成
onFullFeatureIdChanged: {
}就可以啦。
importQtQuick.Controls1.2 包括Button。
其实,QML 中的属性,就是我们非常熟悉的 C++中的成员变量
2.1 id 属性
一个对象的id 属性是唯一的,在同一个QML 文件中不同对象的 id 属性的值不能重复。当给一个对象指定了id ,就可以在其它对象或脚本中通过id 来引用该对象。首字符必须是小写字母或下划线并且不能包含字母、数字、下划线以外的字符。
2.2 信号处理器
它的名字还有点儿特别,一般是on{Signal}这种形式,就这么简单,以on 起始后跟信号名字(第一个字母大写)。
e.g
onClicked: {
Qt.quit();
}
最后说下Keys对象,它是 Qt Quick 提供的,专门供 Item 处理按键事件的对象。
因为QML 中所有的可视化元素都继承自Item ,而Item 则定义了一些基本的、通用的属性和方法。
QML 中的Item 元素与C++ 中的 QQuickItem类对应
Rectangle 元素对应于QQuickRectangle类。
信号处理器,其实等价于Qt 中的槽。但是我们没有看到类似C++ 中的明确定义的函数……没错,就是这样,你的的确确只看到了一对花括号!对啦,这是JavaScript 中的代码块。其实呢,你可以理解为它是一个匿名函数。函数的好处是你可以在其它地方根据名字调用它,而代码块的好处是,除了定义它的地方,没人能调用它。还有一种情况,要处理的信号不是当前元素发出来的,而是来自其它类型(对象)比如处理按键的Keys ,这就是附加信号处理器。
2.3 其它
怎么找QML 类型对应的 C++ 类型呢?很简单,只需要使用Component.onCompleted附加信号,在附加信号处理器中输出类型信息即可。
三、在 QML 中使用C++ 类和对象
3.1实现可以导出的 C++ 类
http://blog.youkuaiyun.com/foruok/article/details/32698603
前提条件
要想将一个类或对象导出到QML中,下列前提条件必须满足:
- 从 QObject 或 QObject 的派生类继承
- 使用 Q_OBJECT 宏
Qt提供了3种在QML 环境中使用 C++ 对象的方式:
3.1.1通过各种宏
只要是信号或者槽,都可以在QML 中访问。一旦你使用 Q_INVOKABLE 将某个方法注册到元对象系统中,在QML 中就可以用${Object}.${method} 来访问。如果你要导出的类定义了想在QML中使用枚举类型,可以使用Q_ENUMS 宏将该枚举注册到元对象系统中。一旦你使用Q_ENUMS 宏注册了你的枚举类型,在QML 中就可以用 ${CLASS_NAME}.${ENUM_VALUE}的形式来访问。Q_PROPERTY 宏用来定义可通过元对象系统访问的属性,通过它定义的属性,可以在QML中访问、修改,也可以在属性变化时发射特定的信号。
class ImageProcessor : public QObject
{
Q_OBJECT
Q_ENUMS(ImageAlgorithm)//枚举
Q_PROPERTY(QStringsourceFile READsourceFile)//成员变量及读其的成员函数
Q_PROPERTY(ImageAlgorithmalgorithmREADalgorithm)
public:
ImageProcessor(QObject*parent = 0);
~ImageProcessor();
enumImageAlgorithm{
Gray = 0,
Binarize,
Negative,
Emboss,
Sharpen,
Soften,
AlgorithmCount
};
QStringsourceFile() const;
ImageAlgorithmalgorithm() const;
signals: 也可以使用
void finished(QString newFile);
void progress(int value);
public slots: 也可以使用
void process(QString file,ImageAlgorithmalgorithm);
void abort(QString file,ImageAlgorithmalgorithm);
void abortAll();
};
那么在qml中就可以直接定义该类
ImageProcessor {
id: processor;
onFinished: {
imageViewer.source="file:///" +newFile;
}
}
可以使用该类的sourceFile()、algorithm()和信号和槽
processor.process(fileDialog.fileUrl,ImageProcessor.Soften);
3.1.2在 C++ 中实现一个类,注册到QML 环境中, QML 环境中使用该类型创建对象
要注册一个QML 类型,有多种方法可用,如qmlRegisterSingletonType()用来注册一个单例类型, qmlRegisterType()注册一个非单例的类型,qmlRegisterTypeNotAvailable()注册一个类型用来占位,qmlRegisterUncreatableType()通常用来注册一个具有附加属性的附加类型。
一旦你在C++ 中注册好了 QML 类型,就可以在 QML 文档中引入你注册的包,然后使用注册的类型。要引入包,使用import 语句。引入包后,你就可以在QML 中创建 C++ 导入类型的对象了,与 QML 内建类型的使用完全一样。
qmlRegisterType<ColorMaker>("an.qt.ColorMaker", 1, 0, "ColorMaker");
"an.qt.ColorMaker":包名
主版本为1 ,次版本为 0
"ColorMaker"则是 QML 中可以使用的类名。
import an.qt.ColorMaker 1.
3.1.3 在 C++ 中构造一个对象,将这个对象设置为 QML 的上下文属性,在 QML 环境中直接使用改属性
你还可以把C++中创建的对象作为属性传递到QML环境中,然后在QML环境中访问。viewer.rootContext()->setContextProperty("colorMaker", new ColorMaker);
正式这行代码从堆上分配了一个ColorMaker 对象,然后注册为QML 上下文的属性,起了个名字就叫colorMaker。一旦调用setContextProperty() 导出了属性,就可以在QML 中使用了,不需要 import 语句哦。
QQmlContext::setContextProperty()
在C++应用程序加载QML对象时,我们可以直接嵌入一些C++数据来给QML使用。
int main(int argc,char *argv[])
{
QGuiApplicationapp(argc, argv);
QQuickViewview;
Gemini gemini;
view.rootContext()->setContextProperty("gemini",&gemini);
view.setSource(QUrl(QStringLiteral("qrc:///main.qml")));
view.show();
returnapp.exec();
}