qt quick中qml编程语言 qt quick中qml编程语言 Qt QML 入门 — 使用C++定义QML类型 注册C++类 Qt QML — QML 和 JavaScript 整合 在QML中使用JavaScript 使用JavaScript动态创建QML object JavaScript的运行环境 Qt QML — 调试QML程序 使用Console调试 包含模块的调试 (Debugging module imports) Qt Quick 2 — QML类型(QML Types) 可视类型 (visual types) 可视的实用功能项 (Visual Item Utility) 可视项的生成器 (Visual Item Generation) 可视项的变换 (Visual Item Transformations) 获取用户输入 (User Input) 文本输入的实用工具项 (Text Input Utility) 用户输入事件 (User input events) 位置 (P

原创文章,转载请注明转自 >> Thuai’s blog

文章链接>> http://www.thuai.com/archives/50

Qt QML 入门 — 使用C++定义QML类型


注册C++类

注册可实例化的类型

如果一个C++类继承自QObject,如果需要在QML中使用创建对象,则需要注册为可实例化的QML类型。

使用qmlRegisterType()注册可实例化的QML类型,具体查看qmlRegisterType()的文档说明。

//Message.cpp
class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
    Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
    // ...
};

//main.cpp
#include <QtQml>
...
qmlRegisterType<Message>("com.mycompany.messaging", 1, 0, "Message");
...

//aQmlFile.qml
import com.mycompany.messaging 1.0

Message {
    author: "Amelie"
    creationDate: new Date()
}

注册不实例化的QML类型

1. qmlRegisterType()不带参数 这种方式无法使用引用注册的类型,所以无法在QML中创建对象。

2. qmlRegisterInterface() 这种方式用于注册C++中的虚基类。

3. qmlRegisterUncreatableType()

4. qmlRegisterSingletonType() 这种方法可以注册一个能够在QML中使用的单例类型。

附带属性

在QML语法中有一个附带属性的概念。

这里使用C++自定义QML类型的时候,也可以定义附带属性。

核心的亮点就是

static <AttachedPropertiesType> *qmlAttachedProperties(QObject *object);

QML_DECLARE_TYPEINFO() 中声明 QML_HAS_ATTACHED_PROPERTIES标志

例如:

//Message.cpp
class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
    Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
    // ...
};


//MessageBoardAttachedType.cpp
class MessageBoardAttachedType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool expired READ expired WRITE expired NOTIFY expiredChanged)
public:
    MessageBoardAttachedType(QObject *parent);
    bool expired() const;
    void setExpired(bool expired);
signals:
    void published();
    void expiredChanged();
};

//MessageBoard.cpp
class MessageBoard : public QObject
{
    Q_OBJECT
public:
    static MessageBoard *qmlAttachedProperties(QObject *object)
    {
        return new MessageBoardAttachedType(object);
    }
};
QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES)

//在QML中的使用
Message {
    author: "Amelie"
    creationDate: new Date()

    MessageBoard.expired: creationDate < new Date("January 01, 2015 10:45:00")
    MessageBoard.onPublished: console.log("Message by", author, "has been
published!")
}

//main.cpp
...
Message *msg = someMessageInstance();
MessageBoardAttachedType *attached =
        qobject_cast<MessageBoardAttachedType*>(qmlAttachedPropertiesObject<MessageBoard>(msg));
qDebug() << "Value of MessageBoard.expired:" << attached->expired();
...

MessageBoard这个类中首先实现了static *qmlAttachedProperties(QObject *object),然后又用QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES)声明MessageBoard为附带属性。


水平有限,还请不吝指正!

文章属原创,转载请注明转自>>[Thuai’s blog][http://www.thuai.com]

文章链接>>http://www.thuai.com/archives/154

发表在 QtQt QML 发表回复

Qt QML — QML 和 JavaScript 整合


在QML中使用JavaScript

PRAGAM LIBRARY

C/C++中关键字#pragam,就是指定编译器执行一些特定动作的指令。这里也可以在JavaScript中使用这个关键字,告诉编译器生成一个shared library。

因为在QML component 中如果使用了JavaScript文件,则会每个component都会有 独立的 JavaScript实例 的 copy,但是如果我们不想每个Component都有独立的JavaScript实例呢?这怎么办呢?

这时候就需要在JavaScript文件中使用.pragam library告诉编译器,这个JavaScript文件是可以共享的。

导入JAVASCRIPT

同样也是使用import来导入JavaScript文件到QML文件中使用。

例如:

import "./myJs" as MyJs

这里我使用相对路径来指定js文件,也可以使用绝对路径来指定js文件。为什么这样写呢?其实这就是告诉编译器,需要使用到的qml文件和js文件的目录位置方便引用解析。如此,你可以将QML文件和js文件按照层级关系和不同的作用,分类放置不用放在和main.qml文件同级目录,从而有个清晰的项目文件结构。

在JAVASCRIPT文件中引用其他JAVASCRIPT文件

QtQuick1.x中是不支持,在js文件中引用另外的非无状态js文件的。

QtQuick2.0版本则支持在一个非无状态的js文件中引用另外一个无状态的js文件或者QML模块。

使用.pragam library定义无状态的JavaScript。

使用.imports则可以导入其他js文件和QML模块。

.import TypeNamespace MajorVersion.MinorVersion as Qualifier

使用Qt.include包含其他非无状态的js文件。文档中有这样一个例子,可以很明了的看出如何使用Qt.include

//main.qml
import QtQuick 2.0
import "script.js" as MyScript

Item {
     100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {
            MyScript.showCalculations(10)
            console.log("Call factorial() from QML:",
                MyScript.factorial(10))
        }
    }
}

