8.qml中tableview使用QtQuick.Controls2
数据模型
开发过程中我们发现qml提供了一些数据模型诸如
ListModel(qquicklistmodel)
FolderListModel(qquickfolderlistmodel)
qquicklistmodel与qquickfolderlistmodel都是派生于qabstractlistmodel
而qabstractlistmodel 是派生于abstractitemmodel的
而qabstractlistmodel 就是单列数据模型
就是重写的columnCount = 1的
而要实现多列的数据模型
需要继承与abstractTablemodel
高版本Qt6官方提供了qml 有个 TableModel
但是以前的版本诸如Qt5就没有TableModel 就得自己去实现这个东西
好在官方也提供了
QSqlQueryModel 数据库只读模型
QSqlTableModel 数据库直接关联模型
其中我想要讲下数据模型中的
virtual QHash<int, QByteArray> roleNames() const
深入解析tableview
需要结合tableview进行分析
TableView{
id: tableView
width: parent.width
height: 300
boundsBehavior: Flickable.OvershootBounds
rowHeightProvider: function (row) { return 60 }
columnWidthProvider: function (column) { return 120 }
delegate: DelegateChooser{
DelegateChoice{
column: 0
delegate: Text {
text: model.index
}
}
DelegateChoice{
column: 1
delegate: Text {
text: model.display
}
}
DelegateChoice{
column: 2
delegate: Text {
text: model.index
}
}
DelegateChoice{
column: 3
delegate: Text {
text: display
Component.onCompleted: {
console.log(model["display"])
}
}
}
DelegateChoice{
column: 4
delegate: Row{
Button{
text: "修改"
}
Button{
text: "删除"
}
}
}
}
}
tableview.model 与 delegate中的model.index或者model.display
这里面用到的model是不同的东西
怎么知道呢? 使用
DelegateChoice{
column: 2
delegate: Text {
text: display
Component.onCompleted: {console.log(model)}
}
}
结果QQmlDMAbstractItemModelData(0x26cf170)
在delegate中打印你会发现确实不同,那delegate中的model是什么呢?
可以理解为传递给委托的行数据模型-----那么是怎么将比如listmodel中的字段加入进去的呢
TableView{
model:ListModel{
ListElement{name:"zhangsan";age:18}
}
delegate:Text{
text: model.name + ':' + age;
}
}
原理就是listelement添加到listmodel的时候会将rolenames填充好然后
前往tableview 源码查看–qquicktableview
会通过这个将委托生成一个实例
QObject* object = model->object(modelIndex, incubationMode);
这个model是QQmlTableInstanceModel
找到qqmltableinstancemodel的文件打开cpp
QObject *QQmlTableInstanceModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
{
Q_ASSERT(m_delegate);
Q_ASSERT(index >= 0 && index < m_adaptorModel.count());
Q_ASSERT(m_qmlContext && m_qmlContext->isValid());
QQmlDelegateModelItem *modelItem = resolveModelItem(index);
if (!modelItem)
return nullptr;
if (modelItem->object) {
// The model item has already been incubated. So
// just bump the ref-count and return it.
modelItem->referenceObject();
return modelItem->object;
}
// The object is not ready, and needs to be incubated
incubateModelItem(modelItem, incubationMode);
if (!isDoneIncubating(modelItem))
return nullptr;
// Incubation is done, so the task should be removed
Q_ASSERT(!modelItem->incubationTask);
if (!modelItem->object) {
// The object was incubated synchronously (otherwise we would return above). But since
// we have no object, the incubation must have failed. And when we have no object, there
// should be no object references either. And there should also not be any internal script
// refs at this point. So we delete the model item.
Q_ASSERT(!modelItem->isObjectReferenced());
Q_ASSERT(!modelItem->isReferenced());
m_modelItems.remove(modelItem->index);
delete modelItem;
return nullptr;
}
// Incubation was completed sync and successful
modelItem->referenceObject();
return modelItem->object;
}
QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
{
// Check if an item for the given index is already loaded and ready
QQmlDelegateModelItem *modelItem = m_modelItems.value(index, nullptr);
if (modelItem)
return modelItem;
QQmlComponent *delegate = resolveDelegate(index);
if (!delegate)
return nullptr;
// Check if the pool contains an item that can be reused
modelItem = takeFromReusableItemsPool(delegate);
if (modelItem) {
reuseItem(modelItem, index);
m_modelItems.insert(index, modelItem);
return modelItem;
}
// Create a new item from scratch
modelItem = m_adaptorModel.createItem(m_metaType, index);
if (modelItem) {
modelItem->delegate = delegate;
m_modelItems.insert(index, modelItem);
return modelItem;
}
qWarning() << Q_FUNC_INFO << "failed creating a model item for index: " << index;
return nullptr;
}
重点 modelItem = m_adaptorModel.createItem(m_metaType, index);
找到qqmladaptormodel就是这个东西所在位置
然后你就会发现他就往这个委托中注入了一个data这个data就是所谓的model
model就是调用了roleNames 做了一个动态属性的插入
这也就是有了我们所谓的可以调用listelement 可以通过字段名的方式
model.name的原因,当然也可以model[“name”]
void initializeConstructor(QQmlAdaptorModelEngineData *const data)
{
QV4::ExecutionEngine *v4 = data->v4;
QV4::Scope scope(v4);
QV4::ScopedObject proto(scope, v4->newObject());
proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);
QV4::ScopedProperty p(scope);
typedef QHash<QByteArray, int>::const_iterator iterator;
for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
const int propertyId = propertyRoles.indexOf(it.value());
const QByteArray &propertyName = it.key();
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
QV4::ExecutionContext *global = v4->rootContext();
QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property));
QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property));
p->setGetter(g);
p->setSetter(s);
proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
}
prototype.set(v4, proto);
}
所以我们要想要通过model获取指定字段的值就需要使用
就得封装好abstractmodel的roleNames 与data虚函数
好了下面就以sqlquerymodel为例子封装一个qmlsqlquerymodel以供qml使用
实际上直接将qsqlquerymodel 注册到qml也能使用,但是他的rolenames提供了display字段
只能使用model.display 存在缺点就是无法跨列设置数据
就比如说有两个字段id与name 我想拼接在一起,但是只有display根本就搞不了
当然可以写一个方法类似于folderlistmodel中getProperty(i,propertyname);但是没必要
qmlsqlquerymodel实现
请参考https://blog.csdn.net/zjgo007/article/details/112673115
QmlSqlQueryModel.h
#include "QmlSqlQueryModel.h"
#include <QSqlRecord>
#include <QSqlField>
QmlSqlQueryModel::QmlSqlQueryModel(QObject *parent) :
QSqlQueryModel(parent)
{
}
QVariant QmlSqlQueryModel::data(const QModelIndex &index, int role) const
{
QVariant value;
if(role < Qt::UserRole) {
value = QSqlQueryModel::data(index, role);
}
else {
int columnIdx = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnIdx);
value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
return value;
}
QHash<int, QByteArray> QmlSqlQueryModel::roleNames() const
{
return m_roleNames;
}
void QmlSqlQueryModel::setQuery(const QSqlQuery &query)
{
qDebug()<<__FUNCTION__;
QSqlQueryModel::setQuery(query);
}
void QmlSqlQueryModel::queryChange()
{
QSqlQueryModel::queryChange();
generateRoleNames();
}
void QmlSqlQueryModel::generateRoleNames()
{
m_roleNames.clear();
for( int i = 0; i < record().count(); i ++) {
m_roleNames.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
}
}
QmlSqlQueryModel.cpp
#include "QmlSqlQueryModel.h"
#include <QSqlRecord>
#include <QSqlField>
QmlSqlQueryModel::QmlSqlQueryModel(QObject *parent) :
QSqlQueryModel(parent)
{
}
QVariant QmlSqlQueryModel::data(const QModelIndex &index, int role) const
{
QVariant value;
if(role < Qt::UserRole) {
value = QSqlQueryModel::data(index, role);
}
else {
int columnIdx = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnIdx);
value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
return value;
}
QHash<int, QByteArray> QmlSqlQueryModel::roleNames() const
{
return m_roleNames;
}
void QmlSqlQueryModel::setQuery(const QSqlQuery &query)
{
qDebug()<<__FUNCTION__;
QSqlQueryModel::setQuery(query);
}
void QmlSqlQueryModel::queryChange()
{
QSqlQueryModel::queryChange();
generateRoleNames();
}
void QmlSqlQueryModel::generateRoleNames()
{
m_roleNames.clear();
for( int i = 0; i < record().count(); i ++) {
m_roleNames.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
}
}
TableView{
id: tableView
width: parent.width
height: 300
boundsBehavior: Flickable.OvershootBounds
rowHeightProvider: function (row) { return 60 }
columnWidthProvider: function (column) { return 120 }
delegate: DelegateChooser{
DelegateChoice{
column: 0
delegate: Text {
text: model.id
}
}
DelegateChoice{
column: 1
delegate: Text {
text: model.name
}
}
DelegateChoice{
column: 2
delegate: Text {
text: model.score
}
}
DelegateChoice{
column: 3
delegate: Text {
text: model.class
}
}
DelegateChoice{
column: 4
delegate: Row{
Button{
text: "修改"
}
Button{
text: "删除"
}
}
}
}
}
原文地址:https://blog.csdn.net/adsd1233123/article/details/143593465
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!