Filling a listView model in seperate Thread .
-
Hi guys,
I am facing a problem using QML and C++.
In fact I'm creating a ListView model when starting the main program and a generator of a listView to generate that list from QML(key press or any other event..):
@
myModel model;
Generator generator(&model);ctxt->setContextProperty("myModel", &model); ctxt->setContextProperty("generator", &generator); view.setSource(QUrl("qrc:///qmlFolder/mainView.qml"));
@
Then when the application starts I use a key event to show the listView:
@
if (event.key === Qt.Key_Return)
{
generator.generate("All");
}
@
And the C++ part to generate the list is :
@
void Generator::generate()
{for(int i = 0 ; i < N ; i++) { m_model->addModelElements("str1", "str2"); }
}
@Every thing works perfect, But sometimes when the list is tooo long the annimated QML background freezes until the listView model is filled, so I have created a separete thread to handle the fill listView part and then post a signal to the main GUI thread. So in the model Class I Instantiate a New Thread and when receiving the user press button to call generate I fill ListView on the created thread. and then I have got this error :
@
[ 0x7f1a8377e700 ] Generate ChannelList
QObject::connect: Cannot queue arguments of type 'QQmlChangeSet'
(Make sure 'QQmlChangeSet' is registered using qRegisterMetaType().)
@It is like QT does not like that I generate the ListView model from another thread and call the m_model->addModelElements() from another thread then the GUI thread ?
Any Ideas Guys ??
-
See "this thread":http://qt-project.org/forums/viewthread/28884 for possible solution.
-
I suspect some UI components you are trying to access inside the worker thread. Can you post your complete simple example ? This will surely help.
-
:andreyc : I have already seen that post and unfortunately the solution is to post a signal from the QML to the GUI thread which turn to be the same acting thread, so the freeze problem will remains.
:Dhreerendra : Yes indeed I'm trying to access to my model which is a ListView from a worker thread :
@
ListView {
id: channelList
anchors.left: channelScrollZone.left
anchors.right: channelScrollZone.right
anchors.top: channelScrollZone.top
anchors.bottom: channelScrollZone.bottommodel: myModel highlight: highlight highlightFollowsCurrentItem: false focus: true clip: true keyNavigationWraps: true interactive: false delegate: channelComponent }
@
As I have understand it is not possible to modify the GUI from a worker thread, But it has to be a solution to avoid the freeze when loading a big ListView.
Thx
-
Yes. You are right. We need to do something like yours idea to solve the freeze issue. Here the issue is that you may be modifying/accessing something from worker thread which is not allowed. Is the model is your custom class ? Are you creating the thread inside your model class to just fill only data ? Which thread is creating the myModel object ?
-
The thread of the model class is created when declaring the class in the main which means that the thread that create the myModel Object is the GUI thread so that it can interact with the model in the QML scene. And yes the worker thread is created when the myModel Class is instantiated by the QuickView. So every time that the QML scene sends a request to update the ListView, I just pass the information to the worker thread, but indeed it is not possible to share the myModel Object with another thread to fill it . I don't know how a worker thread could possibely fill a QML listView model ?
-
Well I have succeeded to perform the parsing on another thread. the thing is despite of this message :
@
QObject::connect: Cannot queue arguments of type 'QQmlChangeSet'
(Make sure 'QQmlChangeSet' is registered using qRegisterMetaType().)
@That I don't know what it is ? I have succeded to perform the model fills on another thread, the only thing that the QT does not accept is to make the model refresh in the different thread !
Meaning that you need to call those two functions from the Gui thread other wise it does not work.
@
beginResetModel();
endResetModel();
@The final thing is that those two :
@
beginResetModel();
endResetModel();
@took about 200ms to excute which results on a noticable freeze on the screen .
Have you guys an other way to update the ListView without using those two functions for refreshing the list ? -
Hi,
bq. But sometimes when the list is tooo long the annimated QML background freezes until the listView model is filled, ...
Another idea would be to use fetchMore and canFetchMore functions of QAbstractListModel and load items as required and not all at a time.
-
Populating a model in a separate thread is one of the main reasons that the WorkerScript type exists in QML.
See http://qt-project.org/doc/qt-5/qml-qtquick-workerscript.html and http://qt-project.org/doc/qt-5/qtquick-threading-example.html#threaded-listmodel for more information.
Cheers,
Chris. -
Thanks for your response. But worker script are only a .js script which means that there is no interaction with C++ components. It is here only to perform some local processing on the QtQuick context.