Order in which loading completes with GridView/ListView when using a Loader asynchronously in a delegate is reversed
-
I am using Qt 5.1.0 for a "Qt Quick Application" project (with QML and C++).
I was trying to create a grid of images on my embedded device. I used a loader in the delegate for a smoother user experience. I noticed that the images would appear in a reverse order; the positions are correct, just the order in which they finish loading seems reversed - that is, I would see an empty window to start with, the images at indices 7, 6, 5 and 4 finish loading, although they are outside the visible area, then image at index 3 would appear at the bottom-most position in the window, followed by the image at index 2, then index 1 and finally the image at index 0.
A simplified version of the QML code is posted below:
@import QtQuick 2.1
ListView
{
width: 120
height: 400// Model to help populate the GridView model: 100 delegate: Component { Loader { height: 100 width: 150 asynchronous: true sourceComponent: Component { Row { spacing: 10 Text { text: index } Image { height: 100 width: 100 source: "some_image.png" } } } onStatusChanged: console.log( "Delegate " + index + ": " + loaderStateNames[status] ); } } property var loaderStateNames: [ "Loader.Null", "Loader.Ready", "Loader.Loading", "Loader.Error" ]
}
@Output when using this in a "Qt Quick Application" project (with QML and C++):
@
Delegate 0: Loader.Loading
Delegate 1: Loader.Loading
Delegate 2: Loader.Loading
Delegate 3: Loader.Loading
Delegate 4: Loader.Loading
Delegate 5: Loader.Loading
Delegate 6: Loader.Loading
Delegate 7: Loader.Loading
Delegate 7: Loader.Ready
Delegate 6: Loader.Ready
Delegate 5: Loader.Ready
Delegate 4: Loader.Ready
Delegate 3: Loader.Ready
Delegate 2: Loader.Ready
Delegate 1: Loader.Ready
Delegate 0: Loader.Ready
@- Why do the loaders complete loading in the reverse order of their starting? Is this by design or am I missing something?
- For a user looking at the screen, this behavior seems very odd, as they see items at the very end of the screen(possibly, just below the viewing area) show up first, while the images in the main viewing area appear only later.
When I tried moving this QML code into a "Qt Quick 2 UI" project, and run with "QML Scene", it produced different results:
Output when using this in a "Qt Quick 2 UI" project, produces the output below:
@
Delegate 0: Loader.Ready
Delegate 1: Loader.Ready
Delegate 2: Loader.Ready
Delegate 3: Loader.Ready
Delegate 4: Loader.Ready
Delegate 5: Loader.Loading
Delegate 6: Loader.Loading
Delegate 7: Loader.Loading
Delegate 7: Loader.Ready
Delegate 6: Loader.Ready
Delegate 5: Loader.Ready
@- This behavior makes more sense to me; the items in the visible area appear first in the correct order.
- It seems to have created items 0 through 4, which are in the viewing area, synchronously, I'm guessing, because I do not see the window until "Delegate 4: Loader.Ready" is printed out, and also because these loaders do not seem to go into the Loader.Loading state at all.
- Thereafter, it seems to start loading a few additional items, but they again complete in the reverse order.
- Why is there a difference in these usages for the same QML?
-
I've created a bug report: https://bugreports.qt-project.org/browse/QTBUG-35502
-
The order of creation is not guaranteed. In cases where the asynchronous loading does not take the same time per delegate, you could see any random order happening.
The difference between qmlscene and qtquick2viewer is odd though, and could be caused by QTBUG-31203. If you prefer the qmlscene like behavior, try using this as your C++ application:
@
int main(int argc, char* argv[]) {
QGuiApplication app(argc, argv);
QQuickView v;
v.setSource("main.qml");
v.show();
return app.exec();
}
@