Я пытаюсь создать модель списка на основе асинхронной базы данных api. Вот QML пример того, как я хочу, чтобы иметь возможность использовать его:QAbstractListModel: имена ролей обновлений
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» в определении моего ярлыка Я использую имена ролей, как, что:
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()
недоступен сразу. Однако я получаю сигнал, сообщающий мне, когда это так, я хотел бы обновить список имен роли в данный момент, а не раньше.
Даже если 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();
}
}
Ролевые имена должны обновляться до концаResetModel(). Я не уверен, хотя это будет работать надежно, в прошлый раз, когда я отлаживал это, представления QML не могли справиться с изменением имен ролей, даже если они только изменились во время сброса модели. –
Кроме того, я не вижу смысла динамически создавать имена ролей. Как вы планируете обновлять делегат QML для изменения имен ролей? Не могли ли вы использовать «role001» для «role999» и поместить изменения данных столбца SQL в эти фиксированные имена ролей? –
Фактически имена ролей не «обновляются», их инициализация задерживается, но выполняется только один раз.Мне удалось сделать что-то свое, позвонив beginResetModel ПОСЛЕ ТОГО, что currentRequestFields() станет доступным. Как только я смогу удалить «своеобразное» из предыдущего предложения, я опубликую рабочий код – Nyashes