Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Call for Presentations - Qt World Summit

    [Solved] Item::mapToItem(): wrong returned values

    QML and Qt Quick
    4
    9
    9224
    Loading More Posts
    • 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.
    • j1elo
      j1elo last edited by

      UPDATE 2: Solved. I was using the function in a wrong way!
      Solution: http://qt-project.org/forums/viewreply/114331/


      UPDATE: Read next post for a minimal example code.


      Hi all!
      I'd like to write my very first message in this forum since the acquisition by Digia and creation of the Qt Project.

      My problem is that Item::mapToItem(null, x, y) is giving wrong values. As I'm a beginner about the new Qt Quick 2, and QML in general, it is most probably due to a misuse but I cannot find it.

      A maybe-not-so-minimal working example to show my case follows. It creates a couple of rectangles with a Repeater, and fails at finding the central point for the second one (stored in posX, posY properties). Being squares of size 25, I'd expect the second one to stay at (0, 25), with its center at (0, 37.5), but mapToItem() says that it is placed at (0, 50), so the center calculations go for (0, 67.5) instead.

      I would bet the culprit is the reparenting done to the items, but that's the only way I found to have a clean list of Rectangles: if the Repeater was placed inside the Column, as most Qt examples show, then the Column's children would include that Repeater, which is not nice for code abstraction (other parts of the code shouldn't have to deal with that detail).

      @
      import QtQuick 2.0

      Item {
      id: root
      width: buttonSize
      height: (2 * buttonCount + 1) * buttonSize

      property int buttonCount: 2
      property real buttonSize: 25
      property alias buttons: container.children
      
      Component.onCompleted: {
          console.log("root: onCompleted")
          for (var i = 0; i < buttons.length; ++i) {
              console.log("root:", buttons[i].buttonId, "x", buttons[i].x, "y", buttons[i].y)
              buttons[i].posUpdate()
          }
      }
      
      Column {
          id: container
          anchors {
              fill: parent
      

      // topMargin: buttonSize
      }
      // spacing: buttonSize
      }

      Repeater {
          model: buttonCount
      
          Item {
              // Use a dummy Item to wrap our Socket element.
              // The wrapper will become child of the Repeater's parent,
              // while the Socket will be reparented to our container.
              id: wrapper
      
              Rectangle {
                  id: button
                  width: buttonSize; height: buttonSize; radius: buttonSize
                  color: "red"
      
                  property string buttonId: "button_" + index
                  property real posX
                  property real posY
      
                  function posUpdate() {
                      console.log("button: posUpdate", buttonId, "button.x", x, "button.y", y, "mapToItem().x", mapToItem(null, x, y).x, "mapToItem().y", mapToItem(null, x, y).y)
                      posX = button.mapToItem(null, x, y).x + (buttonSize / 2.0)
                      posY = button.mapToItem(null, x, y).y + (buttonSize / 2.0)
                      console.log("button: posUpdate", buttonId, "posX", posX, "posY", posY)
                  }
      
                  Component.onCompleted: {
                      parent = container
                  }
              }
          }
      }
      

      }
      @

      Any help would be appreciated :-)

      1 Reply Last reply Reply Quote 0
      • j1elo
        j1elo last edited by

        OK I have a new, minimal example to show this problem:

        @
        import QtQuick 2.0

        Item {
        id: window
        width: 25; height: 50

        Rectangle {
            id: button_1
            x: 0; y: 0
            width: 25; height: 25
            color: "red"
        
            Component.onCompleted: {
                var obj = mapToItem(null, x, y)
                console.log("[button_1]", "x:", x, "y:", y, "mapToItem().x:", obj.x, "mapToItem().y", obj.y)
            }
        }
        
        Rectangle {
            id: button_2
            x: 0; y: 25
            width: 25; height: 25
            color: "pink"
        
            Component.onCompleted: {
                var obj = mapToItem(null, x, y)
                console.log("[button_2]", "x:", x, "y:", y, "mapToItem().x:", obj.x, "mapToItem().y", obj.y)
            }
        }
        

        }
        @

        Expected output:
        @[button_2] x: 0 y: 25 mapToItem().x: 0 mapToItem().y 25@

        Obtained output:
        @[button_2] x: 0 y: 25 mapToItem().x: 0 mapToItem().y 50@

        1 Reply Last reply Reply Quote 0
        • T
          tzander last edited by

          Responding to a weird issue, that may even be the core problem;
          @
          "if the Repeater was placed inside the Column [] then the Column’s children would include that Repeater
          which is not nice for code abstraction (other parts of the code shouldn’t have to deal with
          that detail)."
          @

          This looks weird, the idea behind QML and scenegraphs in general is that this kind of details are irrelevant to the rest of the codebase.
          Just because there is a repeater in between should have zero effect on other code.

          You use the name (id: foo) of an element.

          Maybe you are trying to fetch an item from a C++ code using the QObject:child() method, I would strongly suggest you do not do that ;)

          Maybe you can explain exactly what the problem is that you ran into that made you reparent? Its likely that its the one that should be solved first.

          1 Reply Last reply Reply Quote 0
          • j1elo
            j1elo last edited by

            Note that in my second post I included a minimal example which shows the same wrong results on Item::mapToItem(), without any reparenting.

            Replying to your question:

            My project is pure QML + JavaScript so far; I just want to process a list of items all in the same way, which means all must be of the same type.

            I'm using a Canvas item which paints lines; these lines are parametrized by properties of some items, previously instantiated inside a Column. Ideally, the JS code on the Canvas::onPaint() method would use a "for" loop over all of the Colum's children, but that approach doesn't work because one of the children is a Repeater, thus not being of the expected type and not having the expected properties.

            Maybe I'm not doing this the "QML way"? But I didn't find a better way...

            1 Reply Last reply Reply Quote 0
            • C
              chrisadams last edited by

              Passing in null as the first parameter of mapToItem is currently broken. There are some changes in codereview to address this issue, but currently the script engine returned is null. In the future, this function should map it from top left of the top-level application window; currently the behaviour is undefined.

              Cheers,
              Chris.

              1 Reply Last reply Reply Quote 0
              • j1elo
                j1elo last edited by

                I assumed that there was no need for a bug report because this issue is already a work in progress, but after searching in the Qt bugreports site for "mapToItem" and "mapFromItem", I cannot find any proper report about this issue.

                So I'm adding one for being able to track this bug.

                Thank you all for the ideas and chrisadams for the explanation

                1 Reply Last reply Reply Quote 0
                • ?
                  A Former User last edited by

                  Hi,

                  parameters x,y are not required in maptoItem. Just put it as 0 for both x and y and then try.

                  Regards
                  ansif

                  1 Reply Last reply Reply Quote 0
                  • j1elo
                    j1elo last edited by

                    [quote author="ansifpi" date="1360752153"]Hi,

                    parameters x,y are not required in maptoItem. Just put it as 0 for both x and y and then try.

                    Regards
                    ansif [/quote]

                    Thank you very much!!
                    Thanks to this comment I realized that the mapToItem() function is working properly, it's just that I was misusing it in my examples!! The cause of the problem is a conceptual error.

                    Note that in both examples I was using
                    @mapToItem(null, x, y)@
                    which would map to the Window the point (x, y) inside the rectangle. In my second example, the point (0, 25) inside of the second rectangle would effectively correspond to the point (0, 50) in the Window.

                    Correct way of using the function in my sample would be:
                    @mapToItem(null, 0, 0)@

                    And for my specific need of mapping the center point:
                    @mapToItem(null, width / 2.0, height / 2.0)@

                    Thanks everybody for the help.

                    1 Reply Last reply Reply Quote 0
                    • ?
                      A Former User last edited by

                      Good luck!!!!!!!!!

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post