qml之Loader使用

http://blog.csdn.net/xiangzi_011/article/details/25488137

qml Loader是用来动态加载qml components的,这样就可以在你需要相应的component时才创建它。好处我就不说了。

1.加载方式

Loader可以通过两种方式来加载components,一种是通过source属性来加载一个qml文件(例子1),另一种是通过sourceComponent属性来加载(例子2)。这两种方式都是在鼠标click root后才加载的。

例子1:

import QtQuick 2.2

Rectangle {
    id:root
    width: 360
    height: 360

    Loader
    {
        id:loader
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            loader.source = "Page.qml";
        }
    }
}



例子2:
import QtQuick 2.2

Rectangle {
    id:root
    width: 360
    height: 360

    Loader
    {
        id:loader
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            loader.sourceComponent = component1
        }
    }

    Component
    {
        id:component1

        Rectangle {
            width: 100
            height: 62

            color: "red"
        }
    }
}

2. 位置和大小

通过Loader加载的Component的大小和位置,可以通过Loader来进行设置,如果不设置,则Component会使用默认的大小和位置。

直接看代码:

Rectangle {
    id:root
    width: 200
    height: 200

    Loader {
        anchors.fill: parent //rect会充满root
        sourceComponent: rect
    }

    Component {
        id: rect
        Rectangle {
            width: 50
            height: 50
            color: "red"
        }
    }
}

Rectangle {
    id:root
    width: 200
    height: 200

    Loader {
        anchors.centerIn: parent  //rect会处于root的中心
        sourceComponent: rect
    }

    Component {
        id: rect
        Rectangle {
            width: 50
            height: 50
            color: "red"
        }
    }
}

3. 接收Loader加载的Component的信号

Loader加载的Component发送的任何信号都可以通过Connections方式来处理。target代表发送信号者,这里通过Loader的item属性来获取加载的Component对象,onMessage是对应message信号的处理方法。其实就是一个信号绑定过程。


Rectangle {

    id:root
    width: 200
    height: 200

    Loader {
       id: myLoader
       sourceComponent: rect
    }

    Connections {
        target: myLoader.item   //代表的是rect,但是这里不能直接使用rect,通过Loader加载的对象只能通过item属性进行访问
        onMessage: console.log(msg)
    }

    Component {
        id: rect
        Rectangle {

            signal message(string msg)  //声明信号

            width: 50
            height: 50
            color: "red"

            MouseArea
            {
                anchors.fill: parent
                onClicked:
                {
                    message("rect clicked!");//发送message信号
                }
            }
        }
    }
}

4. Component的销毁
当source或是sourceComponent属性发生变化时,之前加载的项都会被销毁,将source设置成空字符串或是将sourceComponent属性设置成null可以销毁当前已经加载的项,释放Loder所占用的资源。下面例子点击root时会进行判断,如果loader.sourceComponent为null,就设置成component1,component创建,log里输出 " component1onCompleted",如果不为空,就设置为null,就会销毁component,log里输出 " component1 onDestruction"。可见component1对象已经被销毁。
Rectangle {
    id:root
    width: 360
    height: 360

    Loader
    {
        id:loader
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            loader.sourceComponent = (loader.sourceComponent==null)? component1:null
        }
    }

    Component
    {
        id:component1

        Rectangle {
            width: 100
            height: 62

            color: "red"

            Component.onCompleted:
            {
                console.log("component1 onCompleted");
            }
            Component.onDestruction:
            {
                console.log("component1 onDestruction");
            }
        }

    }
}

5. 从QtQuick 2.0以后,Loader可以加载任何qml中的类型,包括QtObject,Timer等非可视化的元素。下面例子中就是实现在一个Text中显示当前的时间。

Rectangle {

    id:root
    width: 200
    height: 200

    Text {
        id: text
        anchors.fill: parent
        color: "red"
        text: myLoader.item.displayTime  //通过myLoader.item访问Timer的displayTime属性
    }

    Loader {
       id: myLoader
       sourceComponent:
           Component {

           id:noVisualComponent

           Timer {
               property string displayTime:Date().toString()
               interval: 500; running: true; repeat: true
               onTriggered: displayTime = Date().toString()
           }
       }
    }
}

6.  焦点和键盘事件
Loader是一个焦点区域,如果想让Loader的子item获得活动的焦点,必须将Loader的focus属性设置为真。同时如果Loader的子item将accepted属性设置为true后,Loader所在的Item将捕捉不到相应的事件。
下面的例子就是root item鼠标按下前可以捕获按键事件,当鼠标按下后,myComponent被创建,注意Loader和Loader的子item的focus属性都要设置为true。将myComponent中event.accepted = true;改为event.accepted = false; 那么键盘事件会继续传播到root item。
import QtQuick 2.0

Rectangle {
    width: 200; height: 200

    Loader {
        id: loader
        focus: true
    }

    MouseArea {
        anchors.fill: parent
        onClicked: loader.sourceComponent = myComponent;
    }

    Keys.onPressed: {
        console.log("root Item captured:", event.text);
    }

    Component
    {
        id:myComponent
        Item {
            Item {
                focus: true
                Keys.onPressed: {
                    console.log("Loaded item captured:", event.text);
                    event.accepted = true;
                }
            }
        }
    }
}

7. 在view delegate中使用Loader

我们可以在ListView的delegate中使用Loader动态的创建Component,来优化ListView的加载性能。这里需要注意: delegateComponent上下文中的 context 属性的访问限制问题。直接上官网给的代码。

Item {
    width: 400
    height: 400

    Component {
        id: myComponent
        Text { text: index }    //Text无法访问到delegateComponent中的index属性
    }

    ListView {
        anchors.fill: parent
        model: 5
        delegate: Component {
            id: delegateComponent
            Loader {
                sourceComponent: myComponent
            }
        }
    }
}

如果想解决这个问题,大概有三种方式。

1)可以将delegateComponent改为inline形式

delegate: Component {
            Loader {
                sourceComponent: Component {
                    Text { text: index }    //这里Text可以直接访问index属性了
                }
            }
        }
2)将delegateComponent实现到一个单独的qml文件中

 delegate: Component {
            Loader {
                source: "MyComponent.qml" 
            }
        }

  myComponent.qml中的Text元素中可以直接访问index属性

3)给Loader增加自定义属性,

Item {
    width: 400
    height: 400

    Component {
        id: myComponent
        Text { text: modelIndex }    //这里可以正常访问Loader自定义属性了
    }

    ListView {
        anchors.fill: parent
        model: 5
        delegate: Component {
            Loader {
                property int modelIndex: index //自定义属性,绑定index
                sourceComponent: myComponent
            }
        }
    }
}

你可能感兴趣的:(QT,qml,Loader)