我试图基于异步数据库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();
}
}
答案 0 :(得分:0)
一个可能符合您需求的想法(猜测您希望为此模型的用户提供一个好的API并且只有SELECT查询)是按以下方式构建查询:
所以你的简单例子看起来像
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();
}
}