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.value<QGraphicsItem*>(); // ALWAYS
NON-NULL

     QObject* my_object = dynamic_cast<QObject*>(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,
>> 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.
>>
>
> Very helpful -- opaqueArea() not used, but QGraphicsItem::boundingRect()
> should reflect what was set on QML.  That would be ideal -- I'll confirm
> over the next day or two, but my current tests have that function as
> *inconsistent* with what I've explicitly set in QML (e.g., I always see
> QRectF(0,0,-1,-1) on the C++ side from the child).
>

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).

<snip>,
>>
>> > (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.
>>
>
After testing, it's not a difference between MouseArea{} or Text{}, but
rather, hard-coded child in the QML (no notifications), or children
explicitly re-parented in QML (yes, *does* trigger notifications).

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).

Thanks!

--charley
_______________________________________________
Qt-qml mailing list
Qt-qml@trolltech.com
http://lists.trolltech.com/mailman/listinfo/qt-qml

Reply via email to