3

I have problem with loading QAbstractListModel items to QML GridView asynchronously. When I execute method that loads items to model I have to wait for every item is loaded. How can I get items dynamically (i.e. one by one)?

I have pretty big model objects with 17 fields (QString and QStringList's). Objects are contained in custom model:

class MyListModel : public QAbstractListModel 
{
    Q_OBJECT
public:
    enum ListItemRole {
        IdRole  = Qt::UserRole,
        VisualIndexRole,
        NameRole,
        ...
    };

    MyListModel(QObject *parent = 0) 
        : QAbstractListModel(parent)
    {
    }
    int rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent)
        return m_data.size();
    }
    QVariant data(const QModelIndex &index, int role) const
    {
        if( !index.isValid() || index.row() >= m_data.size() || index.row() < 0)
            return QVariant();

        switch(role) {
        case NameRole:
            return QVariant(m_data.at(index.row())->name());

        ...
        (rest of the roles)
        ...
        }
    }


    QHash<int, QByteArray> roleNames() const
    {
        QHash<int, QByteArray> roles;
        roles[IdRole] = "folderName";
        ...
        return roles;

    }

private:
    QList<Item*> m_data;

}

I'm inserting items to model by append method:

void append(Item *item)
{
    beginInsertRows(QModelIndex(), m_data.size(), m_data.size());
    m_data.append(item);
    endInsertRows();
}

Items is created in loop in other function. This function loads data from 3 JSON files. It takes about 2 seconds to load 50 items.

On top of this list model, there are two QSortFilterProxyModel's responsible for sorting and filtering view. Filtering model is registered as QML type and used in GridView.

What I tried:

  • Use QtConcurrent::run() method for function that create item - FAIL ( view not refreshed after every item)
  • Make QThread for every list item, and load it with Worker class - FAIL ( crashes and strange behavior of application, i.e. empty items, empty spaces between delegates and - as in the first point - not async)
  • Move model to QThread and use item creating loop in Worker class - Partiall Success ( when I use QCoreApplication::processEvents(QEventLoop::AllEvents,100); as a sleep function I could get one by one items, but there is heavy performance issues and - as i read - it is not good approach)

Is there any possible workarounds for my problem?

Sajmplus
  • 262
  • 4
  • 18
  • 1
    See [this answer](http://stackoverflow.com/a/32100486/1329652) for some ideas. – Kuba hasn't forgotten Monica Jan 21 '16 at 14:55
  • Why don't you `emit dataChanged()` signal? Actually, in the case of QML UIs, it should be emited to sync your UI each time model content changed. This is how you can avoid long freezes of UI elements. Check this paragraph https://doc.qt.io/qt-5/qabstractitemmodel.html#dataChanged . Sorry if it doesn't answer your question. I hope it helps. – user3417815 Apr 07 '20 at 01:23

1 Answers1

3

Take a look at this question. I believe you are having the same issue. The problem with asynchronous model loading is that you can load the model data from a separate thread i.e. call your append(Item *item) function from non GUI thread. But you have to make sure that both beginInsertRows(...) and endInsertRows() functions are run from the main GUI thread. The linked question explains how you can do that.

Community
  • 1
  • 1
JuliusG
  • 2,321
  • 21
  • 30