QML如何获得Loader的位置

时间:2016-05-27 15:37:51

标签: qt qml loader

我想生成一个像流一样的二叉树来显示与QML的组织关系信息。enter image description here

我的方式:

  1. 像流程示例一样创建树节点。
  2. 使用Canvas将树节点排成一行,如上图所示。我想得到 在Loader.onLoaded之后指向并绘制线条。
  3. 我的问题:

    完成第一步后。在第二步中,我无法获得树节点的正确位置点。

    详细信息:

    根据Qt文档,如果我没有明确设置Loader的宽度和高度,它将根据其项目大小自动设置。但是,我无法在Loader.onloaded()

    中获取节点位置点
    import QtQuick 2.3
    import QtQuick.Window 2.2
    
    Window {
        id: appWindow
    
        visible: true
        width: 1066
        height: 600
    
        property var jsonData: [{"id":1,"pid":0},{"id":2,"pid":1},{"id":3,"pid":1},
            {"id":4,"pid":2},{"id":5,"pid":2},{"id":6,"pid":3},
            {"id":7,"pid":3},{"id":8,"pid":4},{"id":9,"pid":4},{"id":10,"pid":6}]
        property int maxRectangles: 5
        Component.onCompleted: {
            var color = Qt.lighter("red", maxRectangles / 7)
            pLoader.sourceComponent = rectangleComponent;
            var currItem = pLoader.item;
            currItem.color = "blue"
            currItem.text = 0
    
            var tmp = {};
            tmp[jsonData[0]["id"]] = currItem ;
    
            for(var index = 1; index < jsonData.length; index++) {
                color = Qt.lighter("red", index / 7)
                var sItem = jsonData[index]["pid"];
                if(tmp[sItem].rComponent.sourceComponent === null){
                    tmp[sItem].rComponent.sourceComponent = rectangleComponent
                    attachData(tmp[sItem].rComponent.item,index, color);
                    tmp[jsonData[index]["id"]] = tmp[sItem].rComponent.item ;
                }
                else {
                    tmp[sItem].lComponent.sourceComponent = rectangleComponent
                    attachData(tmp[sItem].lComponent.item,index, color);
                    tmp[jsonData[index]["id"]] = tmp[sItem].lComponent.item ;
                }
            }
        }
        function attachData(item, text, color){
            item.text = text;
            item.color = color
        }
    
        Component {
            id: rectangleComponent
            Column{
                property alias rComponent: rightLoader
                property alias lComponent: leftLoader
                property alias color: rect.color
                property alias text: myText.text
                spacing: 40
                //anchors.horizontalCenter: parent.horizontalCenter
                Rectangle {
                    anchors.horizontalCenter: parent.horizontalCenter
                    id:rect
                    width: 100
                    height: 100
                    Text{
                        id:myText
                        font.pixelSize: 18
                        anchors.centerIn: parent
                        color:"white"
                    }
                    Component.onCompleted: {
                        console.log("Component.onCompleted", mapToItem(canvas, 0, 0))
                    }
    
                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            updateDotPosition(parent)
                            //here, printed coordinate is my expected
                            //but i want line them after tree node loaded antomate
                            console.log("updateDotPosition", mapToItem(canvas, 0, 0))
                        }
                    }
                }
    
                Row{
                    spacing: 40
                    anchors.horizontalCenter: parent.horizontalCenter
                    Loader {
                        id:leftLoader
                        onLoaded: {
                            console.log("leftLoader", mapToItem(canvas, 0, 0))
                        }
                    }
                    Loader {
                        id:rightLoader
                        onLoaded: {
                            console.log("rightLoader", mapToItem(canvas, 0, 0))
                        }
                    }
                }
            }
        }
    
        Canvas{
            anchors.fill: parent
            id:canvas
            Loader {
                id:pLoader
                anchors.horizontalCenter: parent.horizontalCenter
                //sourceComponent: rectangleComponent
            }
        }
    
        Rectangle {
            id: testMapToItemDot
            width: 20
            height: width
            radius: width / 2
            z: 1
            color: "darkblue"
        }
    
        function updateDotPosition(itemToMap) {
            var pos = testMapToItemDot.mapFromItem(
                        itemToMap,
                        (itemToMap.width - testMapToItemDot.width) / 2,   // these parameters are optional - I want to move the dot to
                        (itemToMap.height - testMapToItemDot.height) / 2) // the center of the object, not upper left corner
            testMapToItemDot.x += pos.x
            testMapToItemDot.y += pos.y
        }
    }
    

1 个答案:

答案 0 :(得分:0)

可以按以下方式访问已加载项目的位置和大小:Loader.item.xLoader.item.yLoader.item.widthLoader.item.height

如果这不是您想要的,请更准确地描述问题。

请查看此示例应用程序。我认为这正是你要找的 - 看看function updateDotPosition(itemToMap)。请注意,如果您将&#34;映射&#34;到一个没有移动的对象(示例中的点正在移动),该对象将是具有相同Canvasx值的y的兄弟,然后是该函数的结果将给出精确的点,从哪里画线。您不需要像我使用的那样使用+=

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    id: appWindow

    visible: true
    width: 1066
    height: 600

    property int maxRectangles: 5

    Component {
        id: rectangleComponent
        Rectangle {
            x: 110
            y: 30
            width: 100
            height: 100
            property var loaderSource
            Component.onCompleted: {
                color = Qt.lighter("red", maxRectangles / 7)
                if (maxRectangles-- > 0)
                    loaderSource = rectangleComponent
                else
                    loaderSource = undefined
            }
            Loader {
                sourceComponent: loaderSource
            }
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    updateDotPosition(parent)
                }
            }
        }
    }

    Loader {
        sourceComponent: rectangleComponent
    }

    Rectangle {
        id: testMapToItemDot
        width: 20
        height: width
        radius: width / 2
        z: 1
        color: "darkblue"
    }

    function updateDotPosition(itemToMap) {
        var pos = testMapToItemDot.mapFromItem(
                    itemToMap,
                    (itemToMap.width - testMapToItemDot.width) / 2,   // these parameters are optional - I want to move the dot to
                    (itemToMap.height - testMapToItemDot.height) / 2) // the center of the object, not upper left corner
        testMapToItemDot.x += pos.x
        testMapToItemDot.y += pos.y
    }
}

