zoukankan      html  css  js  c++  java
  • qt quick中qml编程语言

    qt quick中qml编程语言

    原创文章,转载请注明转自 >> 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

  • 相关阅读:
    .NET 开源工作流: Slickflow流程引擎基础介绍(六)--模块化架构设计和实践
    .NET 开源工作流: Slickflow流程引擎基础介绍(五) -- 会签加签高级特性介绍
    vue实现Excel文件的上传与下载
    库存商品计算成本的几种方法
    如果有一天不做程序员了,还能入什么行业?
    C#使用EF连接PGSql数据库
    回顾2018,展望2019
    Git命令使用大全
    使用VSCode配置简单的vue项目
    SqlServer的两种插入方式效率对比
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/12636855.html
Copyright © 2011-2022 走看看