Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic instantiation of QML objects?

Tags:

qt

qml

I want to draw many Rectangular's inside a QML. The coordinates for Rectangulars (x,y) will be calculated inside C++, and need to be passed to QML.

I tried to look for ListView or Column or Row elements (with Repeater), but non of this seems to solve the problem, because the elements are arranged like in 'tables'... I faced the lack of information on the web examples on such case.

To be more specific:
1. How to pass many coordinates for my Rectangular's to QML? (what data structure)
2. What mechanism should I use to display them?

like image 504
Knight of Ni Avatar asked Apr 14 '13 17:04

Knight of Ni


People also ask

How do I create a dynamic object in QML?

Creating a Component Dynamically To dynamically load a component defined in a QML file, call the Qt. createComponent() function in the Qt object. This function takes the URL of the QML file as its only argument and creates a Component object from this URL.

What is component onCompleted in QML?

Emitted after component "startup" has completed. This can be used to execute script code at startup, once the full QML environment has been established. The corresponding handler is onCompleted. It can be declared on any object. The order of running the onCompleted handlers is undefined.

What are QML objects?

A QML object type is a type from which a QML object can be instantiated. In syntactic terms, a QML object type is one which can be used to declare an object by specifying the type name followed by a set of curly braces that encompasses the attributes of that object.

What is alias in QML?

Unlike an ordinary property definition, which allocates a new, unique storage space for the property, a property alias connects the newly declared property (called the aliasing property) as a direct reference to an existing property (the aliased property).


1 Answers

You could simply:

import QtQuick 2.0

Rectangle {
    id: root
    height: 500
    width: 500

    property string sc: 'import QtQuick 2.0; Rectangle {width: 20; height: 20; color: "red"; Component.onCompleted: {x = Math.random() * parent.width; y = Math.random() * parent.height;}}'

    Component.onCompleted: {
        for (var i = 0; i < 10; ++i) Qt.createQmlObject(sc, root, 'obj' + i);
    }
}

This code will create the specified number of rectangles and position them randomly over the parent rectangle.

If generating the position in C++ is a necessity, you will have to create a custom C++ element, here is a basic example:

class Positioner : public QObject
{
    Q_OBJECT
public:
    explicit Positioner(QObject *parent = 0) : QObject(parent) {}

public slots:
    QPointF getPosition() {
        return QPoint(qrand() % 500, qrand() % 500);
    }    
};

Register it in main.cpp:

qmlRegisterType<Positioner>("TestComponent", 1, 0, "Positioner");

And finally use it, this time we use the Positioner's getPosition() C++ slot:

    import QtQuick 2.0
    import TestComponent 1.0

    Rectangle {
        id: root
        height: 500
        width: 500

        Positioner {id: myPositioner}

        property string sc: 'import QtQuick 2.0; Rectangle {width: 20; height: 20; color: "red"; Component.onCompleted: {var pos = myPositioner.getPosition(); x = pos.x; y = pos.y;}}'

        Component.onCompleted: {
            for (var i = 0; i < 10; ++i) Qt.createQmlObject(sc, root, 'obj' + i);
        }
    }

You can also use an existing QML file instead of a string, which is a little more convenient, since you get autocomplete. That would be your TestItem component and just for fun, its instances will delete themselves when clicked:

import QtQuick 2.0

Rectangle {
    width: 100
    height: 100
    color: "black"

    MouseArea {
        anchors.fill: parent
        onClicked: parent.destroy()
    }

    Component.onCompleted: {
        var pos = myPositioner.getPosition()
        x = pos.x
        y = pos.y
    }
}

And in your main QML file you instantiate it:

var component = Qt.createComponent("TestItem.qml")
component.createObject(root)

In case you don't want to instantiate a Positioner in QML and instead instantiate and use a single object in QML, you can do the following (in main.cpp):

Positioner p;
view.rootContext()->setContextProperty("sPositioner", &p);

And use in QML:

var pos = sPositioner.getPosition()
like image 189
dtech Avatar answered Oct 16 '22 17:10

dtech