// script.js
Qt.include("factorial.js")

function showCalculations(value) {
    console.log("Call factorial() from script.js:",
        factorial(value));
}

// factorial.js
function factorial(a) {
    a = parseInt(a);
    if (a <= 0)
        return 1;
    else
        return a * factorial(a - 1);
}

script.js中使用Qt.include来包含factorial.js,而在main.qml文件中只是使用了一个qualifier MyScript就访问了两个js文中定义的function。

使用JavaScript动态创建QML object

动态创建QML object 有两种方式:

  1. 使用Qt.createComponent()

  2. 使用Qt.createQmlObject()

如果你自定义了一个QML组件,则使用Qt.createComponent()动态创建对象会方便一些。方便重用自定义component。

可以参看我的这篇Qt QML– 动态创建QML objects和销毁

JavaScript的运行环境

QML引擎提供的JavaScript运行环境和浏览器提供的JavaScript运行环境是不一样的。QML的运行环境实现了”ECMAScript Language Specification”的标准,支持ECMAScript标准的内建类型和函数,如Object,Array,Math等。关于详细的ECMAScript标准有哪些内建类型,可以参看ECMA-262 第5版的文档。


水平有限,还请不吝指正,谢谢!

文章属原创,转载请注明转自>>Thuai’s blog

文章链接>>http://www.thuai.com/archives/118

发表在 QtQt QML 标签有  发表回复

Qt QML — 调试QML程序


使用Console调试

Log

console.log 打印日志信息

console.debug 打印调试信息

console.info 打印普通信息

console.warn 打印警告信息

console.error 打印错误信息

Assert

就像C++就的assert,判断表达式是否成立。QML中的console.assert在表达式不成立时并不会终止程序,而是会打印出错误的代码位置。

console.assert 断言

Timer

console.time 和 console.timeEnd 用来查看代码运行所花费的时间。

Trace

在JavaScript的函数中加入console.trace()就可以跟踪代码的调用过程,但是只能够跟踪最后的10次调用。

Count

console.count 会打印出代码调用的次数

Profile

JavaScript 函数的性能分析, console.profile 开始,console.profileEnd 结束。

Exception

console.exception 打印出错误信息和堆栈调用信息。


包含模块的调试 (Debugging module imports)

添加环境变量QML_IMPORT_TRACE=1,可以查看import的module是否正确。然后在终端中使用qmlscene命令运行指定的qml文件,终端就会输出import信息。


水平有限,还请不吝指正,谢谢!

原创文章,转载请注明转自>>Thuai’s blog

文章链接>>http://www.thuai.com/archives/123

发表在 QtQt QML 标签有  发表回复

Qt Quick 2 — QML类型(QML Types)


注意: 末尾写了一个2的,表示QtQuick2中才出现的。对于部分新出现的一些类型,我自己也不怎么熟悉,所以暂时不写中文,免得误人子弟就不好了。以后我会再次更新这篇文章。

可视类型 (visual types)

  • Item — QML 基本的试图类型,其他可视类型都是从Item继承来的
  • Rectangle — 矩形区域
  • Image — 图片
  • BorderImage — 边框背景
  • AnimatedImage — 播放一张GIF图片
  • AnimatedSprite — 播放一系列帧动画 2
  • SpriteSequence — 播放一系列帧动画中的部分帧 2
  • Text — 显示文本
  • Window — 显示一个顶层窗口 2

可视的实用功能项 (Visual Item Utility)

  • Accessible — 提供Component的获取性 2
  • Gradient — 渐变
  • GradientStop — 渐变阈值
  • SystemPalette — 系统调色板
  • Screen — 获取设备的屏幕宽高横向参数 2
  • Sprite — 显示特定的Sprite动画 2
  • FontLoader — 字体加载器

可视项的生成器 (Visual Item Generation)

  • Repeater — 能够根据model生成多个可视化的项
  • Loader — QML component动态加载器

