How can you know when all the delegates of a View or Repeater have been created once the model is set?
-
Hi
I am having synchronization problems within my C++/QML application.After I set the
modelproperty of aRepeaterinside aColumnwhich functions as a drawer of sorts. Then, I reparent some of the items in that Column to a Grid.In my first version, the model was a QML
XmlListModel, and then the above worked fine.
Now, I have replaced the XmlListModel by an equivalent C++ model, exposed as a custom QML type, but things now no longer work, because the reparenting is now apparently started before theRepeateritems are created.In this new approach, I therefore need to wait until all
Repeateritems have been created. Is there an event I can use for this, other than to count (in the delegate'sonCompleted()) the number of instantiated items myself? (I am already using that convoluted approach for another model/view part, but I'm wondering if there is a better way). -
Hi,
maybe the problem is in c++, how are you linking c++ to qml you Register the Type in c++?
Hi @Diackne
Thanks for reacting.you Register the Type in c++
Yes, I register the model as a QML-type in C++, having implemented, amongst others, the following methods:
int rowCount(const QModelIndex & parent = QModelIndex()) const; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); Q_INVOKABLE QVariantMap get(int row); -
@Diracsbracket said in How can you know when all the delegates of a View or Repeater have been created once the model is set?:
Q_INVOKABLE QVariantMap get(int row);
Q_INVOKABLE is the problem, you maybe in your qml code call this get(N) but not the reactive way!! if c++ ends after the first call of get(N) your result of get(N) return empty
maybe you need follow this ideactxt->setContextProperty("myModel", &model);Repeater { model: myModel // this notify c++ --> Qml delegate: Text { text: type + ", " + size } }but in qml who you pass the model only get(N) or inside repeater and the repeater have the model?
-
@Diracsbracket said in How can you know when all the delegates of a View or Repeater have been created once the model is set?:
Q_INVOKABLE QVariantMap get(int row);
Q_INVOKABLE is the problem, you maybe in your qml code call this get(N) but not the reactive way!! if c++ ends after the first call of get(N) your result of get(N) return empty
maybe you need follow this ideactxt->setContextProperty("myModel", &model);Repeater { model: myModel // this notify c++ --> Qml delegate: Text { text: type + ", " + size } }but in qml who you pass the model only get(N) or inside repeater and the repeater have the model?
At the time I created this post, I did it as follows:
Flickable{ id: sourceFlick .... Column { id: buttonList Repeater { model: xmlButtonModel ... delegate: DragTile {} } } }I used a
Repeaterbecause I needed all the delegates to be instanciated at all times (as opposed to only when they are visible). But in the meanwhile, I learned that I could do the same with aListViewby setting thecacheBufferto an appropriate value, and now I do things like this:ListView { id: buttonList ... model: xmlButtonModel .... delegate: DragTile {} }The model and
ListVieware part of anItem, of which several instances are created dynamically, based on the number of XML files found in a directory:Item { id: layout XmlListModel { id: xmlButtonModel ... onStatusChanged: { if (status == XmlListModel.Ready) { ... Js.createGridPages() ... } } } Rectangle { id: drawer ... ListView { id: buttonList ... model: xmlButtonModel .... delegate: DragTile {} } } Item { id: layoutItem ... SwipeView { id: swipeView ... contentItem: ListView { ... model: ListModel { id: viewModel } delegate: ButtonGrid {} } } } }So for a given layout
Item, once the XML model is loaded, the layout is populated byJs.createGridPages(), which creates the pages inswipeView, each page containing aGridof cells to which items ofbuttonListare reparented based on a user-preferences file...I must note that this reparenting process even fails occasionally when simply rebuilding + autolaunching the app via Qt Creator (target device is Android), even when I don't use my faster C++ XML model. The error is always the same: some of the
DragTiledelegates of mybuttonListis stillundefined. -
At the time I created this post, I did it as follows:
Flickable{ id: sourceFlick .... Column { id: buttonList Repeater { model: xmlButtonModel ... delegate: DragTile {} } } }I used a
Repeaterbecause I needed all the delegates to be instanciated at all times (as opposed to only when they are visible). But in the meanwhile, I learned that I could do the same with aListViewby setting thecacheBufferto an appropriate value, and now I do things like this:ListView { id: buttonList ... model: xmlButtonModel .... delegate: DragTile {} }The model and
ListVieware part of anItem, of which several instances are created dynamically, based on the number of XML files found in a directory:Item { id: layout XmlListModel { id: xmlButtonModel ... onStatusChanged: { if (status == XmlListModel.Ready) { ... Js.createGridPages() ... } } } Rectangle { id: drawer ... ListView { id: buttonList ... model: xmlButtonModel .... delegate: DragTile {} } } Item { id: layoutItem ... SwipeView { id: swipeView ... contentItem: ListView { ... model: ListModel { id: viewModel } delegate: ButtonGrid {} } } } }So for a given layout
Item, once the XML model is loaded, the layout is populated byJs.createGridPages(), which creates the pages inswipeView, each page containing aGridof cells to which items ofbuttonListare reparented based on a user-preferences file...I must note that this reparenting process even fails occasionally when simply rebuilding + autolaunching the app via Qt Creator (target device is Android), even when I don't use my faster C++ XML model. The error is always the same: some of the
DragTiledelegates of mybuttonListis stillundefined.I finally found what was happening.
I incorrectly assumed (from a few debug output samples) that when using a
Repeaterto instantiate the cells of myGrid, the cells would always be listed first in thechildrenlist ofGridand that theRepeateritem would always be listed as the last child (i.e. cells would be "inserted" in the list before theRepeateras they got instantiated) .Based on that assumption, I directly used the cell index (let's say i) to get the corresponding item as
children[i].The above assumption was apparently wrong: once in a while, the
Repeateritem would not always be the last child, and a cell could come after it... Therefore, my above approach of using the grid cell index to retrieve the item sometimes resulted in getting theRepeateritem instead...To avoid this, I have eliminated the Repeater, and simply instantiate the cells dynamically in the
Component.onCompleted()handler. This allows me to directly use the grid cell index to retrieve the item from thechildrenlist, not having to worry about other types of children... -
Why not use the
Repeater'sitemAt(index)method? -
@GrecKo
That's a good one, I didn't think there would be such a method! Thanks for pointing it out!