以下是您的示例的工作版本。这只是一个例子。很遗憾,很脏。这是因为我很难理解代码中发生了什么 - 我相信你不会遇到这个问题。此外,我使用了Timer,因为创建时的Rectangle个对象x,y等于0。我需要等一下。请不要在发布代码中使用它 - 这是糟糕的设计:)

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    id: appWindow

    visible: true
    width: 1066
    height: 600

    property var jsonData: [{"id":1,"pid":0},{"id":2,"pid":1},{"id":3,"pid":1},
        {"id":4,"pid":2},{"id":5,"pid":2},{"id":6,"pid":3},
        {"id":7,"pid":3},{"id":8,"pid":4},{"id":9,"pid":4},{"id":10,"pid":6}]
    property int maxRectangles: 5
    Component.onCompleted: {
        var color = Qt.lighter("red", maxRectangles / 7)
        pLoader.sourceComponent = rectangleComponent;
        var currItem = pLoader.item;
        currItem.color = "blue"
        currItem.text = 0
        connectedItems.push([currItem, null])

        var tmp = {};
        tmp[jsonData[0]["id"]] = currItem ;

        for(var index = 1; index < jsonData.length; index++) {
            color = Qt.lighter("red", index / 7)
            var sItem = jsonData[index]["pid"];
            if(tmp[sItem].rComponent.sourceComponent === null){
                tmp[sItem].rComponent.sourceComponent = rectangleComponent
                attachData(tmp[sItem].rComponent.item,index, color);
                tmp[jsonData[index]["id"]] = tmp[sItem].rComponent.item ;
                connectedItems.push([tmp[sItem].rComponent.item, null])
            }
            else {
                tmp[sItem].lComponent.sourceComponent = rectangleComponent
                attachData(tmp[sItem].lComponent.item,index, color);
                tmp[jsonData[index]["id"]] = tmp[sItem].lComponent.item ;
                connectedItems.push([tmp[sItem].lComponent.item, null])
            }
            if ( jsonData[index]["pid"] !== 0) {
                connectedItems[connectedItems.length - 1][1] = connectedItems[jsonData[index]["pid"] - 1][0]
            }
        }
    }
    function attachData(item, text, color){
        item.text = text;
        item.color = color
    }

    property var connectedItems: [];

    function paintConnection(objectFrom, objectTo) {
        var vectorStart = canvas.mapFromItem(
                    objectFrom, objectFrom.width / 2, objectFrom.height)

        var vectorEnd = canvas.mapFromItem(
                    objectTo, objectTo.width / 2,0)

        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.moveTo(vectorStart.x, vectorStart.y);
        ctx.lineTo(vectorEnd.x,vectorEnd.y);
        ctx.stroke();

        canvas.requestPaint()
    }

    Timer {
        id: paintLines
        interval: 100
        running: true
        onTriggered: {
            for (var i = 1 ; i < connectedItems.length ; i++) {
                paintConnection(connectedItems[i][1].rect, connectedItems[i][0].rect)
            }
        }
    }

    Component {
        id: rectangleComponent
        Column{
            property alias rComponent: rightLoader
            property alias lComponent: leftLoader
            property alias color: rect.color
            property alias text: myText.text
            property alias rect: rect
            spacing: 40
            //anchors.horizontalCenter: parent.horizontalCenter
            Rectangle {
                anchors.horizontalCenter: parent.horizontalCenter
                id:rect
                width: 100
                height: 100
                Text{
                    id:myText
                    font.pixelSize: 18
                    anchors.centerIn: parent
                    color:"white"
                }
                Component.onCompleted: {
                    console.log("Component.onCompleted", mapToItem(canvas, 0, 0))
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        updateDotPosition(parent)
                        //here, printed coordinate is my expected
                        //but i want line them after tree node loaded antomate
                        console.log("updateDotPosition", mapToItem(canvas, 0, 0))
                    }
                }
            }

            Row{
                spacing: 40
                anchors.horizontalCenter: parent.horizontalCenter
                Loader {
                    id:leftLoader
                    onLoaded: {
                        console.log("leftLoader", mapToItem(canvas, 0, 0))
                    }
                }
                Loader {
                    id:rightLoader
                    onLoaded: {
                        console.log("rightLoader", mapToItem(canvas, 0, 0))
                    }
                }
            }
        }
    }

    Canvas{
        anchors.fill: parent
        id:canvas
        Loader {
            id:pLoader
            anchors.horizontalCenter: parent.horizontalCenter
            //sourceComponent: rectangleComponent
        }
    }

    Rectangle {
        id: testMapToItemDot
        width: 20
        height: width
        radius: width / 2
        z: 1
        color: "darkblue"
    }

    function updateDotPosition(itemToMap) {
        var pos = testMapToItemDot.mapFromItem(
                    itemToMap,
                    (itemToMap.width - testMapToItemDot.width) / 2,   // these parameters are optional - I want to move the dot to
                    (itemToMap.height - testMapToItemDot.height) / 2) // the center of the object, not upper left corner
        testMapToItemDot.x += pos.x
        testMapToItemDot.y += pos.y
    }
}