可视项的变换 (Visual Item Transformations)

  • Transform — 变形 2
  • Scale — 缩放
  • Rotation — 旋转
  • Translate — 平移

获取用户输入 (User Input)

  • MouseArea — 鼠标区域
  • Keys — 按键
  • KeyNavigation — 导航键 2
  • FocusScope — 焦点区域
  • Flickable — 橡皮筋区域
  • PinchArea — 捏拽区域
  • MultiPointTouchArea — 多点触控区域 2
  • Drag –拖动区域 2
  • DropArea — 掉落区域 2
  • TextInput — 文本输入区域
  • TextEdit — 文本编辑区域

文本输入的实用工具项 (Text Input Utility)

  • IntValidator — 整数校验器
  • DoubleValidator — 双精度浮点校验器
  • RegExpValidator — 正则表达式校验器

用户输入事件 (User input events)

  • TouchPoint — 触摸点击事件 2
  • PinchEvent — 捏拽事件
  • WheelEvent — 鼠标滚轮事件 2
  • MouseEvent — 鼠标点击事件
  • KeyEvent — 按键事件
  • DragEvent — 拖动事件 2

位置 (Positioning)

  • Positioner — Item在scene中的位置信息(附带属性) 2
  • Column — 子对象竖直方向排列
  • Row — 子对象水平方向排列
  • Grid — 子对象按照网格形式排列
  • Flow — 流动
  • LayoutMirroring — 布局镜像(附带属性) 2

状态 (States)

  • State — 状态
  • PropertyChanges — 属性变更
  • StateGroup — 状态组
  • StateChangeScript — 状态变更脚本
  • ParentChange — 父对象变更
  • AnchorChanges — 锚点变更

转变和动画 (Transitions and Animations)

  • Transition — 转变动画
  • ViewTransition — 视图转变 2
  • SequentialAnimation — 串行动画序列
  • ParallelAnimation — 并行动画序列
  • Behavior — 特定属性变化时的行为
  • PropertyAction — 在动画序列中执行属性变更动作
  • SmoothedAnimation — 属性值平滑变化动画
  • SpringAnimation — 弹力动画
  • ScriptAction — 在动画序列中执行脚本(主要用于动画中执行脚本)

与类型相关的动画 (Type-specific Animations)

  • PropertyAnimation — 属性动画
  • NumberAniamtion — 数值动画
  • Vector3dAnimation — Vector3d属性的动画
  • ColorAnimation — color属性的动画
  • RotationAnimation — rotation属性的动画
  • ParentAnimation — parent属性动画
  • AnchorAnimation — anchor属性动画
  • PathAnimation — path动画 2

底层动画 (Lower-level Animation Types)

  • PathInterpolator — path修改器 2
  • AnimationController — 动画控制器 2

路径动画 (Animation paths)

  • Path — 路径
  • PathLine — 路径为直线
  • PathQuad — 路径为二次方程式贝尔曲线
  • PathCubic — 路径为三次方程式贝尔曲线
  • PathArc — 路径为弧线 2
  • PathCurve — 路径为曲线 2
  • PathSvg — SVG 路径 2
  • PathAttribute — 在path中设置属性
  • PathPercent — 修改path中item的间距

数据模型 (Model and Model Data)

  • ListModel
  • ListElement
  • VisualItemModel
  • VisualDataModel
  • VisualDataGroup
  • XmlListModel
  • XmlRole

视图 (Views)

  • ListView
  • GridView
  • PathView
  • Pack age

数据存储 (Data Storage)

  • QtQuick.LocalStorage 2 — 本地存储模块 2

图形效果 (Graphical Effects)

  • Flipable
  • ShaderEffect 2
  • ShaderEffectSource
  • GridMesh 2
  • QtQuick.Particles 2 2

实用方便的类型 (Convenience Types)

  • Connections
  • Binding — 绑定器
  • Timer — 定时器
  • WorkScript

画布 (Canvas)

  • Canvas 2
  • Context2D 2
  • CanvasGradient 2
  • CanvasPixelArray 2
  • CanvasImageData 2
  • TextMetrics 2

水平有限,还请不吝指正,谢谢!


原创文章,转载请注明 >> Thuai’s blog

文章链接 >>http://www.thuai.com/archives/122

发表在 QtQt QMLQt Quick 标签有  发表回复

Qt QML– 动态创建QML objects和销毁


动态创建Qml对象

使用JavaScript动态创建Qml对象有两种方式,一是使用Qt.createComponent,二是使用Qt.createQmlObject

如果你已经有一个qml文件定义了一个component,则使用Qt.createComponent()这种方式会比较好。如果本身对象就是在Qml运行期生成的对象且简单,则使用Qt.createQmlObject(),你肯定不想在一条语句中写上百来行代码定义一个component对吧!

