0

I have dynamically created some QML rectangles on a Canvas. I wish to toggle whether the rectangles can be dragged around or not via the drag.target property, which is declared upon creation inside MouseArea. If the rectangles are draggable, I set drag.target to "parent". If not, I set it to "undefined".

The rectangles are stored in an array called verts[]. When I try to access the drag.target property, I get an error: TypeError: Value is undefined and could not be converted to an object

Here is the function that produces the error. I am feeding it an array of rectangles (verts) and a boolean.

function setVertsDraggable(verts, draggable) {
    for (var i=0; i<verts.length; i++) {
        if (draggable) {
            verts[i].drag.target = "parent";
        }
        else {
            verts[i].drag.target = "undefined";
        }
    }
}

I have tried feeding it the values of "parent" and "undefined" in quotes, without quotes, by setting another variable to undefined and passing that variable, and an empty string. Perhaps there are values defined in QML somewhere, such as QtQuick.(SomeClassOfEnums).undefined

But I suspect that the bigger problem is that it is not recognizing vert[i].drag.target as a property. Perhaps my path is wrong. I have tried

vert[i].drag.target
vert[i].MouseArea.drag.target
vert[i].Rectangle.MouseArea.drag.target
vert[i].Rectangle.drag.target

Additionally, I am able to set the color of those rectangles via javascript. The same syntax allows me to set the color without any error:

function setVertsColor(verts, color) {
    for (var i=0;i<verts.length; i++) {
        verts[i].color = color;
    }
}

So if this syntax works with color, what is the problem with the drag.target property?

If it helps, here is the command I use to dynamically create the rectangles:

var component = Qt.createComponent("Vertex.qml");
var vertex = component.createObject(parent, {x: xPos, y: yPos, width: size, color:"yellow"});

And here is the Vertex.qml which contains the definition of the rectangles, called by component.createObject(...)

import QtQuick

Rectangle {
    width: 8
    height: 8
    color: yellow
    property string tag: ""
    MouseArea {
        anchors.fill: parent
        drag.target: undefined
        drag.smoothed: false
        onReleased: {
            polyCanvas.requestPaint()
        }
    }
}

Please let me know if you have any ideas. I'm fresh out of 'em.

1 Answer 1

0

You can use a delegate/model to dynamically create and destroy components. You can also replace MouseArea with a DragHandler and TapHandler. By adding dragEnabled to your model we can control runtime dragability via property binding:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
    property list<var> pts: []
    Repeater {
        model: pts
        delegate: Vertex {
            x: modelData.x
            y: modelData.y
            dragEnabled: modelData.dragEnabled
        }
    }
    function addRandom(n) {
        do {
            let x = Math.floor(Math.random() * 300);
            let y = Math.floor(Math.random() * 300);
            let dragEnabled = Math.random() >= 0.5;
            pts.push( {x,y,dragEnabled} );
        } while (--n > 0);
    }
    Component.onCompleted: addRandom(3)
    footer: Frame {
        RowLayout {
            Button { text: "Clear"; onClicked: pts.length = 0 }
            Button { text: "Add 1"; onClicked: addRandom() }
            Button { text: "Add 10"; onClicked: addRandom(10) }
        }
    }
}

// Vertex.qml
import QtQuick
import QtQuick.Controls
Rectangle {
    width: 16
    height: 16
    color: dragEnabled ? "green" : "red"
    property bool dragEnabled: true
    DragHandler { enabled: dragEnabled }
    TapHandler { onTapped: dragEnabled = !dragEnabled }
}

You can Try it Online!

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the better approach and online demo! I see you have put everything in one file, rather than referencing the Vertex.qml file. That’s fine by me. But line 10 says “delegate: Vertex {“, and it is the only reference to “Vertex” or "delegate" that I can find. How does it know to associate what was in Vertex.qml (and is now in the same file) with line 10’s “delegate: Vertex”? The Vertex.qml code is just a Rectangle, and isn’t called Vertex, so I don’t understand how it’s connecting. Obviously it does, since it works on your live code page.
I’m also confused on how to reference the Vertex object, and how to feed it an empty array of vertices so that I can add them dynamically. And that begs the question of how to create a new Vertex dynamically and and add it to the Repeater.without using createObject()? Thanks for all the help.
You should be inspired by the for loop which grows the array model by JavaScript. The Repeater will, declarative, create/destroy objects as per the model changes.
Thanks for your help! I have it toggling now!
Oh... one further question. I'm new to QML and javascript, so can you tell me why you have declared "property list<var> pts:" the way you did? Why the <var> syntax? I would have thought just "property var pts: []" would work. What is the list<var> doing for us?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.