QML动态创建自定义组件

一、动态加载和实例化对象:createComponent

例子1:

①、创建本地的QML文件,注意文件第一个字母要大写

ZStation.qml

import QtQuick 2.5

Rectangle{
    property string mName: "station"
    signal entered(string objName);
    signal exited();
    property int station_width: width/3

    id: root
    color: Qt.rgba(0,0,0,0)
    width: 90
    height: width/3
    Rectangle{
        id: station
        color:"green"
        width: station_width
        height: width
        radius: width/2
    }
    Text {
        anchors.top:parent.top;
        anchors.left: station.right;
        anchors.leftMargin: 5;
        width: 30
        height: 12
        text: mName
        color: "white"
    }
    MouseArea {
        hoverEnabled: true;
        anchors.fill: parent;
        onEntered: {
            root.entered(root.objectName);
        }
        onExited: {
            root.exited();
        }
    }
}

②、在主qml里动态创建并连接信号槽

function addStation(x, y, id, name){
    console.log(x,y,id,name);
    var componentIn = Qt.createComponent("ZStation.qml");
    if (componentIn.status === Component.Ready) {
        var objIn = componentIn.createObject(root, {"mName":name, "objectName":id});
        if(auto_scale){
            x = getNearX(x);
            y = getNearY(y);
        }

        objIn.x = x;
        objIn.y = y;
        objIn.entered.connect(root.showPopInfo)
        objIn.exited.connect(root.hidePopInfo)
        station_list.push(objIn);
        console.log(x,y);
    }else{
        console.log("qml create station err:",componentIn.errorString());
    }
}

 

例子2:

①、main.qml

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    id: mainWin
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    LoginPage {
        width: 300
        height: 200
        anchors.centerIn: parent
    }
}

②、LoginPage.qml

import QtQuick 2.0
import QtQuick.Controls 2.3

Rectangle {
    id: loginPage
    width: 400
    height: 300
    color: "#051f58"
    radius: 8
    clip:true

    Button {
        text: "登录页面-登录按钮"
        anchors.centerIn: parent
        onClicked: {
            // 隐藏登录页面
            loginPage.visible = false // 不能销毁,否则下面的"主页面"也会跟随销毁,则后面
            // 点击"主页面-关闭按钮",将无法销毁关闭"主页面"

            // 在主窗口(mainWin)上显示主页面
            var compMainPage = Qt.createComponent("MainPage.qml")
            .createObject(mainWin, {x:50, y:50, width:200, height:250});
        }
    }
}

③、MainPage.qml

import QtQuick 2.0
import QtQuick.Controls 2.3

Rectangle {
    id: mainPage
    color: "#498ff8"
    radius: 8

    Button {
        text: "主页面-关闭按钮"
        anchors.centerIn: parent
        onClicked: {
            // 销毁关闭主页面
            mainPage.destroy()
        }
    }
}

参考:https://www.cnblogs.com/linuxAndMcu/p/13566502.html

 

PS: 

①、createComponent的返回值

 

 ②、创建过程时间是不确定的,我们上面的例子都是直接创建并判断状态,大多数情况是没问题,但是遇到特殊情况如:加载多种依赖或位于缓慢服务器中的QML时,会很慢【而且貌似创建函数不会阻塞】,故正确做法是:加一个判断

function createImageObject() {
    component = Qt.createComponent("dynamic-image.qml");
    if (component.status === Component.Ready || component.status === Component.Error) {
        finishCreation();
    } else {
        component.statusChanged.connect(finishCreation);
    }
}

function finishCreation() {
    if (component.status === Component.Ready) {
        var image = component.createObject(root, {"x": 100, "y": 100});
        if (image === null) {
            console.log("Error creating image");
        }
    } else if (component.status === Component.Error) {
        console.log("Error loading component:", component.errorString());
    }
}

例子位于QMLBook的第15章节,动态创建组件。

③、销毁

item=Qt.createQmlObject(...);
... item.destroy();

 

二、动态创建Component

这个方式和上面原理一致,component1是事先定义好的Component

 Component.onCompleted: {
        var obj1 = component1.createObject(root, { "color": "red", "width": 100, "height": 100})
        var obj2 = component2.createObject(root, { "color": "green", "width": 200, "height": 200})
        var obj3 = component3.createObject(root, { "color": "gray", "width": 300, "height": 300})
    }

 

 

三、从文本文件动态实例化:createQmlObject

1、接口

 

 qml:qml文本

 parent:对象的父亲

 filepath:存储创建对象时的错误报告

 返回:立即返回创建的对象或null,这是与上面其他接口不一样的:

 

 

2、例子1:

import QtQuick 2.5

Item {
    id: root

    width: 1024
    height: 600

    function createItem() {
        Qt.createQmlObject("import QtQuick 2.5; Rectangle { x: 100; y: 100; width: 100; height: 100; color: \"blue\" }", root, "dynamicItem");
    }

    Component.onCompleted: root.createItem();
}

 

四、createComponent

createComponent其实和createObject一样,除了createComponent多了一个指定是否同步创建的参数,可以认为就是一个createObject,这里不加例子了

 

 如图,多了mode参数

posted @ 2021-11-25 16:54  朱小勇  阅读(1767)  评论(0编辑  收藏  举报