QT.CREATECOMPONENT

先看代码

//Sprite.qml
import QtQuick 2.0

Rectangle {  80; height: 50; color: "red" }

//main.qml
import QtQuick 2.0
import "componentCreation.js" as MyScript

Rectangle {
    id: appWindow
     300; height: 300

    Component.onCompleted: MyScript.createSpriteObjects();
}

//componentCreation.js
var component;
var sprite;

function createSpriteObjects() {
    component = Qt.createComponent("Sprite.qml");
    if (component.status == Component.Ready)
        finishCreation();
    else
        component.statusChanged.connect(finishCreation);
}

function finishCreation() {
    if (component.status == Component.Ready) {
        sprite = component.createObject(appWindow, {"x": 100, "y": 100});
        if (sprite == null) {
            // Error Handling
            console.log("Error creating object");
        }
    } else if (component.status == Component.Error) {
        // Error Handling
        console.log("Error loading component:", component.errorString());
    }
}

从上面的代码看出,先自定义了一个qml文件Sprite.qml,这个qml文件中有个宽80、高50、颜色为红色的Rectangle组件。在main.qml首先是导入了componentCreation.js这个JavaScript脚本,并去了别名MyScript。rootObject则是一个宽300、高300、id为appWindow的Rectangle组件。当这个Rectanle类型的组件加载完成的时候就会调用componentCreation.js中的createSpriteObjects()方法动态创建对象。

核心就是createSpriteObjects()这个方法了。

可以看出使用Qt.createComponet()这种方法动态创建qml对象,需要两个步骤:1.使用Qt.createComponent(url,parent, mode). url即为自定义好的需要创建qml对象的qml文件。parent和mode通常可以不写。具体可以查看文档中Qt.createComponent()的详细说明。因为Qt.createCompoent()成功则会返回一个Component类型的对象,所以需要第二步。2.使用createObject()创建实例,createObject()方法是Component类型的一个方法。createObject()返回的才是Script.qml的实例。

在上面的这段代码中,还可以看到,component.statusChanged这个signal连接了一个createScriptObjects.js中的另外一个方法,通过component.status和Component组件中的不同枚举值对比,进行错误的判断和处理。

总结: Qt.createComponent()这个function是 Qt 这个Qml全局类型中的一个方法,这个方法返回一个Component类型的对象。需要得到自定义qml组件的实例,还需要使用Component.createObject()方法。如果需要使用非阻塞方式创建qml object则可以使用incubateObject()方法。

QT.CREATEQMLOBJECT()

如果需要在qml运行期创建一个qml对象且这个对象定义并不复杂时,则使用Qt.createQmlObject()这种方法比较好。

import QtQuick 2.0

Rectangle {
    id: rect
     360
    height: 360
    Text {
        anchors.centerIn: parent
        text: "Hello World"
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            createObject();
        }
    }

    function createObject()
    {
        //第一种写法
        /*
        var object = Qt.createQmlObject('import QtQuick 2.0;' +
                                        'Rectangle {' +
                                        '30; ' +
                                        'height:30;' +
                                        'colo: "red"}', rect, "error");
        */

        //第二种写法
        //var newObject = Qt.createQmlObject('import QtQuick 2.0; ' + 'Rectangle {  20; height: 20; colo: "red"}', rect, "dynamicSnippet1");

        //第三种写法
        var newObject = Qt.createQmlObject('import QtQuick 2.0; 
 Rectangle { 20; height: 20; colo: "red"}', rect, "error3");
   }
}

从上面的代码可以看出Qt.createQmlObject()有三个参数,第一个为定义qml对象的字符串。第二个为创建的qml对象的父对象。第三个则为出错时候的文件路径提示。并且提示会出现行数和列数,可以分别试验三种写法看错误提示有何不同。

维护动态创建的Qml对象

动态创建Qml对象,你必须知道它所存在的context的生命周期,必须保证context的生命周期比动态创建的Qml对象生命周期要长,因为context销毁了,其中绑定的动态创建的Qml对象也会失效。动态创建的Qml对象的context取决于它创建的方式。

  • Qt.createComponet(),使用这种方法,则context就是调用这个Qt.createComponent方法的QQmlContext。QQmlContext跟Qt4.8.x中的QDecalartiveContext()其实差不多。

  • Qt.createQmlObject(),使用这种方法,则context就是这个方法的的parent参数。

  • 如果使用Component{}定义一个对象,然后在这个Component对象中调用createObject()或者incubateObject()方法,这时动态创建出的对象的context就是这个Component的context。

动态销毁对象

使用Object.destroy()方法删除对象。

在多数情况下,你可以使用改变可视对象的opacity值为0或者将它移出屏幕就可以了,而不是delete它。如果你有很多动态创建的对象,delete那些不用的对象,则是值得做的事情。

