September 23, 2011

njeisecke njeisecke
Lab Rat
50 posts

How to track the global position of an Item?

 

Hi!

I would like to track the global position of an item (relative to the root item). Property binding to the item’s x and y coordinates does not help because they are relative to its parent, so mapToItem would not be reevaluated if the parent is moved.

Maybe there’s something in Qml that I’ve missed, so before I start working on a C++ extension that provides the information (should be possible, I guess), I’m asking here.

Thanks!

Nils

11 replies

September 26, 2011

mbrasser mbrasser
Lab Rat
452 posts

Hi Nils,

I don’t think you are missing anything: the built-in QML elements don’t provide any simple ways of dealing with global position changes.

Regards,
Michael

October 6, 2011

njeisecke njeisecke
Lab Rat
50 posts

ok, thanks. I’ll look into doing this from the C++ side.

November 17, 2011

diro diro
Lab Rat
39 posts

Hi Njeisecke,
I think you really miss something, I use mapFromItem()/mapToItem() function to get the item’s position in global scene.

http://doc.qt.nokia.com/4.7-snapshot/qml-item.html#mapFromItem-method

The document says:
Maps the point (x, y), which is in item’s coordinate system, to this item’s coordinate system, and returns an object with x and y properties matching the mapped cooordinate.
If item is a null value, this maps the point from the coordinate system of the root QML view.

November 17, 2011

njeisecke njeisecke
Lab Rat
50 posts

Hi diro,

the problem is that x and y do not change if for example the item’s parent is being moved. So in this case mapFromItem would not be reevaluated event though the global position changes.

Nils

November 18, 2011

diro diro
Lab Rat
39 posts

Hi Nils,
I think the event issue could be solved in QML, the main idea is that if the itme’s coordinate won’t change but its parent will, how about leverage its notify?

The original code may be:
subpanel.mapToItem(null, 0, 0).x
than, becomes:
subpanel.mapToItem(null, (basepanel.width * 0) + 0, 0).x

PS.The basepanel.width may changed to other properties, such as x, y, height… and so on, depends on your case

The following is my full sample code, you may try it.

  1. import QtQuick 1.1
  2.  
  3. Rectangle {
  4.     id: basepanel
  5.     anchors.leftMargin: 10;
  6.     anchors.rightMargin: 10;
  7.     width:800;
  8.     height: 480;
  9.     color:"#333333";
  10.  
  11.     Rectangle {
  12.         id: subpanel
  13.         width: 657
  14.         height: 294
  15.         anchors.horizontalCenter: parent.horizontalCenter
  16.         anchors.verticalCenter: parent.verticalCenter
  17.         color:"black"
  18.         border.color: "#777777"
  19.     }
  20.  
  21.     Text {
  22.         id: status
  23.         x: parent.width/2
  24.         y: parent.height/2
  25.         color: "#ffffff"
  26.         text: qsTr("Global Position of item subpanel:") +
  27.               subpanel.mapToItem(null, (basepanel.width * 0) + 0, 0).x +
  28.               "," +
  29.               subpanel.mapToItem(null, (basepanel.width * 0) + 0, 0).y;
  30.         visible: true
  31.         styleColor: "#a23e3e"
  32.     }
  33. }

Besides, if you really want to monitor many properties of basepanel, you may use

  1.  (basepanel.width * basepanel.height * basepanel.x * basepanel.y * 0)

November 18, 2011

njeisecke njeisecke
Lab Rat
50 posts

Hi Diro,

thank you very much for posting your example code.

The problem is that “subpanel” is supposed to be a component. It doesn’t know if the moving item is it’s parent, parent parent oder parent parent parent, …

So to get it right you would have to iterate through the parent chain and bind to each x and y property. You also have to take possible reparenting into account.

I guess you could do this in pure Qml. However I doubt that the amount of necessary bindings and function calls would give reasonable performance in more complex applications.

So as soon as time admits, I’m going to check what could be done from the C++ side. The downside of this approach might be that I’ll have to do it again for the scene graph.

Nils

November 18, 2011

diro diro
Lab Rat
39 posts

Hi Nils,
Okay, I understand your problem now. And I also interested in your C++ solution, hope you can share with us in the future, thanks :-)

