QAbstractListModel:更新角色名称

时间:2015-12-04 13:40:01

标签: c++ qt model-view-controller qml qabstractitemmodel

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

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,而不仅仅需要一个Label来显示此项目。

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

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是&#34; toto.sqlite&#34;的数据库会话。在这种情况下,m_query是&#34; SELECT id FROM test&#34;。

问题是我的数据库会话是异步的并且m_database->currentRequestFields()不能立即使用,但是我收到一个信号告诉我它何时是这样我想在此时更新roleNames列表而不是之前。< / p>

即使m_database可能看起来像黑盒子,我也是这样做来更新模型的:

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();
    }
}

2 个答案:

答案 0 :(得分:0)

一个可能符合您需求的想法(猜测您希望为此模型的用户提供一个好的API并且只有SELECT查询)是按以下方式构建查询:

  • 字符串表
  • String []列
  • 字符串选择
  • String [] selectionArgs
  • String groupBy
  • 字符串
  • String 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

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

public class Game1 : Microsoft.Xna.Framework.Game
{
    Background background;

    protected override void LoadContent()
    {
        // Assign Background
        background = new Background(Content.Load<Texture2D>("Stars"),GraphicsDevice, 128);
    }  

    protected override void Update(GameTime gameTime)
    {
        if(Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
            this.Exit();

        background.Update();
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(bgc);
        spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
        // Call all drawing functions here 
        background.Draw(spriteBatch);
        player1.Draw(spriteBatch);
        player2.Draw(spriteBatch);
        // 
        spriteBatch.End();
        base.Draw(gameTime);
    }

通过这种方式,您可以尽早使用列名称将其用于角色名称。

答案 1 :(得分:0)

好的,我终于得到了我想要的行为,这可以延迟我的itemModel的角色名称的第一次初始化。代码与一些重新排序基本相同。特别是角色名称必须在调用beginResetModel之前可用。您可以将此代码段与我的问题中的代码段进行比较

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();
    }
}
相关问题