记住,不要去删除不是你手动创建的对象,例如Repeater和Loader创建的对象。

例如下面这段代码中SelfDestroyingRect就不能使用destroy来销毁它。

Item {
    SelfDestroyingRect {
        // ...
    }
}

水平有限,还请不吝指正,谢谢!

文章属原创,转载请注明转自>>Thuai’s blog

文章链接>>http://www.thuai.com/archives/119

发表在 QtQt QML 发表回复

Qt QML—QML signal与signal handler系统

QML 的signal 和 signal handler机制的存在,是为了应用能够和UI组件之间相互交互。signal就是button clicked、mouse area pressed这些event,signal handler则就是这些事件的响应。

当一个signal emitted,相应的signal handler就会被调用,在signal handler中执行一些scripts或是其他操作,已完成event的响应。

signal和signal handler的定义

signal

signal <signalName>[([<type> <parameter name>[, ...]])]

signal handler

on<SignaleName>

可以参考另一篇文章 Qt QML入门– QML 语法 (2)

Property Change Signal Handler

当Property的值改变了,就会自动emitted一个signal,这种property changed signal,有property Signal handler与之对应。你只需要实现signal handler即可。

on<PropertyName>Changed

使用Connections Type

很多人都知道Qt一个很好的东西,就是signalslot机制。你可以很方便的connect的signal和slot。QML中的Connections,它能够让你接收指定object的任意signal,从而能够在signal声明的那个Object之外接收到声明的signal,从而实现自己想要logic。

import QtQuick 2.0

Rectangle {
    id: rect
     100; height: 100

    MouseArea {
        id: mouseArea
        anchors.fill: parent
    }

    Connections {
        target: mouseArea
        onClicked: {
            rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
        }
    }
}

上面的代码中,Connections中的target绑定的是ouseArea,从而在rect中能够接收到mouseArea的signal,如clicked、pressed、released等等signal。

附带的signal handler

附带的signal handler是附带组件的signal与之对应的signal handler,并不是使用附带组件本身Object的signal的signal handler。

可以参看另一篇文章 Qt QML入门– QML 语法 (2)

signal与signal的连接,signal与method的连接

signal 都有一个connect()方法,可以连接method或者signal。

可以看下面两段代码

signal connect signal

Rectangle {
    id: forwarder
     100; height: 100

    signal send()
    onSend: console.log("Send clicked")

    MouseArea {
        id: mousearea
        anchors.fill: parent
        onClicked: console.log("MouseArea clicked")
    }

    Component.onCompleted: {
        mousearea.clicked.connect(send)
    }
}

注意:mousearea.clicked.connect(send),这里send是signal但是却没有加或括号。emitted signal的时候则不论是否signal声明的时候有无括号,都须要加上括号。

signal connect method

Rectangle {
    id: relay

    signal messageReceived(string person, string notice)

    Component.onCompleted: {
        relay.messageReceived.connect(sendToPost)
        relay.messageReceived.connect(sendToTelegraph)
        relay.messageReceived.connect(sendToEmail)
    }

    function sendToPost(person, notice) {
        console.log("Sending to post: " + person + ", " + notice)
    }
    function sendToTelegraph(person, notice) {
        console.log("Sending to telegraph: " + person + ", " + notice)
    }
    function sendToEmail(person, notice) {
        console.log("Sending to email: " + person + ", " + notice)
    }
}

注意:这里使用connect连接是的method,同样没有加上括号。

既然能够connect,那有没有disconnect呢?当然有。

有时候,你不使用disconnect,你某些动态create的对象都无法distroy。

Rectangle {
    id: relay
    //...

    function removeTelegraphSignal() {
        relay.messageReceived.disconnect(sendToTelegraph)
    }
}

disconnect跟connect就只是一个单词差别而已,没有其他特别不同的地方。


水平有限,还请不吝指正,谢谢!


原创文章,转载请注明 >> Thuai’s blog

文章链接 >>http://www.thuai.com/archives/116

发表在 QtQt QML 发表回复

Qt QML—QML 属性的绑定(Property Binding)

QML 属性绑定 (Property Binding)

属性的绑定能够更好的使用QML的特性-QML object动态行为变化的自动响应。这是QML一个很重要的特性。

注意:绑定的一个很重要的标志就是“:”–冒号

当QML object 的属性既可以分配一个static value,也可以绑定一个JavaScript表达式,也可以使用JavaScript的自带的Date Math这些对象。因为QML uses a standards compliant JavaScript engine。

Rectangle {
    id: parentRect
     200; height: 200

    Rectangle {
        id: childRect
         100; height: parent.height
        color: "blue"
    }
}

上面的代码中,childRect的height绑定到了parent的height,当parentRect的height改变的时候,QML engine会重新计算childRect.height