March 22, 2012

Merinas Merinas
Lab Rat
90 posts

Hi,

Did you get any progress on that ?

Merinas

March 22, 2012

njeisecke njeisecke
Lab Rat
50 posts

No, not really.

I’ve been talking about this with some Qt developers at DevDays and they came to the conclusion that this would be pretty difficult to implement generally without sacrificing overall system performance.

You should be able to connect to all xChanged and yChanged signals of the item’s parent chain but I have not tried this yet. Seems to be the only possibility though.

Nils

March 22, 2012

feldifux feldifux
Lab Rat
106 posts

Yes, connecting an item’s own x/y-Changed signals to the xChanged and yChanged signals of all parents is possible – I tried it and it works fine. But I do not recommend it for items that change often, because the performance penalty is significant! If you have control over the items you want to track, it would be the best solution to write a custom QDeclarativeItem in C++ and overwrite the itemChange function from QGraphicsItem: QGraphicsItem itemChange function [doc.qt.nokia.com].

Regarding the doc, this also has a performance impact, but presumably not that much compared to the parent-signal-connection approach.

Chris

March 23, 2012

Merinas Merinas
Lab Rat
90 posts

Maybe we need a specific Item to provide this functionnality or add a new property in item to add tracking global pos.

For now I used the flag ItemSendsScenePositionChanges in a new item. My purpose is to anchor a punctual item to another punctual item anywhere ni the QML tree here what I used :

  1. class AnchorPoint : public QDeclarativeItem
  2. {
  3.     Q_OBJECT
  4.     Q_DISABLE_COPY(AnchorPoint)
  5.     Q_PROPERTY(AnchorPoint* anchorTo READ anchorTo WRITE setAnchorTo NOTIFY anchorToChanged)
  6.  
  7. public:
  8.     AnchorPoint(QDeclarativeItem *parent = 0)
  9.     : QDeclarativeItem(parent)
  10.     , m_anchorTo(NULL)
  11.     {
  12.         setFlag(ItemSendsScenePositionChanges, true);
  13.     }
  14.     ~AnchorPoint(){}
  15.  
  16.     AnchorPoint* anchorTo() const { return m_anchorTo;}
  17.     void setAnchorTo(AnchorPoint* anchorPoint)
  18.     {
  19.         if(anchorPoint != m_anchorTo)
  20.         {
  21.             if(m_anchorTo != NULL)
  22.             {
  23.                   disconnect(m_anchorTo,SIGNAL(scenePosChanged()),this,SLOT(anchorPosChanged()));
  24.             }
  25.             m_anchorTo = anchorPoint;
  26.             if(m_anchorTo != NULL)
  27.            {
  28.                 connect(m_anchorTo,SIGNAL(scenePosChanged()),this,SLOT(anchorPosChanged()));
  29.            }
  30.         }
  31.     }
  32.  
  33.     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
  34.     {
  35.         if (change == ItemScenePositionHasChanged && scene())
  36.         {
  37.             emit scenePosChanged();
  38.         }
  39.         return QGraphicsItem::itemChange(change, value);
  40.     }
  41.  
  42. signals:
  43.     void anchorToChanged();
  44.     void scenePosChanged();
  45.  
  46. protected slots:
  47.     void anchorPosChanged()
  48.     {
  49.         QGraphicsItem* anchorParent = (QGraphicsItem*)m_anchorTo->parentItem();
  50.         if(anchorParent==NULL)
  51.         {
  52.             qDebug() << "Item anchored to has no parent : can't anchored to it";
  53.             return;
  54.         }
  55.  
  56.         if(parentItem()==NULL)
  57.         {
  58.             qDebug() << " Item has no parent : can't be anchored ";
  59.             return;
  60.         }
  61.  
  62.         QPointF anchorPos = m_anchorTo->pos();
  63.         setPos(anchorParent->mapToItem((const QGraphicsItem*)parentItem(),anchorPos));
  64.     }
  65.  
  66. private:
  67.     AnchorPoint* m_anchorTo;
  68. };

 
  ‹‹ how to use landmark model in QML MAP ELEMENT??      [Solved] "Widgets must be created in the GUI thread" error ››

You must log in to post a reply. Not a member yet? Register here!