[Development] Can we have id's in dynamically generated elements for the next QML?

Mark markg85 at gmail.com
Thu Aug 2 17:01:51 CEST 2012


On Thu, Aug 2, 2012 at 4:29 AM, Alan Alpert <alan.alpert at nokia.com> wrote:
> On Wed, 1 Aug 2012 12:59:08 ext Charley Bay wrote:
>>  Mark spaketh:
>> > Sadly, QML 1 doesn't have id in dynamically generated id. That is a
>> > real big pain if you want to drag/drop something since then you
>> > need... an id! Right now i'm trying to fight against a lot of issues
>> > that wouldn't even be there if i simply had an ID. You can read more
>> > about that in this blog post:
>> >
>> > http://kdeblog.mageprojects.com/2012/08/01/what-will-qml-calendar-have-pro
>> > gress-update-qml-issue/
>> >
>> > I'm also curious to know why the decision was ever made to have
>> > dynamically generated elements exist without id?
>> >
>> > Is there any possibility that QML 2 (or QML 2.1 or whatever comes
>> > after 2) is going to have ID's for generated elements?
>>
>> This is an interesting thing that I'm still trying to "grok" (the
>> direction-forward is not obvious to me yet, and I'm not sure what the
>> Trolls have discussed on IRC).
>>
>> I know it's been discussed (a little), and that I'm not sure I'm about to
>> add much.
>>
>> IMHO the issue is this "declarative-approach", which IMHO is quite new as a
>> paradigm.   The QML components/items themselves are "independent-actors".
>>  They don't use layouts *explicitly* in the parent/child relationship, and
>> shouldn't (but yes, "layouts" can be implemented to visually place
>> collections of items, and that is legitimate).  While "imperative"
>> organization is possible, it seems it should be discouraged as
>> "not-best-practice".
>>
>> I'm not-yet sure whether IDs are part of that topic:
>>
>> *- I *know* instance-IDs are needed for imperative.
>>
>> *- I *don't* know if instance-IDs are needed for declarative.
>
> I think you've almost got it. The thing you're missing is that that in QML,
> ids aren't for instances. Declarative languages do not follow such a strict
> instance mapping as imperative logic (where you need to keep track of every
> individual item - declarative languages do that for you in their own crazy
> ways ;) ).
>
> For example, if you have the following QML you might think you have an ID to
> an instance: Rectangle { id: rect; Rectangle{ id: rect2; width: rect.width }}.
> But if you place that inside Button.qml, you have one instance of 'rect' for
> every Button{} you use in other files. Much of the power from QML
> componentization is that you don't have to track the instances here yourself -
> write one Button which works within its own file, with the ids in that file, and
> the engine takes care of multiple instances for you.
>
> It's almost amusing that QML is so successful in hiding the complexities of
> these multiple instances that people don't even realize it's happening :P .