import QtQuick 2.0

Rectangle {
     100
    height: width * 2
    focus: true
    Keys.onSpacePressed: {
        height = width * 3
    }
}

在看上面的这段代码,Rectangle的height首先绑定了width2,然后在Key.onSpacePressed这个附带的signal handler中,height 被赋值width3,注意是赋值,不是绑定。

所以之前的bind被这个赋值语句移除了,也就是说以后Rectangle的width变化了,height不会自动变成width的2倍。

如果是想要重新binding而不是赋值,则需要使用Qt.binding()。

this的使用

使用JavaScript绑定时,QML允许使用Javascript中this关键字。

例如下面的代码:

Item {
     500
    height: 500

    Rectangle {
        id: rect
         100
        color: "yellow"
    }

    Component.onCompleted: {
        rect.height = Qt.binding(function() { return this.width * 2 })
        console.log("rect.height = " + rect.height) // prints 200, not 1000
    }
}

rect.heigth属性的绑定使用了JavaScript的语句,所以可以使用this,这里的this表示的是Item而不是rect


水平有限,还请不吝指正,谢谢!


原创文章,转载请注明 >> Thuai’s blog

文章链接 >>http://www.thuai.com/archives/115

发表在 QtQt QML 发表回复

Qt QML入门– QML 语法 (2)


QML 对象的属性

一个QML对象所具有的属性有以下几种:

  • id -id 标识
  • property attributes –属性(其中包括继承自Item的attributes,自定义的attributes)
  • signal attributes –信号
  • signal handler attributes –信号处理
  • method attributes –函数
  • attached propeties and attached signal handler attributes –附带的属性 和 附带的signal handler

id

id 用来标识QML对象,id不能够以大写字母开头,同样method也不能够以大写字母开头。请记住这点,不然就会有“xxx cannot begin with an upper case letter”这样的error。 有了id你就能够通过id引用id为xxx的对象了。所以尽量的给你的每个QML object都写上id吧! QML object 一旦实例化,id值就无法改变。


Property Attributes

自定义属性的语法格式:

[default] property <propertyType> <propertyName>

例如:

property int myAge 25;
default property string myName thuai

//MyCustomRectangle.qml
property MyCustomRectangle myCusRect
property color myFavoriteColor: "blue"

default关键字表示,该QML object有个默认属性,你使用这个属性的时候不需要显式的声明。

例如:

// MyLabel.qml
import QtQuick 2.0

Text {
    default property var someText

    text: "Hello, " + someText.text
}

上面的MyLabel类型中中有个default属性someText,所以在MyLable使用的时候,

MyLabel {
    Text { text: "world!" }
}

//和这段代码是等效的
MyLable {
    someText: Text { text: "world!" }
}

这就是default property

单行语句的分号是可写不用写的。但是一行写多条语句,语句则必须要用分号分隔!

propertyType 可以是QML的基本类型,一种QML对象类型,也可以是QML可以是C++通过Q_PROPERTY宏注册的类,还可以是JavaScript中的var,var它可以表示任何类型的数据,还可以是自定义的QML类型,如MyCustomRectangle

为PROPERTY ATTRIBUTES赋值

  • 一是初始化的时候赋值

    import QtQuick 2.0 Item{ x: 10 y: 10 100 height: 100 }

  • 一是使用的时候赋值。

    import QtQuick 2.0 Rectangle { id: rect Component.OnCompleted: { rect.color = “blue” } }

属性组(GROUPED PROPERTIES)

将相同的属性写成一句代码 例如:

Text {
    //dot notation
    font.pixelSize: 12
    font.b: true
}

Text {
    //group notation
    font { pixelSize: 12; b: true }
}

font.pixelSize 和 font.blod用括号括起来写成了一句,注意 pixelSize和 b之间有个;

属性别名(PROPERTY ALIASES)

格式: [default] property alias <name>: <alias reference>

// Button.qml
import QtQuick 2.0

Rectangle {
    property alias buttonText: textItem.text

     100; height: 30; color: "yellow"

    Text { id: textItem }
}

Button中的属性buttonText是textItem.text属性的别名

Button { buttonText: "Click Me" }

所以对Button的buttonText属性赋值就相当于给Text的text属性赋值

注意: Property Aliases 必须在组件所有初始化工作都完成之后,才能够使用,否则会出错。

import QtQuick 2.0

Rectangle {
     360
    height: 360

    property alias aText: te

    //error before Rectangle initialized completed
    //aText: "init text"

    Component.onCompleted: {
        aText.text = "init text onCompleted"
    }

    Text {
        id: te
        anchors.centerIn: parent
    }
}

如果你在component初始化完成,对alias properties赋初始值,QtCreator会报“Cannot assign to non-existent property “aText”错误!

