Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to track the coordinates of draggable, dynamically-created Qt Quick objects?
Forum Updated to NodeBB v4.3 + New Features

How to track the coordinates of draggable, dynamically-created Qt Quick objects?

Scheduled Pinned Locked Moved QML and Qt Quick
7 Posts 2 Posters 3.0k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JKSHJ Offline
    JKSHJ Offline
    JKSH
    Moderators
    wrote on last edited by
    #1

    Suppose I want Rectangles that can be dragged around a screen. I also want a Line (adapted from http://www.developer.nokia.com/Community/Wiki/Drawing_lines_in_QML ) that connects the centers of 2 Rectangles. It's straightforward to achieve this using property binding, if everything is created statically:
    @
    import QtQuick 2.0

    Rectangle {
    width: 800
    height: 600

    Rectangle {
        id: draggableBox1
        width: 100
        height: 100
        color: "green"
    
        MouseArea {
            anchors.fill: parent
            drag.target: draggableBox1
        }
    }
    
    Rectangle {
        id: draggableBox2
        width: 100
        height: 100
        color: "green"
    
        MouseArea {
            anchors.fill: parent
            drag.target: draggableBox2
        }
    }
    
    Line {
        x1: midpoint(draggableBox1.x, draggableBox1.width)
        y1: midpoint(draggableBox1.y, draggableBox1.height)
        x2: midpoint(draggableBox2.x, draggableBox2.width)
        y2: midpoint(draggableBox2.y, draggableBox2.height)
    
        function midpoint(origin, delta) {
            return origin+delta/2
        }
    }
    

    }
    @

    However, I can't figure out how to do this dynamically. Here's what I want:

    Draggable boxes are to be created one at a time (e.g. using Qt.createQmlObject()), at the user's command. The first box will not be connected to anything in the beginning. However, the user can select any existing box, and spawn another box from it. The new box will be connected to the selected box via a Line.

    I can't bind the line's endpoints to the boxes' properties, because dynamically-created objects don't have ids. How can I get the Lines to move appropriately when I drag the boxes around?

    Thanks in advance!

    Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      Ids are not available, but you can use QObject names (in C++ :)) and QObject::findChildren().

      In QML, I think what you could do is to push every object you create onto a JavaScript array and then use that to periodically update the viewport. Or, add a property to your Rectangle object that would hold a reference to Line object... I would need to think about it a bit more to give you a good answer, but maybe those small hints will help :)

      (Z(:^

      1 Reply Last reply
      0
      • JKSHJ Offline
        JKSHJ Offline
        JKSH
        Moderators
        wrote on last edited by
        #3

        [quote author="sierdzio" date="1370977017"]Ids are not available, but you can use QObject names (in C++ :)) and QObject::findChildren().[/quote]Thanks for this tip! That led me to "this page":http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-interactqmlfromcpp.html#accessing-loaded-qml-objects-by-object-name -- I haven't tried it yet, but it looks like I can use a QTimer to periodically query the Rectangles' positions and update the Lines using QObject::setProperty(). Updating every 150 ms should be fine.

        I'm still interested to see if there's a way to do this directly in QML.

        [quote]In QML, I think what you could do is to push every object you create onto a JavaScript array and then use that to periodically update the viewport. Or, add a property to your Rectangle object that would hold a reference to Line object... I would need to think about it a bit more to give you a good answer, but maybe those small hints will help :)[/quote]Holding references sounds good. If I can get the Lines to remember which 2 Rectangles they're attached to, then the Lines can compute their own endpoints. So the question now is: How do I make a dynamically-created object hold references to other dynamically-created objects in QML?

        EDIT: "This page":http://supportforums.blackberry.com/t5/Cascades-Development/Array-of-QML-objects/td-p/2002103 suggests that referencing QML objects isn't really possible :( The posters talked about using JavaScript objects for storing and manipulating dynamic data, but I'm interested in reading the coordinates of dynamic graphical objects

        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

        1 Reply Last reply
        0
        • sierdzioS Offline
          sierdzioS Offline
          sierdzio
          Moderators
          wrote on last edited by
          #4

          See this, for example:

          • "accessing children":https://github.com/sierdzio/closecombatfree/blob/1129caa84a07fad9001a371bc22d9e00ef93bca9/qml/scenarios/Scenario.qml#L275
          • "children arrays as properties":https://github.com/sierdzio/closecombatfree/blob/1129caa84a07fad9001a371bc22d9e00ef93bca9/qml/scenarios/Scenario.qml#L41 and "this":https://github.com/sierdzio/closecombatfree/blob/1129caa84a07fad9001a371bc22d9e00ef93bca9/qml/maps/Map.qml#L39

          Feel free to roam through the whole project. If you take a look at newer commits (say, after September 2012) you will see how it can be done in C++ (I have moved most of "hardcore" functionality to C++). The project requires Qt5, and works well with QtCreator.

          EDIT: thing you really want to take a look at is aimLine, updateAimLine() and aimLineTimer - that stuff looks very much like what you are trying to achieve.

          (Z(:^

          1 Reply Last reply
          0
          • JKSHJ Offline
            JKSHJ Offline
            JKSH
            Moderators
            wrote on last edited by
            #5

            sierdzio, thank you for sharing! Your code has very helpful examples on referencing QML objects through JavaScript arrays. This code does the trick:

            @
            import QtQuick 2.0

            Rectangle {
            id: root
            width: 800
            height: 600

            // Arrays to hold references to dynamic objects
            property var rects: new Array
            property var lines: new Array
            
            // Periodically update Line position
            Timer {
                interval: 25
                running: true
                repeat: true
                onTriggered: {
                    lines[0].x1 = rects[0].x
                    lines[0].y1 = rects[0].y
                    lines[0].x2 = rects[1].x
                    lines[0].y2 = rects[1].y
                }
            }
            
            Component.onCompleted: {
                // Dynamically create draggable boxes
                for (var i = 0; i < 2; ++i)
                {
                    var rect = Qt.createQmlObject(
                                 'import QtQuick 2.0\n'
                                +'Rectangle {\n'
                                +'    x: ' + i*100 + '\n'
                                +'    y: ' + i*100 + '\n'
                                +'    color: "lightblue"\n'
                                +'    width: 100\n'
                                +'    height: 100\n'
                                +'    MouseArea {\n'
                                +'        anchors.fill: parent\n'
                                +'        drag.target: parent\n'
                                +'    }\n'
                                +'}',
                        root, "dynamicRect");
            
                    rects.push(rect)
                }
            
                // Dynamically create Line
                var comp = Qt.createComponent("Line.qml");
                var line = comp.createObject(root)
                lines.push(line)
            }
            

            }
            @

            Interestingly, if I create my Line using Qt.createQmlObject(), I can dynamically bind the Line endpoints and get rid of the timer:
            @
            var line = Qt.createQmlObject(
            'import QtQuick 2.0\n'
            +'Rectangle {\n'

                  ...
            
                +'    property real x2: rects['+idx2+'].x\n'
                +'    property real y2: rects['+idx2+'].y\n' // Auto-updates when I move the Rectangle :)
                +'}', root, "dynamicLine.qml")
            

            @

            However, if I try to bind using Qt.createComponent(), it only assigns the initial value -- the values don't update on-the-fly:
            @
            var comp = Qt.createComponent("Line.qml");
            var line = comp.createObject(root, {"x1": rects[0].x, ...) // Once-off assignment, not property binding :(
            @

            Is that expected behaviour?

            Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

            1 Reply Last reply
            0
            • sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by
              #6

              I'm happy to hear that, you are very welcome! :)

              That is a really cool feature you've discovered with Qt.createQmlObject(). I don't know whether the difference with Qt.createComponent() is intentional. You might want to experiment with "Binding":http://qt-project.org/doc/qt-4.8/qml-binding.html element. I have not used it myself.

              (Z(:^

              1 Reply Last reply
              0
              • JKSHJ Offline
                JKSHJ Offline
                JKSH
                Moderators
                wrote on last edited by
                #7

                So apparently, the parameters passed into "Component.createObject()":http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-component.html#createObject-method are used for inital value assignment only. To do binding, we need to pass in the value returned by "Qt.binding()":http://qt-project.org/doc/qt-5.0/qtqml/qml-qt.html#binding-method -- I think that's nicer than creating Binding objects, which I'll also have to create dynamically

                Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved