我试图创建一个基于异步数据库api的列表模型。下面是一个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,还有更多的标签来显示这个项目。
为了能够在标签的定义中使用"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是"toto.sqlite“的数据库会话,m_query是”从测试中选择id“。
问题是,我的数据库会话是异步的,m_database->currentRequestFields()是不可立即使用的,但是我收到一个信号告诉我什么时候可以使用,所以我现在想更新roleNames列表,而不是之前。
即使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();
}
}发布于 2015-12-08 08:57:12
好的,我终于得到了我想要的行为,它能够延迟项目模型角色名称的第一次初始化。代码与某些重新排序的代码基本相同。特别是在调用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();
}
}发布于 2015-12-06 15:37:25
一个可能适合您需要的想法(猜测您希望为该模型的用户提供一个很好的api,并且只具有SELECT查询)是以以下方式构造您的查询:
(从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窃取的想法)
所以简单的例子看起来就像
DatabaseModel {
id: dmodel
table: "test"
colums: ["id"]
database: "toto.sqlite"
}这样,您就有了足够早可用的列名,可以将它们用于角色名称。
https://stackoverflow.com/questions/34089685
复制相似问题