这里又看到了一个有意思的东西。Component.onCompleted,这是一个QtQuick所有的Object都有的一个附带信号处理函数。组件初始化创建完成就会触发这个处理函数。后面在关于signal的文章中有更详细的讲解。

PROPERTY MODIFIER OBJECTS

<PropertyModifierTypeName> on <propertyName> {
    // attributes of the object instance
}

这里Property Modifier Objects我没有用中文,因为我也不知道该译成什么。具体后面的例子中大家可以看到Property Modifier Objects的应用。如下面代码中的NumberAnimation

import QtQuick 2.0

Rectangle {
     360
    height: 360

    Rectangle {
        id: moveRect
         50
        height: 50
        radius: 5
        color: "red"

        NumberAnimation on x {
            from: 0
            to: 100
            duration: 200
        }
    }
}

信号(Signal Attributes)

信号属性定义语法:

signal <signalName>[([<type> <parameter name>[, ...]])]

[]表示可选

例如:

//不带参数和括号
signal mySignal

//带空括号
signal mySignal2()

//signal 信号名(参数类型 参数名, 参数a类型 参数a)
signal mySignal3(string name, var any)

对应的signal handler的语法格式则是:

on<SignalName>

如上例中的mySignal,对应的signal handler 就写成 onMySignal

注意: mySignal的第一个字母S成了大写的了。因为这里onMySignal,on作为开头了。所以按照QML的语法,mySignal中的m就要写成M, signal 还可以以下划线_开头, 比如_mySignal4,对应的signal handler则写成on_MySignal4,下划线的数目也可以不同。再比如__mySignal4和_mySignal4**就是两个不同的signal(前者一个下划线,后者两个下划线)

signal mySignal3的 signal handler:

onMySignal3: {
     console.debug("i'm a signal handler")
     console.debug("name"en);
}

QML有内建的属性signal,当属性的value变化的时候,就会emitted signal. 这个就是文档中所说的Property Changed Signal

import QtQuick 2.0

Item {
     100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("Click!")
        }
    }
}

MouseArea有clicked signal, 当鼠标点击MouseArea 的时候,就会emit clicked signal。 signal handler onClicked 就会触发,console 就会打印出“Click!“

Signal Handler是一种特殊的method属性。当你在QML中文件中声明一个singal的时候,QML会自动帮你关联一个signal handler,这个signal handler默认是没有实现的。所以你只需要实现这个signal handler就可以了,然后在emitted一个signal的时候,与之关联的signal handler就会自动的被QML引擎调用。

例如文档中的一个例子:

// SquareButton.qml
Rectangle {
    id: root

    signal activated(real xPosition, real yPosition)
    signal deactivated //注意我没有括号哦!

     100; height: 100

    MouseArea {
        anchors.fill: parent
        onPressed: root.activated(mouse.x, mouse.y) //emit activated signal and parameter
        onRelased: root.deactivated() //emit deactivated signal 注意我有括号哦!
    }
}

// myapplication.qml
SquareButton {
    //implement onActivated signal
    onActivated: console.log("Activated at " + xPosition + "," + yPosition) 
    //implement onDeactivated signal
    onDeactivated: console.log("Deactivated!")
}

在SquareButton.qml中的MouseArea,pressed、released都emitted了一个signal。 由此可以看出QML中emitted一个signal,你只需要调用它就行了。

注意:在QML中声明无参signal你可以不带括号,但是emitted它的时候,就必须要带括号了。否则,它不会报错,但是它也不会emitted signal

而在Qt C++代码中你要想emittd一个signal,你就必须使用emit <定义的信号>,才能够emit一个signal。

在myapplication.qml中你使用SquareButton这个自定义的Component时,只需实现下onActivated、onDeactivated这两个signal handler就行,因为QML已经帮你declare并connected了。

signal不仅有signal handler,它还可以与后面讲到的method连接(connect),Qt 一个很重要的机制就是信号和槽机制,其实在QML中也有这个,只是叫法不一样而已。QML中所有的method都是slot。

PROPERTY CHANGE SIGNAL HANDLERS

语法格式:

on<Property>Changed

signal 有signal handler,property呢? property有property changed signal handler(属性变化信号处理方法,呵呵有点拗口,翻译水平不行,不纠结在这种意会的层次,能够理解就行),既然也是signal hanlder那就不需要你去declare它并关联到信号了。你也只需要使用它就行了。

例文档中的:

import QtQuick 2.0

TextInput {
    text: "Change this!"
    onTextChanged: console.log("Text has changed to:", text)
}

方法(Method Attributes)

QML定义一个method:

function <functionName>([<parameterName>[, ...]]){ <body> }

