Component.onCompleted does not work as expected in a ListView's delegate
-
When porting my QML application (Qt 4.8.0) to the new Qt version 5.2.1 I noticed the following issue:
The event Component.onCompleted of a ListView's delegate does not fire every time as it was with Qt 4.8.0.
To localize the problem and to eliminate other side effects of my application I tried to reproduce the error with a simple project reduced to the essential. For this purpose I took the objectlistmodel example of the Qt 5.2.1 bundle and just modified the view.qml a bit:
@import QtQuick 2.0
ListView {
width: 200; height: 400model: myModel delegate: Rectangle { height: 400 width: 200 color: model.modelData.color Text { text: name } Component.onCompleted: console.debug("currentIndex: "+currentIndex); //this event does not fire every time } boundsBehavior: Flickable.StopAtBounds snapMode: ListView.SnapOneItem; focus: true interactive: true highlightFollowsCurrentItem: true highlightRangeMode: ListView.StrictlyEnforceRange cacheBuffer: 0
}@
When scrolling between the ListView's delegate pages the Component.onCompleted is not called on every page change?! Does anybody know why this is happening? Is it a known issue with this new Qt version or did I something wrong?
Any help is appreciated - thank you!
-
In QtQuick 2, views have a cache buffer associated with them by default. This means that some delegates are cached after creation, so that they can be "reused" when they come back into the visible region of the view.
Depending on the size of the cache buffer, this might mean that you'll only get the signal emitted from the delegate once during the lifetime of the application.
Is that the issue you're seeing, or are you saying that you don't get any signal emitted for the delegates for some indexes? If this one is the case, then I think it's a bug which should be filed.
Cheers,
Chris. -
Hi Chris,
in fact I wanted to find out if the event Component.onCompleted is fired on every page change because I need an event which is emitted for every delegate when it is shown (not just once after first creation).
To ensure that this event is fired every time I knowingly did set cacheBuffer to 0. But it seems that with Qt 5.2.1 (QtQuick 2) the cacheBuffer is not zero then - Component.onCompleted is fired two times at startup! Obviously a cacheBuffer set to 0 does not mean that every delegate is recreated every time when it is shown (as it apparently was with Qt 4.8.0 !!)So is there an alternavite event I could use in QtQuick 2? I would need one which is fired every time a delegate is shown, because it can happen that I have to change the content of the delegate in the meantime?
Thanks so far, Chris!
-
I don't actually know. Perhaps onVisibleChanged -- I don't know much about the views and delegates in QtQuick. No doubt the information is in the documentation somewhere, though.
Views should describe, somehow, which indexes are in the visible region. You could use a signal handler with code that checks if the delegate index is one of those visible indexes, if it's not already exposed via the onVisibleChanged signal as I would expect.
It's certainly possible to get what you want, but I don't know for certain what it would be, unfortunately :-(
Cheers,
Chris. -
taferi: I am not sure how accurate your example code is but it seems to me that the most appropriate way of implementing this would be to simply make use of currentIndex in ListView that already will notify you of page changes:
@
onCurrentIndexChanged: print("current index is now " +currentIndex)
@ -
I don't think currentIndex can be used in this case, because it never changes by itself when the view changes (the current index has to be set manually as far as I know).
At least from my experience if you have a ListView and you scroll/flick around there is no signal for that, unless you use the signals from Flickable I guess, but that is a little "messy"? -
Thank you all for your answers!
@Jens: I also had the idea to use the onCurrentChanged event of the ListView. But that was not enough because I still had to find a appropriate way to inform a specific (the actual visible one) delegate about the page changes - and I struggled with that without success...
I finally solved the problem for me by using the following Binding for my relevant content inside the delegate:
@Binding {
target: contentItem
property: 'model'
value: {
if(myListView.currentIndex===index) loadCurrentPageModel();
else loadPageModel();
}
}@