Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
On 25/11/2010, at 7:25 AM, ext Charley Bay wrote: This does raise the next question (or two): (1) The QML implies an instantiation tree of items in a parent-child relationship. That's great, and part of what makes QML so easy to use. Is this tree special in any way? For example, if I dynamically create items, or explicitly re-parent-items, are they treated differently in any way from the ones hard-coded in the QML? (I've observed strange behavior attempting to re-parent a nested item that was hard-coded to a peer of the parent, effectively removing it from its hard-coded parent.) One difference is that the items created by the instantiation tree cannot be destroyed from QML (you cannot call destroy() on them the way you can for dynamically created items). I can't think of any differences in reparenting though -- do you remember what the strange behavior was that you observed? Fun stuff! It works, and I'm happy. However, I'd feel better if one of the Trolls would comment that I'm doing acceptable as-designed practice, or if I should think about doing this differently (e.g., how to implement a C++ layout container operating on items dynamically added/removed from QML). I'm not certain, but it's probably more of an optimization than anything else that ItemChildAddedChange is not triggered for items in the instantiation tree. If you haven't done so already, I'd suggest looking at the implementation of the QML positioners (Row, Column, Grid, etc) -- they layout all items (not just those added dynamically), but might give you some additional ideas for your layout container. Regards, Michael ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
snip, boundingRect() not working as expected? Ummm... sorry to add confusion, but it is possible (seems likely to me) that I observed an order of operations on initialization problem ... I've re-structured my code, and now *both* the boundingRect() and width/height properties work properly. In the previous implementation, I had instantiation combined with reparenting, and if the re-parenting happened before the instance was fully constructed, then the size used during the re-parenting was incorrect (the item later correctly resized itself after its attributes were set). This is somewhat further complicated by the fact that setting attributes on my QDeclarativeItem-derived types triggered signals for updates elsewhere. It is interesting that I saw -1,-1 for default width/height before initial size calculations, but I suppose that doesn't matter. So... sorry for the confusion. This has been a (very) good learning exercise for me, though: I think I better understand the dynamics of the QDeclarativeItem (QObject) world as it relates to the QGraphicsItem (non-QObject) world. Thanks for the help! --charley ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
Girish spaketh: boundingRect() works as I would expect. Can you provide some sample code? snip, example extracting good coordinates from QDeclarativeItem::boundingRect() Was your C++ code inside an application-derived QDeclarativeItem::itemChange()? I'm Qt4.7.0, Win7-64bit, MSVC++2008. I tried it again to make sure there was no difference between my dynamic_cast() and your qobject_cast(), and they behave the same. (I suppose I should be doing qobject_cast anyway). My code subset: - //FILE: MyQml.qml import Qt 4.7 import MyPluginLayout 1.0 Rectangle { MyPluginLayout { id: myPluginLayout } Text { text: hello parent: myPluginLayout width: 40 height: 30 } } - //FILE: MyPluginLayout.cpp class MyPluginLayout : public SdqDeclarativeItem { ...Q_OBJECT, Q_PROPERTY, ... public: virtual QVariant itemChange( QGraphicsItem::GraphicsItemChange change, const QVariant value) { if(change == QGraphcisItem::ItemChildAddedChange) { QGraphicsItem* graphics_item = value.valueQGraphicsItem*(); ASSERT(graphics_item); //DEBUGGER SHOWS VTABLE FOR graphics_item TO BE A QDeclarativeText QRectF bounding_rect; bounding_rect = graphics_item-boundingRect(); // (0,0,-1,-1) bounding_rect = qobject_castQGraphicsObject*(graphics_item)-boundingRect(); // (0,0,-1,-1) bounding_rect = qobject_castQDeclarativeItem*(graphics_item)-boundingRect(); // (0,0,-1,-1) double value; value = qobject_castQObject*(graphics_item)-property(width).toReal(); // 40 value = qobject_castQObject*(graphics_item)-property(height).toReal(); // 30 value = dynamic_castQObject*(graphics_item)-property(width).toReal(); // 40 value = dynamic_castQObject*(graphics_item)-property(height).toReal(); // 30 //...do layout stuff to place item added... } }; --- On the bright side, all of the boundingRect() calls agree. They just don't have the width/height property values. So, I'm using QObject::property(), which seems to always work. --charley ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
snip, detect parent/child changes from QML in C++ Martin spaketh: QGraphicsItem::itemChange() may do what you want: http://doc.qt.nokia.com/4.7-snapshot/qgraphicsitem.html#itemChange Works great! Thanks! Related question: Now that I'm in the QGraphicsItem world, which is *not* a QObject with properties, how does QML expose attributes (since those are *all* properties based)? For example, the QGraphicsItem::boundingRect() is always (0,0,-1,-1), even though the referenced QML component *has* width and height. Similarly, the QGraphicsItem::opaqueArea()::boundingRect() is always (0,0,0,0). Does the QGraphicsItem have *any* opinion about or state from attributes in the QML element? (e.g., what attributes can I trust in the QGraphicsItem as being those used by the QML element?) What is the intended mechanism by which I interrogate the QGraphicsItem? (Is the expectation that the user will merely attempt to downcast to QGraphicsObject or QDeclarativeItem, handling the scenarios where it is not that type?) For examle, I *assume* that the MouseArea will trigger child notification, but it is not a QDeclarativeItem. In contrast, a Rectangle{} or Text{} trigger child notification, and happen to be QDeclarativeItem instances. Thanks! --charley ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
Hi Charley, On Wed, Nov 24, 2010 at 7:42 PM, Charley Bay charleyb...@gmail.com wrote: snip, detect parent/child changes from QML in C++ Martin spaketh: QGraphicsItem::itemChange() may do what you want: http://doc.qt.nokia.com/4.7-snapshot/qgraphicsitem.html#itemChange Works great! Thanks! Related question: Now that I'm in the QGraphicsItem world, which is *not* a QObject with properties, how does QML expose attributes (since those are *all* properties based)? QML works with properties exposed through the metaobject system (Q_PROPERTY). So, items have to be extend QObject at some point. AFAIK, QML supports properties exposed through QObject and user visible items must be QGraphicsObject or QDeclarativeItem (there are restrictions like the component's root item must be a QDeclarative item etc). For example, the QGraphicsItem::boundingRect() is always (0,0,-1,-1), even though the referenced QML component *has* width and height. Similarly, the QGraphicsItem::opaqueArea()::boundingRect() is always (0,0,0,0). Does the QGraphicsItem have *any* opinion about or state from attributes in the QML element? (e.g., what attributes can I trust in the QGraphicsItem as being those used by the QML element?) QDeclarativeView builds on QGraphicsView. So, QGraphicsItem::boundingRect is still very much used. For a component, the QGraphicsItem of the component will return the (0, 0, width, height), so I think your testing above is probably incorrect. I think opaqueArea is used only for obscurity detection which is not used in QML and thus left unimplemented. What is the intended mechanism by which I interrogate the QGraphicsItem? As I understand, all QGraphicsItem API should still work as expected for QML items. (Is the expectation that the user will merely attempt to downcast to QGraphicsObject or QDeclarativeItem, handling the scenarios where it is not that type?) For examle, I *assume* that the MouseArea will trigger child notification, but it is not a QDeclarativeItem. In contrast, a Rectangle{} or Text{} trigger child notification, and happen to be QDeclarativeItem instances. MouseArea is a QDeclarativeItem. Think of it as a transparent overlay child item that positions itself over the parent. I do not know why it does not trigger child notifications. Girish ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
Ok, update, I couldn't wait to try this out (results below): charley spaketh: Related question: Now that I'm in the QGraphicsItem world, which is *not* a QObject with properties, how does QML expose attributes (since those are *all* properties based)? Giresh respondeth: QML works with properties exposed through the metaobject system (Q_PROPERTY). So, items have to be extend QObject at some point. AFAIK, QML supports properties exposed through QObject and user visible items must be QGraphicsObject or QDeclarativeItem (there are restrictions like the component's root item must be a QDeclarative item etc). Hmmm ... good point. In theory, this means that *if* I could guarantee that all child notification events came from QML, I *should* be able to do a C++ cross-cast to cast my QGraphicsItem* to a QObject*, and then pull out my properties. Very interesting. It will look a little weird, because QGraphicsItem has no base class, but I think it should work? (I'll give it a try.) My original confusion was that I didn't know if it was appropriate to *assume* any castable type (e.g., from QGraphicsItem to a QGraphicsObject or QDeclarativeItem). I'm still a little nervous about assuming the child event would be from any QObject type (that means my class would be usable fto interface from QML, and select C++ implementations) because the QGraphicsView would otherwise manage child QGraphicsItem instances (with no QObject in the hierarchy). However, if that's the intended design, I could probably live with it. The C++ cross-cast *WORKS* (Qt4.7.0,Win-Commercial,Win7-64bit,MSVC++2008): QVariant MyClass::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant value) { if(change == QGraphicsItem::ItemChildAddedChange) { QGraphicsItem* graphics_item = value.valueQGraphicsItem*(); // ALWAYS NON-NULL QObject* my_object = dynamic_castQObject*(graphics_item); // ALSO NON-NULL FOR THIS CASE ...extracting properties from my_object works !! } } Looking in the debugger, the vtable for my_object is for a QDeclarativeText, so I can see that it is my QML Text{} item. Interestingly, the itemChange is NOT triggered for children explicitly nested *within* the parent from QML, but *is* triggered for items explicitly re-parented: //FILE: MyQml.qml Rectangle { MyCppClass { id: myCppClass Text { text: hello } // DOES NOT TRIGGER QGraphicsItem::itemChange() MouseArea { anchors.fill: parent } // DOES NOT TRIGGER QGraphicsItem::itemChange() } Text { text: world parent: myCppClass // YES, DOES TRIGGER QGraphicsItem::itemChange() } } For my particular case, this is accidentally a good thing: I don't want to re-parent the nested MouseArea, but I *do* want to re-parent any added item (e.g., I'm implementing a layout-type container). Because this accidentally works the way I want, I won't complain. However, if this is undocumented behavior, then I need to somehow test children to see if they are something I want to parent (like Text{} items), versus *not* parent (like nested MouseArea{} items). This is acceptable to me: I'll have to merely understand that I shouldn't be hard-coding Text{} children with the assumption that the parent layout container will move them (because it won't, because the QGraphicsItem::itemChange() won't be triggered). This does raise the next question (or two): (1) The QML implies an instantiation tree of items in a parent-child relationship. That's great, and part of what makes QML so easy to use. Is this tree special in any way? For example, if I dynamically create items, or explicitly re-parent-items, are they treated differently in any way from the ones hard-coded in the QML? (I've observed strange behavior attempting to re-parent a nested item that was hard-coded to a peer of the parent, effectively removing it from its hard-coded parent.) (2) If all children in memory are treated the same (e.g., (1) does not imply that the different types of children are treated differently based on how they are defined and instantiated), then this would imply some kind of on-load-difference for firing signals, possibly related to order-of-load (or connection of signals/slots after the items were loaded). [Of course, in this case, technically the hard-coded children were *not* re-parented, but were merely hard-coded-parented, and the Trolls could merely state that this was as designed behavior.] For example, the QGraphicsItem::boundingRect() is always (0,0,-1,-1), even though the referenced QML component *has* width and height. Similarly, the QGraphicsItem::opaqueArea()::boundingRect() is always (0,0,0,0). Does the QGraphicsItem have *any* opinion about or state from attributes in the QML element? (e.g., what attributes can I trust in the QGraphicsItem as being those used by the QML element?) QDeclarativeView builds on QGraphicsView. So,
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
Hi, On Thu, Nov 25, 2010 at 2:55 AM, Charley Bay charleyb...@gmail.com wrote: I confirmed that these *do not* work for me: ...with a Text { width: 50; height: 20 } on the QML side, QGraphicsItem::boundingRect() // ALWAYS RETURNS QRectF(0,0,-1,-1) QGraphicsItem::opaqueArea().boundingRect() // ALWAYS RETURNS QRectF(0,0,0,0) ...however, after casting the QGraphicsItem* to a QObject*, I can correctly extract my width and height properties. So, my current conclusion is that I have *no* useful properties in QGraphicsItem (and must cross-cast it to something I can use). boundingRect() works as I would expect. Can you provide some sample code? Rectangle { width: 300 height: 300 objectName: rect Text { objectName: text text: foo } } QDeclarativeItem *rect = qobject_castQDeclarativeItem *(view-rootObject()); qDebug() rect-boundingRect(); QDeclarativeItem *text = rect-findChildQDeclarativeItem *(text); qDebug() text-boundingRect(); Output: QRectF(0,0 300x300) QRectF(0,0 24x17) The first one is the rect of the top level item (and it matches what I set in qml) and the second one is the text item's computed width/height. So, the values are as I would expect. Girish ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml
Re: [Qt-qml] C++ MyClass to detect child added/removed from QML
QGraphicsItem::itemChange() may do what you want: http://doc.qt.nokia.com/4.7-snapshot/qgraphicsitem.html#itemChange Martin. From: qt-qml-boun...@trolltech.com [mailto:qt-qml-boun...@trolltech.com] On Behalf Of ext Charley Bay Sent: Tuesday, 23 November 2010 12:51 PM To: qt-qml@trolltech.com Subject: [Qt-qml] C++ MyClass to detect child added/removed from QML I'm sure the answer is simple, but I can't find it: I want my C++ implemented QML object to be notified when children are added: //FILE: MyFile.qml import Qt 4.7 import MyCppClass 1.0 Rectangle { MyCppClass { id: myCppClass Text { text: some text } // CHILD NOT DETECTED AS ADDED } Text { text: some other text parent: myCppClass // CHILD NOT DETECTED AS ADDED } } In both the cases above, I'm unable to find a slot/notification/virtual function in the C++ implementation of MyCppClass that I can use to detect these children that are added. Since MyCppClass derives from QDeclarativeItem, I see that it is a QGraphicsObject, mulitply-derived from from both QObject and QGraphicsItem. I stumbled onto virtual QObject::childEvent(QChildEvent*) which looked ideal (since QChildEvent has child add/remove info), but it's not called in either of the cases above. Then, digging into the Qt docs, I see that QGraphicsObject users should *NOT* look to QObject for parent/children relationships, but rather, should look only to QGraphicsItem. Seems reasonable. Unfortunately, I could not find anything in QGraphicsItem that looked like a slot or virtual function I could override to receive add/remove child notification events (I need both). I'm sure this is a simple answer -- what notification does QML trigger that I can catch on the C++ side for (re-)parenting? Thanks! --charley ___ Qt-qml mailing list Qt-qml@trolltech.com http://lists.trolltech.com/mailman/listinfo/qt-qml