QML中的method定义不像signal的定义,需要声明参数(parameter)的类型(type),QML中method的参数类型是var,也只能是var,不论它是在QML中定义的method还是C++中定义的指定参数的method然后注册到QML system中使用的。

对JavaScript熟悉的朋友,应该知道var这个关键字。(此处可以问歌哥或者度娘,建议歌哥,因为度娘都是copy的相似答案)

这是QML定义method的语法格式,C++中的method,可以用Q_INVOKABLE和 slots注册到QML系统中,这样QML中就可以访问你C++中写的method方法了。具体我会在后面关于C++与QML交互的文章中详细表述。

这里先暂不写JavaScript中的method如何在QML object中访问。先理解QML object定义的method如何正确使用,再拓展其他方法定义的method如何使用。

import QtQuick 2.0

Item {
     200; height: 200

    MouseArea {
        id: msArea
        anchors.fill: parent
        onClicked: label.moveTo(mouse.x, mouse.y)
    }

    Text {
        id: label
        function moveTo(newX, newY) {
            label.x = newX;
            label.y = newY;
        }
        text: "Move me!"
    }
}

上面的代码中,id为label的Text中有个method moveTo(newX, newY) 更改label的x、y值,从而移动label,当点击Item中的任意一点,Item中MouseArea msArea自动emitted clicked signal, signal handler onClicked 自动调用label.moveTo()。

从这个例子,你应该能够理解了如何定义一个QML method以及如何调用一个QML method。所以我建议我同事都最好每个component都加上id,不要图少敲几个键,而让代码的可读性降低。

附带的属性和附带的信号处理函数 (Attached Properties and Attached Signal Handlers)

定义的语法格式:

<AttachingType>.<propertyName>

<AttachingType>.on<SignalName>

import QtQuick 2.0

ListView {
     240; height: 320
    model: 3
    delegate: Rectangle {
         100; height: 30
        color: ListView.isCurrentItem ? "red" : "yellow"
    }
}

在上面的代码中,isCurrentItem就是ListView的一个附带属性。ListView还有很多附带的属性,详见QtCreator中的帮助。

Component.onCompleted则是一个附带的Signal handler。


水平有限,还请不吝指正!

非常感谢网友lei,为本文勘正


原创文章,转载请注明 >> Thuai’s blog

文章链接 >>http://www.thuai.com/archives/100

发表在 QtQt QML 标签有  发表回复

Qt QML入门– QML 语法 (1)


一个qml文件的结构

  • 需要包含的模块
  • 唯一一个root对象

包含模块

import ModuleIdentifier Version.Number [as <Qualifier>]

例如:

//HelloWorld.qml
import QtQuick 2.0

或者

import QtQuick 2.0 as Quick

详见文档–Import Statements

有且仅有一个ROOT对象

import QtQuick 2.0

Rectangle {  200; height: 200; color: "red" }
Rectangle {  200; height: 200; color: "blue" } // invalid!

这种在一个qml文件中写两个root object是错误的,只能有一个root object,下面的代码就是正确的形式。

import QtQuick 2.0

Rectangle {  200; height: 200; color: "red" }

qml的基本语法

模块的包含

QML 模块的包含,只能使用关键字 import 包含qml文件需要用到模块,import关键字后面的内容可以有三种:

  1. 注册的带有版本好的模块
  2. 指定路径的qml文件
  3. 一个JavaScript文件

例如:

import QtQuick 2.0
import QtQuick.LocalStorage 2.0 as Database
import "../privateComponents"
import "somefile.js" as Script

其中第一种和第二种都是包含带有版本号注册的模块。

对象的声明

Rectangle {  100 height: 100 color: "red" }

上面的代码就使用Rectangle元素声明了一个宽100,高100,颜色为red的对象。

子对象的声明

例1

import QtQuick 2.0

Rectangle {
      id: rect
       100
      height: 100
      gradient: Gradient {
                id: grad
                GradientStop {id: gStopYellow; position: 0.0; color: "yellow" }
                GradientStop {id: gStopGreen; position: 1.0; color: "green" }
      }
}

例2

import QtQuick 2.0
Rectangle {
    id: rect
     200
    height: 200
    color: "red"

    Text {
        id: text
        anchors.centerIn: parent
        text: "Hello, QML!"
    }
}

上面的两个例子都使用了子对象。这里引出了一个概念

  1. QML对象树中,的父子关系
  2. 试图上的父子对象

例1中Rectangle对象rect中的gradient属性中有个子对象grad,grad中又有两个GradientStop子对象。这些父子对象的上下文环境(context)是QML object tree 中的父子对象关系 ,而不是visual scene 上下文环境的父子对象关系。

例2中的Text与Rectangle的父子关系即是object tree中的父子关系也是visual scene中的父子对象关系。

注释

和大多数语言一样,有单行注释// 和 块注释 /* */

=================== End