自学内容网 自学内容网

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)!