首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QAbstractListModel:更新角色名称

QAbstractListModel:更新角色名称
EN

Stack Overflow用户
提问于 2015-12-04 13:40:01
回答 2查看 976关注 0票数 2

我试图创建一个基于异步数据库api的列表模型。下面是一个qml示例,说明我希望如何使用它:

代码语言:javascript
复制
ListView {
    id: view;

    anchors.fill: parent;

    model: DatabaseModel {
        id: dmodel

        query: "SELECT id FROM test"
        database: "toto.sqlite"
    }

    delegate: Label {
        anchors.horizontalCenter: parent.horizontalCenter;
        width: view.width / 2;
        height: 30;
        text: id;

        color: "teal";
    }
}

显然,在某个时候,我需要的不仅仅是数据库中的id,还有更多的标签来显示这个项目。

为了能够在标签的定义中使用"id“,我使用了这样的角色名称:

代码语言:javascript
复制
QHash<int, QByteArray> DatabaseListModel::roleNames() const
{
    QHash<int, QByteArray> b = this->QAbstractItemModel::roleNames();

    if (m_query != "" && m_database) {
        QStringList l = m_database->currentRequestFields();
        for (int i = 0; i < l.count(); ++i) {
            b.insert(Qt::UserRole + i + 1, l.at(i).toLocal8Bit());
        }
    }
    return b;
}

在本例中,m_database是"toto.sqlite“的数据库会话,m_query是”从测试中选择id“。

问题是,我的数据库会话是异步的,m_database->currentRequestFields()是不可立即使用的,但是我收到一个信号告诉我什么时候可以使用,所以我现在想更新roleNames列表,而不是之前。

即使m_database看起来可能像个黑匣子,我还是要做些什么来更新模型:

代码语言:javascript
复制
void DatabaseListModel::updateModel()
{
    if (m_query != "" && m_database) {
        m_mutex.lock();
        beginResetModel();
        m_cache.clear();

        QObject::connect(m_database, &CollaoDatabase::databaseReady, this, [this] (CollaoDatabase* database) {
            database->setQueryStringi(m_query);
            database->executei(); //currentRequestFields() becomes available 
            database->fetchAlli();
            database->sendNotifierEventi(0); //when everything written before this line has been executed, ask the database to emit CollaoDatabase::notifierEventProcessed. It's not instant and might take a while depending on the query  
        });
        QObject::connect(m_database, &CollaoDatabase::resultReady, this, [this] (QVariantMap result) {
            if (m_cache.size() <= 0)
                m_cache.reserve(m_database->currentPendingFetches() + 1);
            m_cache.append(result.values());
        });

        QObject::connect(m_database, (void (CollaoDatabase::*)())&CollaoDatabase::notifierEventProcessed, this, [this](){
            endResetModel();
            //TODO: update roleNames here

            m_mutex.unlock();
            m_database = NULL; //as soon as stop() is called, we cannot assume the existance of this object anymore
            //it is therefore safer to make it null now
        });
        QObject::connect(m_database, SIGNAL(notifierEventProcessed()), m_database, SLOT(stop()));

        m_database->start();
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-08 08:57:12

好的,我终于得到了我想要的行为,它能够延迟项目模型角色名称的第一次初始化。代码与某些重新排序的代码基本相同。特别是在调用beginResetModel之前必须有角色名称可用。你可以把这个片段和我问题中的那个比较一下。

代码语言:javascript
复制
void DatabaseListModel::updateModel()
{
    if (m_query != "" && m_database) {
        m_mutex.lock();

        QObject::connect(m_database, &CollaoDatabase::databaseReady, this, [this] (CollaoDatabase* database) {
            database->setQueryStringi(m_query);
            database->executei();
            database->sendNotifierEventi(1);
            database->fetchAlli();
            database->sendNotifierEventi(0);
        });
        QObject::connect(m_database, &CollaoDatabase::resultReady, this, [this] (QVariantMap result) {
            if (m_cache.size() <= 0) {
                m_fields = result.keys();
                beginResetModel();
                m_cache.reserve(m_database->currentPendingFetches() + 1);
                m_numRows = m_database->currentPendingFetches() + 1;
                emit numRowsChanged();
                m_progress = 0;
            }

            m_cache.append(result.values());
            ++m_progress;
            if (m_progress % (m_numRows / 100 + 1) == 0)
                emit progressChanged();
        });

        QObject::connect(m_database, (void (CollaoDatabase::*)(int))&CollaoDatabase::notifierEventProcessed, this, [this](int eventIndex){
            switch (eventIndex) {
            case 0: /*terminate*/
                emit progressChanged();
                endResetModel();
                m_mutex.unlock();
                m_database->stop();
                m_database = NULL; //as soon as stop() is called, we cannot assume the existance of this object anymore
                //it is therefore safer to make it null now
                break;

            case 1: /*now able to reset the model*/
                m_cache.clear();
                break;
            }
        });

        m_database->start();
    }
}
票数 0
EN

Stack Overflow用户

发布于 2015-12-06 15:37:25

一个可能适合您需要的想法(猜测您希望为该模型的用户提供一个很好的api,并且只具有SELECT查询)是以以下方式构造您的查询:

  • 串表
  • String[]列
  • 字符串选择
  • String[] selectionArgs
  • 字符串groupBy
  • 弦形
  • 字符串orderBy
  • 串限

(从http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#query%28java.lang.String,%20java.lang.String[],%20java.lang.String,%20java.lang.String[],%20java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String%29窃取的想法)

所以简单的例子看起来就像

代码语言:javascript
复制
DatabaseModel {
    id: dmodel

    table: "test"
    colums: ["id"]
    database: "toto.sqlite"
}

这样,您就有了足够早可用的列名,可以将它们用于角色名称。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34089685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档