[Interest] QML ListView is not updated on model reset

Elvis Stansvik elvstone at gmail.com
Tue Feb 28 08:42:39 CET 2017


Den 27 feb. 2017 11:27 em skrev "Alexander Dyagilev" <alervdvcw at gmail.com>:
>
> It seems the reason is that the model object is located in non-GUI
thread...
>
> Is there a way to work around this? I would prefer to keep my model in
non GUI thread.
>
> Is it a mandatory requirement to keep models in GUI thread only?

I think so. Due to signal connections becoming queued if they're on
separate threads, and the model/view machinery working with begin/end style
emissions, I don't think it's safe. May be other problems as well.

If you really have CPU intensive work to do when updating your model, use a
worker thread, but synchronize with your GUI thread when results are ready.
QtConcurrent can simplify a little here, depending on your use case.

If you're only blocking on I/O, consider making the I/O operations
asynchronous on top of the Qt event loop, if at all possible, and avoid
threading.

Elvis

>
>
>
> On 2/27/2017 8:59 PM, Alexander Dyagilev wrote:
>>
>> Hello,
>>
>> I've created a question on SO but nobody answered still...
>> (
http://stackoverflow.com/questions/42468811/qml-listview-is-not-updated-on-model-reset
)
>>
>> Qt 5.8, Windows 10.
>>
>> Quick Controls 2 application. In QML I have a ListView with a model
derived from QAbstractListModel.
>>
>> In the model I have the following code:
>>
>> void MediaPlaylistModel::update() { beginResetModel(); {
std::unique_lock<std::mutex> lock(m_mutex); m_ids = m_playlist->itemsIds();
} endResetModel(); }
>>
>> Nothing happens in QML view after calling this method: list is not
updated. If I go back and then forward (to the page with the ListView) -
it'll contain updated data. Model object instance is the same always.
>>
>> Am I doing something wrong?
>>
>> Update #2:
>>
>> C++ model code:
>>
>> MediaPlaylistModel::MediaPlaylistModel(
QSharedPointer<AbstractMediaPlaylist> playlist, QObject *parent) :
base_t(parent), m_playlist(playlist) { Q_ASSERT(m_playlist);
connect(playlist.data(), &AbstractMediaPlaylist::changed, this,
&MediaPlaylistModel::update); update(); } QHash<int, QByteArray>
MediaPlaylistModel::roleNames() const { QHash<int, QByteArray> result;
result[IdRole] = "id"; result[TitleRole] = "title"; result[DurationRole] =
"duration"; return result; } void MediaPlaylistModel::update() {
Q_ASSERT_SAME_THREAD; beginResetModel(); { std::unique_lock<std::mutex>
lock(m_mutex); m_ids = m_playlist->itemsIds(); } endResetModel(); } int
MediaPlaylistModel::rowCount( const QModelIndex &parent) const {
Q_UNUSED(parent); std::unique_lock<std::mutex> lock(m_mutex); return
static_cast<int>(m_ids.size()); } QVariant MediaPlaylistModel::data( const
QModelIndex &index, int role) const { auto row =
static_cast<size_t>(index.row()); int id = 0; {
std::unique_lock<std::mutex> lock(m_mutex); if (row >= m_ids.size()) return
QVariant(); id = m_ids[row]; } if (role == IdRole) return id; QVariant
result; auto item = m_playlist->item(id); switch(role) { case
Qt::DisplayRole: case TitleRole: result = item.title; break; case
DurationRole: result = item.duration; break; } return result; }
>>
>> QML code:
>>
>> import QtQuick 2.7 import QtQuick.Controls 2.0 import
com.company.application 1.0 Page { id : root property int playlistId
property var playlistApi: App.playlists.playlist(playlistId) ListView { id
: playlist anchors.fill: parent model: playlistApi.model delegate:
ItemDelegate { text: model.title width: parent.width onClicked:
App.player.play(playlistId, model.id) } ScrollIndicator.vertical:
ScrollIndicator {} } }
>>
>> Update #3:
>>
>> When the model is updated (one item added), something strange happens
with QML ListView: in addition to fact that it's not updated (and it does
not call MediaPlaylistModel::data to retrieve new items), existing items
got damaged. When I click on existed item, it's model.id property is always
0. E.g. at app start its model.id was 24, after one item added its model.id
became 0.
>>
>> Update #4:
>>
>> App.playlists.playlist(playlistId) returns pointer to this class
instance:
>>
>> class CppQmlPlaylistApi : public QObject { Q_OBJECT Q_PROPERTY(QObject*
model READ model NOTIFY modelChanged) Q_PROPERTY(QString title READ title
WRITE setTitle NOTIFY titleChanged) public: explicit CppQmlPlaylistApi( int
playlistId, QWeakPointer<CorePlaylistsManager> playlistsMgr, QObject
*parent = 0); QObject* model() const; QString title() const; void
setTitle(const QString &title); signals: void modelChanged(); void
titleChanged(); void loadPlaylistRequested(int id); protected slots: void
onPlaylistLoaded(int id); void onPlaylistRemoved(int id); protected: int
m_playlistId = 0; QWeakPointer<CorePlaylistsManager> m_playlistsMgr;
QSharedPointer<QAbstractItemModel> m_model; };
>
>
>
> _______________________________________________
> Interest mailing list
> Interest at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/interest
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20170228/fadba906/attachment.html>


More information about the Interest mailing list