• QML使用C++ model(基本用法)


    前言

    界面开发无外乎是布局和界面的美化,而现代业务显示中最常见的非列表、表格莫属,列表表格的界面在Qt中采用model/view进行开发,model/view能够很好实现业务与界面的分离,对于复杂的业务来说是非常有用的。

    Qt QML的model/view相对于widget更简单易用。QML提供有一些model,如数组、键值对等,这些model都相对比较简易,处理复杂的数据和多样的业务就比较费劲了。

    所以,对于复杂的数据,Qt提供了另外一种方式来解决,就是使用C++的model,即model的数据和业务处理都是用C++。我们熟知的用C++写业务,QML来写页面,QML使用C++的model来显示,这就是一个很典型的C++和QML分工合作的体现。

    下面就具体来看看是如何使用的

    基本用法

    C++的model需要继承自QAbstractListModel,并重写QAbstractListModel的虚函数

    1. #include <QAbstractListModel>
    2. class DataEntryModel : public QAbstractListModel
    3. {
    4. Q_OBJECT
    5. public:
    6. explicit DataEntryModel(QObject *parent = nullptr);
    7. ~DataEntryModel();
    8. public: // QAbstractItemModel interface
    9. int rowCount(const QModelIndex &parent) const override;
    10. QVariant data(const QModelIndex &index, int role) const override;
    11. private:
    12. QList<QString> m_data;
    13. };
    1. #include <QColor>
    2. DataEntryModel::DataEntryModel(QObject *parent):
    3. QAbstractListModel(parent)
    4. {
    5. // initialize our data (QList<QString>) with a list of color names
    6. m_data = QColor::colorNames();
    7. }
    8. DataEntryModel::~DataEntryModel()
    9. {
    10. }
    11. int DataEntryModel::rowCount(const QModelIndex &parent) const
    12. {
    13. Q_UNUSED(parent);
    14. // return our data count
    15. return m_data.count();
    16. }
    17. QVariant DataEntryModel::data(const QModelIndex &index, int role) const
    18. {
    19. // the index returns the requested row and column information.
    20. // we ignore the column and only use the row information
    21. int row = index.row();
    22. // boundary check for the row
    23. if(row < 0 || row >= m_data.count()) {
    24. return QVariant();
    25. }
    26. // A model can return data for different roles.
    27. // The default role is the display role.
    28. // it can be accesses in QML with "model.display"
    29. switch(role) {
    30. case Qt::DisplayRole:
    31. // Return the color name for the particular row
    32. // Qt automatically converts it to the QVariant type
    33. return m_data.value(row);
    34. }
    35. // The view asked for other data, just return an empty QVariant
    36. return QVariant();
    37. }

    该例子只做基本的显示,维护一个QList<QString> m_data存放数据,重写rowCount()、data()虚函数,QML内部实现是通过这两个接口获取行数和数据的,其中data()接口的第二个参数role使用的默认的类型Qt::DisplayRole,还可以自定义自己的类型,后面会做介绍。

    注册QML类型:

    qmlRegisterType<DataEntryModel>("org.example", 1, 0, "DataEntryModel");

    QML调用:

    1. import QtQuick 2.15
    2. import QtQuick.Window 2.15
    3. import org.example 1.0
    4. Window {
    5. width: 640
    6. height: 480
    7. visible: true
    8. title: qsTr("Hello World")
    9. ListView {
    10. id: view
    11. anchors.fill: parent
    12. model: DataEntryModel {}
    13. delegate: Text {
    14. // use the defined model role "display"
    15. text: model.display
    16. }
    17. }
    18. }

    运行结果:

     自定义类型的model

    1. #include <QAbstractListModel>
    2. class ModelData;
    3. class DataListModel : public QAbstractListModel
    4. {
    5. Q_OBJECT
    6. public:
    7. explicit DataListModel(QObject *parent = nullptr);
    8. enum AnimalRoles {
    9. TypeRole = Qt::UserRole + 1,
    10. SizeRole1
    11. };
    12. int rowCount(const QModelIndex & parent = QModelIndex()) const override;
    13. QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
    14. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
    15. Q_INVOKABLE void insert(int index, const ModelData &data);
    16. Q_INVOKABLE void append(const ModelData &data);
    17. Q_INVOKABLE void remove(int index);
    18. Q_INVOKABLE void append(const QVariantMap map);
    19. signals:
    20. void countChanged(int arg);
    21. private:
    22. int count() const;
    23. protected:
    24. QHash<int, QByteArray> roleNames() const override;
    25. private:
    26. QList<ModelData> m_list;
    27. };
    28. class ModelData
    29. {
    30. public:
    31. ModelData(const QString &type, const QString &size):
    32. m_type(type), m_size(size)
    33. {
    34. }
    35. QString type() const {return m_type;}
    36. QString size() const {return m_size;}
    37. void setType(const QString &type) {m_type = type;}
    38. void setSize(const QString & size) {m_size = size;}
    39. private:
    40. QString m_type;
    41. QString m_size;
    42. };

    代码中可以看到维护了一个自定义类型的list-QList<ModelData> m_list,并增加了两个枚举类型,对应自定义ModelData里的成员变量,并提供了增删的接口,还重写了setData(),实现该接口QML可直接对数据进行修改,这个model相当于支持了增删改的功能。这个model就比上面的要复杂得多,能够应付一般的项目使用了

    1. DataListModel::DataListModel(QObject *parent):
    2. QAbstractListModel(parent)
    3. {
    4. }
    5. int DataListModel::rowCount(const QModelIndex &parent) const
    6. {
    7. Q_UNUSED(parent);
    8. return m_list.count();
    9. }
    10. QVariant DataListModel::data(const QModelIndex &index, int role) const
    11. {
    12. if (index.row() < 0 || index.row() >= m_list.count())
    13. return QVariant();
    14. const ModelData &data = m_list[index.row()];
    15. // qDebug() << "row: " << index.row();
    16. if (role == TypeRole)
    17. return data.type();
    18. else if (role == SizeRole1)
    19. return data.size();
    20. return QVariant();
    21. }
    22. bool DataListModel::setData(const QModelIndex &index, const QVariant &value, int role)
    23. {
    24. if (index.row() < 0 || index.row() >= m_list.count())
    25. return false;
    26. ModelData &data = m_list[index.row()];
    27. if (role == TypeRole)
    28. data.setType(value.toString());
    29. else if (role == SizeRole1)
    30. data.setSize(value.toString());
    31. QVector<int> roles = {role};
    32. emit dataChanged(index, index, roles);
    33. return true;
    34. }
    35. void DataListModel::insert(int index, const ModelData &data)
    36. {
    37. if(index < 0 || index > m_list.count()) {
    38. return;
    39. }
    40. beginInsertRows(QModelIndex(), index, index);
    41. m_list.insert(index, data);
    42. endInsertRows();
    43. emit countChanged(m_list.count());
    44. }
    45. void DataListModel::append(const ModelData &data)
    46. {
    47. insert(count(), data);
    48. }
    49. void DataListModel::remove(int index)
    50. {
    51. if(index < 0 || index >= m_list.count()) {
    52. return;
    53. }
    54. beginRemoveRows(QModelIndex(), index, index);
    55. m_list.removeAt( index );
    56. endRemoveRows();
    57. emit countChanged(m_list.count());
    58. }
    59. void DataListModel::append(const QVariantMap map)
    60. {
    61. QString type = map["type"].toString();
    62. QString size = map["size"].toString();
    63. ModelData data(type, size);
    64. insert(count(), data);
    65. }
    66. int DataListModel::count() const
    67. {
    68. return rowCount(QModelIndex());
    69. }
    70. QHash<int, QByteArray> DataListModel::roleNames() const
    71. {
    72. QHash<int, QByteArray> roles;
    73. roles[TypeRole] = "type";
    74. roles[SizeRole1] = "size";
    75. return roles;
    76. }

    QML使用

    1. import QtQuick 2.15
    2. import QtQuick.Window 2.15
    3. import QtQuick.Controls 2.15
    4. import org.example 1.0
    5. Window {
    6. width: 640
    7. height: 480
    8. visible: true
    9. title: qsTr("Hello World")
    10. DataListModel {
    11. id: myModel
    12. Component.onCompleted: {
    13. //增加数据
    14. myModel.append({"type": "11","size": "222"})
    15. myModel.append({"type": "222","size": "333"})
    16. myModel.append({"type": "333","size": "444"})
    17. }
    18. }
    19. ListView {
    20. id: listview
    21. clip: true
    22. width: parent.width
    23. height: parent.height
    24. model: myModel
    25. delegate: Item {
    26. id: delegate
    27. width: listview.width
    28. height: 30
    29. Row {
    30. spacing: 5
    31. Text {
    32. //取值
    33. text: type
    34. }
    35. Text {
    36. //取值
    37. text: size
    38. color: "red"
    39. }
    40. Button {
    41. height: parent.height
    42. onClicked: {
    43. //修改值
    44. size = "0000"
    45. }
    46. }
    47. }
    48. }
    49. }
    50. }

     可以看到取值是通过type、size就能拿到数据,这些关键词是在roleNames()中定义的,猜测应该是通过QHash<int, QByteArray>的value取到key值,即role类型,再用role通过data接口获取值进行显示的,具体是不是这样得去看源码才知道,没有具体研究过。

    结语

    以上就是QML显示C++model的基本用法介绍,QML book关于这方面的介绍点这里查看。下一篇将介绍C++model的一些高级用法,如过滤排序撤销。

    Demo github地址:GitHub - a137748099/QMLModelView: c++ model with QML view

  • 相关阅读:
    ZooKeeper
    第04章 Tableau高级操作
    百度云原生数据库GaiaDB的HTAP与多地多活技术实践
    51单片机OLED收银电子秤称重计价清零去皮金额累计HX711
    5年经验之谈 —— 性能测试如何定位分析性能瓶颈?
    DM8 数据库主备/读写分离集群增加节点
    SIEMENS S7-1200 汽车转弯灯程序 编程与分析
    【智慧公寓】东胜物联嵌入式硬件解决方案,为智慧公寓解决方案商降本增效,更快实现产品规模化生产
    Java for循环倒序输出
    【C++ 初阶】运算符重载详解✌
  • 原文地址:https://blog.csdn.net/a137748099/article/details/125361895