标题的「数据」可以是:
类的对象、类的属性、类的方法、信号,或者就是单纯的某个值。

QML 与 C++ 通过 QQmlContext 通讯。

一般传输数据时机是:QQmlEngine 构造好了,但没有加载任何 qml 文档之前。

单纯一个值

  1. QQmlApplicationEngine engine;
  2. engine.rootContext()->setContextProperty("cppVal", 50);
  3. // QML
  4. title: cppVal

类的对象和类的方法

类的方法必须是以下两种之一:

  • Q_INVOKABLE 标记的 public 函数
  • public 槽函数

C++ 函数的参数中的 QObject* 类型,相当于 QML 中的对象 id 或引用对象的 var 值。
C++ 函数的返回值也会转换成对应的 js 类型。

  1. public:
  2. Q_INVOKABLE int cppFunc(int a, int b);
  3. CppData cd;
  4. engine.rootContext()->setContextProperty("cppObj", &cd);
  5. //QML
  6. title: cppObj.cppFunc(4, 8)

类的信号

在 QML 中,可以通过 Connections 对象来接收 C++ 的信号
C++ 定义的信号的参数名(val),QML 可以直接用

可以看到,QML 想调用类的方法或者接收类的信号,都是要传一个类的对象给 QML .

  1. // C++
  2. signals:
  3. void cppSignal(int val);
  4. int CppData::cppFunc(int a, int b)
  5. {
  6. emit cppSignal(88);
  7. return a + b;
  8. }
  9. // QML
  10. Connections {
  11. target: cppObj
  12. onCppSignal: {
  13. console.log(val);
  14. }
  15. }
  16. Component.onCompleted: {
  17. cppObj.cppFunc(4, 9)
  18. win.show()
  19. }

还有一种方法在 QML 中接收 C++ 的信号:
把 C++ 的类注册到元对象系统,这时这个类就相当于一个组件,在组件内使用 onSignal 来处理。

类的属性

类的属性可以分三种:基本类型如 int,对象类型如 Persion,列表类型

由于 QList 不是 QObject 的派生类,强大的元对象系统鞭长莫及。应该使用 QQmlListProperty 替代。

基本类型

  1. // 法一(较繁琐)
  2. Q_PROPERTY(QString qmlName READ name WRITE setName NOTIFY nameChanged)
  3. signals:
  4. void nameChanged();
  5. public:
  6. QString name() const;
  7. void setName(const QString &name);
  8. private:
  9. QString m_name;
  10. // 法二(简洁)
  11. Q_PROPERTY(QString qmlName MEMBER m_name NOTIFY nameChanged)
  12. signals:
  13. void nameChanged();
  14. private:
  15. QString m_name

对象类型

  1. class Compose : public QObject
  2. {
  3. Q_OBJECT
  4. Q_PROPERTY(int qmlAttr MEMBER attr)
  5. public:
  6. explicit Compose(QObject *parent=nullptr): QObject(parent){}
  7. private:
  8. int attr;
  9. };
  10. class CppData : public QObject
  11. {
  12. Q_OBJECT
  13. Q_PROPERTY(Compose *qmlCompose MEMBER compose)
  14. public:
  15. explicit CppData(QObject *parent = nullptr) : QObject(parent)
  16. {
  17. compose = new Compose(this);
  18. }
  19. private:
  20. Compose *compose;
  21. };
  22. // main.cpp
  23. qmlRegisterType<Compose>("ZZ", 1, 0, "A");
  24. qmlRegisterType<CppData>("ZZ", 1, 0, "B");
  25. // QML
  26. import ZZ 1.0
  27. B {
  28. id: b
  29. qmlCompose: A {
  30. qmlAttr: 56
  31. }
  32. }
  33. B {
  34. id: bb
  35. qmlCompose{ // 分组属性,生命周期由父对象控制
  36. qmlAttr: 57
  37. }
  38. }
  39. Component.onCompleted: {
  40. console.log(b.qmlCompose.qmlAttr)
  41. }

列表类型

一般情况下数据都是从 cpp 中获取,所以这里只讨论使用 cpp 作为数据模型的情况。
可以粗略分为三种:

QStringList
  1. //C++
  2. QStringList aa;
  3. aa << "aaaaa" << "bbbb" << "ccccc";
  4. engine.rootContext()->setContextProperty("aa", QVariant::fromValue(aa));
  5. //QML
  6. delegate: Text{text:modelData} // 或者 model.modelData

QList
  1. // C++
  2. Q_PROPERTY(QString data MEMBER m_data NOTIFY dataChanged)
  3. Q_PROPERTY(int number MEMBER m_number NOTIFY numberChanged)
  4. QList<QObject*> ls;
  5. ls.append(new Name("aaa", 1));
  6. ls.append(new Name("bbb", 2));
  7. ls.append(new Name("ccc", 3));
  8. engine.rootContext()->setContextProperty("ls", QVariant::fromValue(ls));
  9. // QML
  10. delegate: Text {text: model.modelData.data + ": " + number}

继承 QAbstractListModel

还是先来说说使用 QML作为数据模型的情况,关键是了解 role 概念:

  1. ListModel {
  2. id: fruitModel
  3. ListElement {
  4. name: "Apple" // 这是一个 role, 不是属性
  5. cost: 2.45 // 这又是一个 role
  6. }
  7. ListElement {
  8. name: "Orange"
  9. cost: 3.25
  10. }
  11. }
  12. ListView {
  13. anchors.fill: parent
  14. model: fruitModel
  15. delegate: Row {
  16. Text { text: "Fruit: " + name } // 在 delegate 中访问 role 的两种方式
  17. Text { text: "Cost: $" + model.cost }
  18. }
  19. }

在 QAbstractListModel 的基类 QAbstractItemModel 有一个 public 的虚函数:

  1. // 定义一堆 role
  2. enum AbstractListRoles{
  3. NameRole=Qt::UserRole+1,
  4. ColorRole,
  5. NumberRole
  6. };
  7. // 给每个 role 起个名称,方便 qml 中使用
  8. QHash<int, QByteArray> QAbstractItemModel::roleNames() const
  9. {
  10. QHash<int,QByteArray> roles;
  11. roles.insert(AbstractListRoles::NameRole,"myname");
  12. roles.insert(AbstractListRoles::ColorRole,"mycolor");
  13. roles.insert(AbstractListRoles::NumberRole,"mynumber");
  14. return roles;
  15. }

维护 QList 列表,实现 data、rowcount 方法

  1. private:
  2. QList<AbstractList> m_abstractList; //抽象列表类容器
  3. int AbstractListModel::rowCount(const QModelIndex &parent) const
  4. {
  5. Q_UNUSED(parent);
  6. return m_abstractList.count();
  7. }
  8. QVariant AbstractListModel::data(const QModelIndex &index, int role) const
  9. {
  10. if(index.row()<0||index.row()>=m_abstractList.count())
  11. return QVariant();
  12. const AbstractList &abstractList=m_abstractList[index.row()];
  13. if(role==AbstractListRoles::NameRole)
  14. return abstractList.name();
  15. else if(role==AbstractListRoles::ColorRole)
  16. return abstractList.color();
  17. else if(role==AbstractListRoles::NumberRole)
  18. return abstractList.number();
  19. return QVariant();
  20. }

参考文档:
https://blog.csdn.net/qq_35173114/article/details/80873842