ListView not being updated at runtime to follow the model
In our new project we have decided to use qml for the 1st time. Having spent sometime learning qt quick 1.0 in Qt 5.0, we suddenly have Qt 5.1 coming up which focuses on qml on desktops - what we need. Since 5.1 is still beta it is buggy (for QQuickView and in general QWindow maximize is not available - https://bugreports.qt-project.org/browse/QTBUG-31258). I want to know if the following issue is a bug or is the result of wrong coding on my part:
I make a class derived from QAbstractListModel and re-implement the necessary functions. I create an object of it, fill in some initial data into the model (all beginInsertRows etc done) and then pass it (the object) to qml via setContextProperty. For qt 5.1 with quick 1.0 I use QDeclarativeView. For qt 5.1 with quick 2.0 I use QQuickView. Once qml is 'shown' by show() command, I spawn a std::thread in which I pass the reference of the Model object. The thread keeps adding data to the model via direct call to Model's addData(..) function (which has beginInsertRows etc) using the passed reference every 'x' milliseconds. Meanwhile in the main thread QApplication's exec() would have started.
Problem: Using qt 5.1 quick 1.0 (QDeclarativeView) there is no problem - the ListView (UI) updates fine and keeps growing showing it is indeed following the model. Using quick 2.0 (QQuickView) breaks this behaviour. There is no update of the UI other than the initial data set into the model (described before). If I resize or imitate a flick with the mouse then suddenly all data contained upto that point is shown but again things halt there. I get the following listed in the Application Output pane in QtCreator:
QObject::connect: Cannot queue arguments of type 'QQmlChangeSet'
Make sure 'QQmlChangeSet' is registered using qRegisterMetaType().
I don't know what QQmlChangeSet is. However if I use QThread derived class and re-implement run() to do the same, but instead of passing the refernece of Model's object I emit signal which is caught by the Model's addData(..) function which I've now turned into a slot, then everything works fine again and the ListView UI grows in number of rows. Is this expected? If so then why (ie., what is wrong with the former approach)?
I have exactly the same problem. The difference to my application is, that the calls for adding/removing items to/from the QAbstractListModel are triggered from a C++ library which runs in its own boost::Thread. I guess it is a cross-thread problem.
One solution (have not tested yet) could be a JobQueue which is processed in the ListModel owning Thread. Jobs for adding/removing items could be added from the library Thread to the JobQueue. The access to the JobQueue must be synchronized with a mutex.
What I do not understand is that the cross-thread model manipulation is a problem. Shouldn't the QAbstractListModel be thread-affine, so that it is bound to the GUI Thread where it was created? And shouldn't the data manipulation actions also be executed automatically in the GUI thread?
Other solutions or suggestions would be appreciated.
Hi, I have exactly the same problem as you. Do you have any easy solution for it?
I didn't know about this problem and now I probably have to completely rewrite a lot of code... :-(
bq. Hi, I have exactly the same problem as you. Do you have any easy solution for it?
The easiest solution is what ustulation wrote. Instead of adding data in the C++ Library Thread or during any other Thread than the GUI Thread, emit a signal (e.g. dataAdded ). The signal must be connected during the GUI Thread to a slot ( addData(Data* pData) ). Because you connected the signal during the GUI Thread, addData is also called during the GUI Thread. Unfortunately you have to add a signal and a slot and connect them. But then it is working like a charm.
Gentle22> Thanks, this seems to be simple to do. I'll probably have create a QList<QVariantList> and then emit a signal with it from the background thread. I hope it will work now...
I am using Qt 5.3 and have the exact same problem. Why can't we use external thread to trigger this type of events?
I've found tircky solution: ListView's model can be QIdentityProxyModel created in gui-thread, and source of proxy is a model from any other thread.
damn. this works only with quick 1.0 ( looks like my answer is useless