Issues with SwipeView and Repeater managing
-
Hi there!
I'm wondering on how a Repeater and SwipeView can be used together without having the following issues...
I have the following QML setup (without the layouting stuff):
Item { MyController { id: control } Connections { target: control onErrorModelChanged: console.info("errorModelChanged catched"); } Connections { target: control.errorModel onRowsAboutToBeRemoved: console.log("onRowsAboutToBeRemoved") onRowsAboutToBeInserted: console.log("onRowsAboutToBeInserted") onRowsRemoved: console.log("onRowsRemoved") onRowsInserted: console.log("onRowsInserted") } SwipeView { Component.onCompleted: { console.log("currentIndex is: " + currentIndex) console.log("currentItem is: " + currentItem) } onCurrentIndexChanged: console.log("currentIndex changed to: " + currentIndex) onCurrentItemChanged: console.log("currentItem changed to: " + currentItem) Repeater { model: control.errorModel onItemAdded: console.log("item added: " + item) onItemRemoved: console.log("item removed: " + item) delegate: Item { visible: swipeIndex === errorview.currentIndex property int swipeIndex: SwipeView.index property bool isCurrentItem: SwipeView.isCurrentItem property int repeaterIndex: index onSwipeIndexChanged: console.log(this + ": swipeIndex changed to: " + swipeIndex) onRepeaterIndexChanged: console.log(this + ": repeaterIndex changed to: " + repeaterIndex) onIsCurrentItemChanged: console.log(this + ": isCurrentItem changed to: " + isCurrentItem) onVisibleChanged: console.log(this + ": visible changed to: " + visible + " (w: " + width + " | h: "+ height + ")") onFocusChanged: console.log(this + ": focus changed to: " + focus) onActiveFocusChanged: console.log(this + ": active focus changed to: " + activeFocus) } } } }
On C++ side (MyController) I have a QStandardItemModel which is passed to the Repeater.
When data changes occur, I'm going to insert, append or remove (take) rows from the model (which has only one column).Initially the SwipeView gets populated by the Repeater, lets say with 3 items, has a currentIndex of 0 and the currentItem is the item with index 0 from the Repeater.
Now I'm going to delete the first item (row index 0) from the model on C++ side, as the data has changed.
What then happens is:
- the Repeater index of the item which is about to be removed become -1
- the Repeater index of the following items are decreased
- the item gets removed from the Repeater
- the SwipeView.index from the following items are decreased
- the item which now has a SwipeView.index of 0 should get visible
What I'm missing is:
- the SwipeView updates it's currentItem to the one which now has the SwipeView.index of 0
That means, that the SwipeView still has a currentItem which has already been deleted and none of the items in the SwipeView has a SwipeView.isCurrentItem property which is 'true'.
Furthermore I have issues with the visibility of Repeater-Items, for one of my common use-cases of this construct.
I know it is quite much log, but demonstrates very well how this is working in the backend.First step: SwipeView gets populated by the Repeater with initial 3 items:
QQuickItem_QML_78(0x3f392d0): isCurrentItem changed to: true item added: QQuickItem_QML_78(0x3f392d0) QQuickItem_QML_78(0x3f61ac0): swipeIndex changed to: 1 QQuickItem_QML_78(0x3f61ac0): visible changed to: false (w: 0 | h: 0) QQuickItem_QML_78(0x3f61ac0): repeaterIndex changed to: 1 item added: QQuickItem_QML_78(0x3f61ac0) QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 2 QQuickItem_QML_78(0x3f728e0): visible changed to: false (w: 0 | h: 0) QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 2 item added: QQuickItem_QML_78(0x3f728e0) QQuickItem_QML_78(0x3f392d0): focus changed to: true currentIndex is: 0 currentItem is: QQuickItem_QML_78(0x3f392d0)
Second Step: The actual visible item, gets hidden by an overlay and then visible again:
QQuickItem_QML_78(0x3f392d0): focus changed to: false QQuickItem_QML_78(0x3f392d0): visible changed to: false (w: 640 | h: 200) QQuickItem_QML_78(0x3f392d0): visible changed to: true (w: 640 | h: 200)
Third Step: Data has changed, a new item needs to be added, an old one to be removed.
The new item will get inserted at row index 1 in the QStandardItemModel.
The item which has to be removed is at row index 0 (before and after insertion of the new item).found position. insert item at 1 onRowsAboutToBeInserted onRowsInserted QQuickItem_QML_78(0x3f61ac0): repeaterIndex changed to: 2 QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 3 QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 3 QQuickItem_QML_78(0x3f61ac0): swipeIndex changed to: 2 QQuickItem_QML_78(0x3165e10): swipeIndex changed to: 1 QQuickItem_QML_78(0x3165e10): visible changed to: false (w: 640 | h: 200) QQuickItem_QML_78(0x3165e10): repeaterIndex changed to: 1 item added: QQuickItem_QML_78(0x3165e10) m_ErrorModel: found item to delete: 0 onRowsAboutToBeRemoved onRowsRemoved QQuickItem_QML_78(0x3f392d0): repeaterIndex changed to: -1 QQuickItem_QML_78(0x3165e10): repeaterIndex changed to: 0 QQuickItem_QML_78(0x3f61ac0): repeaterIndex changed to: 1 QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 2 item removed: QQuickItem_QML_78(0x3f392d0) QQuickItem_QML_78(0x3165e10): swipeIndex changed to: 0 QQuickItem_QML_78(0x3165e10): visible changed to: true (w: 640 | h: 200) QQuickItem_QML_78(0x3f61ac0): swipeIndex changed to: 1 QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 2 errorModelChanged catched QQuickItem_QML_78(0x3165e10): focus changed to: true
As you can see is the signal which should notify about model changes (emitted after inserting and removing rows) catched after all the changes on QML side have already been applied ("errorModelChanged catched").
Fourth Step: Data changes again, one item needs to be removed. And then change again, an item needs to be added:
m_ErrorModel: found item to delete: 1 onRowsAboutToBeRemoved onRowsRemoved QQuickItem_QML_78(0x3f61ac0): repeaterIndex changed to: -1 QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 1 item removed: QQuickItem_QML_78(0x3f61ac0) QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 1 errorModelChanged catched found position. insert item at 1 onRowsAboutToBeInserted onRowsInserted QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 2 QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 2 QQuickItem_QML_78(0x419fd70): swipeIndex changed to: 1 QQuickItem_QML_78(0x419fd70): visible changed to: false (w: 640 | h: 200) QQuickItem_QML_78(0x419fd70): repeaterIndex changed to: 1 item added: QQuickItem_QML_78(0x419fd70) errorModelChanged catched
Last Step: Data changes again in way, that an item needs to be added and an old one to be removed.
The new item will get inserted at row index 1 in the QStandardItemModel.
The item which has to be removed is at row index 0 (before and after insertion of the new item).found position. insert item at 1 onRowsAboutToBeInserted onRowsInserted QQuickItem_QML_78(0x419fd70): repeaterIndex changed to: 2 QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 3 QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 3 QQuickItem_QML_78(0x419fd70): swipeIndex changed to: 2 QQuickItem_QML_78(0x315da70): swipeIndex changed to: 1 QQuickItem_QML_78(0x315da70): visible changed to: false (w: 640 | h: 200) QQuickItem_QML_78(0x315da70): repeaterIndex changed to: 1 item added: QQuickItem_QML_78(0x315da70) m_ErrorModel: found item to delete: 0 onRowsAboutToBeRemoved onRowsRemoved QQuickItem_QML_78(0x3165e10): repeaterIndex changed to: -1 QQuickItem_QML_78(0x315da70): repeaterIndex changed to: 0 QQuickItem_QML_78(0x419fd70): repeaterIndex changed to: 1 QQuickItem_QML_78(0x3f728e0): repeaterIndex changed to: 2 item removed: QQuickItem_QML_78(0x3165e10) QQuickItem_QML_78(0x315da70): swipeIndex changed to: 0 QQuickItem_QML_78(0x315da70): visible changed to: true (w: 640 | h: 200) QQuickItem_QML_78(0x419fd70): swipeIndex changed to: 1 QQuickItem_QML_78(0x3f728e0): swipeIndex changed to: 2 errorModelChanged catched QQuickItem_QML_78(0x315da70): focus changed to: true
This may end up in a SwipeView where the latest added item 0x315da70 is not visible at all, even when the logs state something else (width and height > 0, visible, focus). Sometimes it is working as intended and expected.
I can make the content magically visible, when I just click the area where the item is located - which is not causing any state changes of the item and therefore logs.Does anyone have an idea on how to notify the SwipeView that its currentItem has changed?
And does anyone have an idea what can cause these visibility problems?Regards, matzze
-
Hello again!
I digged a little deeper into this behavior and found out, that the SwipeView actually has a clue on what's going on with its currentItem, but do not tell the world about that.
Therefore I've added some more loggings and stuff to the Repeater:
[...] Repeater { id: errorRepeater model: control.errorModel onItemAdded: { console.log("item added: " + item) console.log("errorview currentItem: " + errorview.currentItem) } onItemRemoved: { console.log("item removed: " + item) console.log("errorview currentItem: " + errorview.currentItem) } onCountChanged: { console.log("count changed") console.log("errorview currentItem: " + errorview.currentItem) updateItems() } signal updateItems delegate: Item { id: theItem Connections { target: errorRepeater onUpdateItems: { console.log("updateItems catched") visible = errorview.currentItem === theItem } [...] } } }
With that you can see the following when an item gets removed from the Repeater:
2022-10-10_16:31:59.696 I m_ErrorModel: found item to delete: 0 (rows before: 4) 2022-10-10_16:31:59.696 D onRowsAboutToBeRemoved 2022-10-10_16:31:59.696 D onRowsRemoved 2022-10-10_16:31:59.696 D QQuickItem_QML_76(0x30211c0): repeaterIndex changed to: -1 2022-10-10_16:31:59.696 D QQuickItem_QML_76(0x3051c10): repeaterIndex changed to: 0 2022-10-10_16:31:59.696 D QQuickItem_QML_76(0x2a2e0a0): repeaterIndex changed to: 1 2022-10-10_16:31:59.696 D QQuickItem_QML_76(0x3248430): repeaterIndex changed to: 2 2022-10-10_16:31:59.696 D item removed: QQuickItem_QML_76(0x30211c0) 2022-10-10_16:31:59.696 D errorview currentItem: QQuickItem_QML_76(0x30211c0) 2022-10-10_16:31:59.696 D QQuickItem_QML_76(0x3051c10): swipeIndex changed to: 0 2022-10-10_16:31:59.697 D QQuickItem_QML_76(0x2a2e0a0): swipeIndex changed to: 1 2022-10-10_16:31:59.697 D QQuickItem_QML_76(0x3248430): swipeIndex changed to: 2 2022-10-10_16:31:59.697 D count changed 2022-10-10_16:31:59.697 D errorview currentItem: QQuickItem_QML_76(0x3051c10) 2022-10-10_16:31:59.697 D updateItems catched 2022-10-10_16:31:59.697 D updateItems catched 2022-10-10_16:31:59.697 D updateItems catched 2022-10-10_16:31:59.697 D QQuickItem_QML_76(0x3051c10): visible changed to: true (w: 640 | h: 200) 2022-10-10_16:31:59.697 I errorModelChanged catched
As you can see, does the errorview's currentItem change after the SwipeIndex' of the items have been updated and the count of the Repeater items changes.
The logged currentItem then is the one that I actually want to be visible and it is the one with SwipeView.index of 0.
I then going to send a signal to update the visibility of the actual currentItem...BUT... the result is still the same :( Sometimes the item is visible, sometimes it is not. It's a mess.
Regards, matzze