QAbstractListModel:更新角色名称
QAbstractListModel: update role names
我正在尝试创建一个基于异步数据库的列表模型 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 是 "SELECT id FROM test"。
问题是我的数据库会话是异步的,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();
}
}
一个可能符合您需求的想法(假设您想要一个很好的 api 供此模型的用户使用,并且只有 SELECT 查询)是按以下方式构建您的查询:
- 字符串table
- 字符串[]列
- 字符串选择
- 字符串[] selectionArgs
- 字符串分组
- 字符串有
- 字符串顺序
- 字符串限制
因此您的简单示例可能如下所示
DatabaseModel {
id: dmodel
table: "test"
colums: ["id"]
database: "toto.sqlite"
}
这样您就可以尽早获得可用的列名称,以便将它们用于角色名称。
好吧,我终于得到了我想要的行为,它能够延迟我的 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();
}
}
我正在尝试创建一个基于异步数据库的列表模型 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 是 "SELECT id FROM test"。
问题是我的数据库会话是异步的,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();
}
}
一个可能符合您需求的想法(假设您想要一个很好的 api 供此模型的用户使用,并且只有 SELECT 查询)是按以下方式构建您的查询:
- 字符串table
- 字符串[]列
- 字符串选择
- 字符串[] selectionArgs
- 字符串分组
- 字符串有
- 字符串顺序
- 字符串限制
因此您的简单示例可能如下所示
DatabaseModel {
id: dmodel
table: "test"
colums: ["id"]
database: "toto.sqlite"
}
这样您就可以尽早获得可用的列名称,以便将它们用于角色名称。
好吧,我终于得到了我想要的行为,它能够延迟我的 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();
}
}