I'm not laughing :p but you're right, it is very powerful yet simple.
>
>> (This is my internal speculation/mapping, I'm just trying to
>> understand/grok the new paradigm to where "best-practices" become obvious
>> to me.)
>>
>> For example, in the design/problem you describe, the following design
>> option *might* be reasonable without IDs (and I concede many other design
>> options exist if we *do* have IDs):
>>
>> *- The "MyCalendarEntry" (QML component, no GUI real estate) has a
>> "DateTimeSpan" property which "implies" where it is on a calendar.
>>
>> *- A "MyCalendarItem" (QML item, with GUI real estate) "parents" (or
>> "references") a SINGLE "MyCalendarEntry" to represent that
>> "MyCalendarEntry".  (Conceivably it would be 1:1, but it seems reasonable
>> to have many "MyCalendarItem" GUI-things represent the same
>> "MyCalendarEntry" instance if there were many "views" of that one "entry"
>> in different calendar-rendering-scenarios.)
>>
>> *- Each "MyCalendarItem" (QML GUI item) is an "independant-actor" which
>> "finds-its-place" upon a parent "MyCalendarDisplay" QML GUI item.  The
>> parent "MyCalendarDisplay" has its own "layout" that physically arranges
>> its "children", which occupy their own real-estate-needs (based on their
>> internal "MyDateTimeSpan" property).  (For example, perhaps the
>> "calendar-display" is a "MyCalendarDay" or "MyCalendarWeek" or
>> "MyCalendarMonth" GUI-item, and there would be different layouts for each
>> of those instances.)
>>
>> *- This works "without-instance-IDs" because creating a "MyCalendarEntry"
>> would *automatically* trigger creation of a "MyCalendarItem", which is
>> *automatically* parented by a "MyCalendarDisplay", and which physically
>> places the items with Z-order.  The drag/drop manipulation would directly
>> manipulate the "DateTimeSpan" in the "MyCalendarEntry", through the
>> "handles" on the "MyCalendarItem".
>>
>> Of course, another design option would be for the "MyCalendarEntry" QML
>> component to have a C++ back-end-object with a unique ID, which could be
>> used for a universal ID from within QML.
>
> The first design option is effectively leveraging the componentization abilities
> of QML. The second one is leveraging the C++ integration that makes all things
> possible if you're having trouble doing it in QML. They are both such great
> aspects of QML that I feel I shouldn't judge either one as a better choice ;).
>
>> I dunno.  I'm about to embark on a fairly large Qt5/QML effort and that's
>> the kind of design I'm looking at, and I'll know more when I get deeper.
>>  At the moment, though, I concede it would not take much for me to agree
>> with you that IDs could/should be added to the next QML spec...
>>
>> Specifically for your question:
>>
>> I'm also curious to know why the decision was ever made to have
>>
>> > dynamically generated elements exist without id?
>>
>> I'm not an authority, and can only speculate, but I was initially confused
>> about this too.  (NOTE to the casual reader, the "Item { id: my_id; }" is
>> not the ID we're discussing, we're talking about an instance-unique ID.)
>
> This confuses me a bit too - if you aren't discussing QML ids, which can't be
> instance-unique because they're declarative, then don't you just use the
> QObject*?
>
>> However, after a time, I came to understand that the "declarative" approach
>> seems to imply:
>>
>> (a) Items are "implicitly-aggregated" based on "parents" and "properties"
>> (e.g., typically not explicitly-aggregated)
>>
>> (b) Declaratively changing an item's "parent" and/or "properties" (such as
>> "events-on-implied-items") should *implicitly* cause animations and
>> re-aggregations (such as implied re-parenting and re-layout on the
>> display), and you're not supposed to need to do the
>> explicit-place-this-item-here thing.
>>
>> As a possible secondary issue, if the QML item "represents/wraps" a C++
>> object, then the "ID" is trivially handled with an application-specific
>> "identifier" (that's typically how mine work, where the "identifier" has
>> compound-application-specific-state).
>
> I fully agree. I've often had my C++ or QML items register the instance with a
> global backend on component,onCompleted, when needed. But this is when you
> need to fall back to imperative JS/C++ for some reason, not when you are using
> declarative properly, so that's why no such instance identifiers exist in "QML"
> - just get the QObject* if you really need it imperatively.
>
>> The question in my mind, of course, is the same as yours:
>>
>> (1) If "ID" is not really needed, what is the "best-practices"
>> declarative-QML-design-pattern that would do what we need?  (One possible
>> pattern-not-yet-proven is listed above.)
>
> Reusable components/delegates, where data propagates in one direction, is the
> best-practices pattern that obviates this need. Create each component with a
> self contained interface on the root item, and whatever instantiates the root
> items can deal with the individual instance requirements. For example, if you
> need to expose the relative position of subItem, the root item of the
> component could have a property which is either an alias to the item position
> or the result of a function mapping the position to the component root item
> coordinates.
>
> For list delegates, this is managed through the model. Individual delegates
> should only depend on the model for state and interaction. If that's not
> enough you probably need a custom view, because views are supposed to handle
> the majority of the UI logic of the data.[1]
>
>> (2) Are the designs not reliant upon (instance)-IDs reasonably practical
>> for non-trivial systems (e.g., systems that make heavy use of a
>> "model-of-items")?
>
> The idea is that it makes it easier. Obviously, non-trivial systems are hard
> to play around with for testing, but QML has the build in safety of C++
> integration. If you start doing your non-trivial system with QML, and get
> great prototyping speed with it, but run into this problem, you can drop back
> to C++. You don't even have to discard your QML, just make a container Item a
> MyItem instead and it can register with a backend. You only need to use C++
> for those specific, unforseen problems.
>
> For example, with a Repeater you can't easily get the delegate pointers in QML
> (which is fine, it's not useful in a declarative language). But you could just
> track the object pointers with either a custom C++ class or just
> Component.onCompleted: instanceList.append(container); to add the reference to
> a global list.
>
> [1] A future research topic that I'm keen on, one of these days, is to better
> componetize the Model/View split. QML has very simplified models, but the Views
> are immense and in some ways restrictive. Sometime people just use a
> Repeater/Column/Flickable for flexibility, but that's not viable for large data
> sets. There's clearly a better split which would allow for more of the View to
> be written in QML, like the UI logic, while not forcing such large tradeoffs.
> After the successful completion of that research project, suggesting that you
> create your own view would just mean another QML file in your project.
>
> --
> Alan Alpert

The messages of you 2 kinda let me think a little bit different about
how i should be doing this kind of stuff in QML.

It seems to boil down - very simplified - of just letting a component
be fully responsible of where it is placed. Rather then what i'm doing
now as in creating the component and controlling where it's being
placed outside of the actual component file.

But i still don't fully understand how to make a component draggable
when it's being created dynamically through a Repeater.. Don't you
just need an id for that to work?



More information about the Development mailing list