1. C++给QML传入一个list或者自定义的数据结构

在QML中,model可以在C++中定义,然后在QML中使用,这种方法对于暴露已经存在的C++数据模型或者其他复杂的数据集合给QML是非常有用的。一个C++类可以被定义为QStringList、 QVariantList、 QObjectList或者QAbstractItemModel.其中QStringList、 QVariantList、 QObjectList这三个类型的list用来暴露简单一点的数据给qml是非常有用的,QAbstractItemModel提供了非常大的灵活方法来定义更加复杂的数据结构

数据的静态更新

通过setContextProperty()的方法把一个list传入qml,也就是把一个实例化的对象传入到qml中,当数值有更新的话,view是不知道的,只能通过重新调用setContextProperty()方法重新传入qml

把QStringList传递给qml

qml 代码

// qml部分的代码
 ListView {
      width: 100; height: 100

      model: myModel
      delegate: Rectangle {
          height: 25
          width: 100
          Text { text: modelData }
      }
  }

c++ 代码

// C++部分代码(通过QQmlApplicationEngine方式加载qml)
 QStringList dataList;
      dataList.append("Item 1");
      dataList.append("Item 2");
      dataList.append("Item 3");
      dataList.append("Item 4");

    QQmlApplicationEngine engine;
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("myModel", QVariant::fromValue(strlist));

这种方式是通过QQmlApplicationEngine 来加载QML文件,还有另一种方式是通过 QQuickView来加载QML文件。代码如下所示

// C++部分代码(通过QQuickView方式来加载qml)
      QStringList dataList;
      dataList.append("Item 1");
      dataList.append("Item 2");
      dataList.append("Item 3");
      dataList.append("Item 4");

      QQuickView view;
      QQmlContext *ctxt = view.rootContext();
      ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));

下面附上完整代码

// C++部分代码(完整代码)
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include<QStringList>
#include<QQmlContext>
int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QStringList strlist;
    strlist.append("item1");
    strlist.append("item2");
    strlist.append("item3");
    strlist.append("item4");
    QQmlApplicationEngine engine;
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("myModel", QVariant::fromValue(strlist));
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}

这样我们就可以把一个QStringList从C++中传入QML了。这种方法需要注意的是QML中的view是不知道QStringList的内容发生变化的,如果需要更新QStringList中的数值,只能再次调用QQmlContext::setContextProperty()函数来重新设

把QVariantList传入qml

方法和QStringList是一样的,这里不再赘述了。需要注意的是QML中的view是不知道QStringList的内容发生变化的,如果需要更新QStringList中的数值,只能再次调用QQmlContext::setContextProperty()函数来重新设置。

把一个自定义数据结构list传入qml中

这个这个数据结构一定要是QObject的子类

// C++部分代码(data.h)
class Data : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
  public:
    Data(QObject *parent = nullptr);
    Data(const QString &name, const QString &color, QObject *parent = nullptr);
    QString name()const;
    void setName(const QString &name);
    QString color()const;
    void setColor(const QString& color);
  signals:
    void nameChanged();
    void colorChanged();
  public slots:
  private:
    QString m_name;
    QString m_color;
};
// C++部分代码(data.cpp)
#include "data.h"

Data::Data(QObject *parent) : QObject(parent) {

}

Data::Data(const QString &name, const QString &color, QObject *parent)
    : QObject(parent), m_name(name), m_color(color) {

}

QString Data::name() const {
    return m_name;
}

void Data::setName(const QString &name) {
    if(m_name != name) {
        m_name = name;
        emit nameChanged();
    }
}

QString Data::color() const {
    return m_color;
}

void Data::setColor(const QString &color) {
    if(m_color != color) {
        m_color = color;
        emit colorChanged();
    }
}

// C++部分代码(main.cpp)
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include"data.h"
#include<QQmlContext>
#include<QQuickView>
int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);



    QList<QObject*> datalist;
    datalist.append(new Data("item1", "red"));
    datalist.append(new Data("item2", "green"));
    datalist.append(new Data("item3", "blue"));
    datalist.append(new Data("item4", "yellow"));
    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    QQmlContext *ctxt = view.rootContext();
    ctxt->setContextProperty("myModel", QVariant::fromValue(datalist));
    view.setSource(QUrl("qrc:main.qml"));
    view.show();
    return app.exec();
}
//QML部分代码(main.qml)
ListView{
        width: parent.width
        model:myModel
        delegate: Rectangle{
            width: parent.width
            height: txt.font.pixelSize
            color: model.modelData.color
            Text {
                id: txt
                text: name
            }
        }
    }

数据的动态更新

利用QAbstractListModel实现qml数据的动态更

整体思路是:
step1:根据自己的项目需求创建自定义数据结构
step2:创建数据模型
step3:将定义的数据模型传入qml

  • 创建自定义数据结构 这里定义了一个DeviceList类,里面有 name,value,unit三个数据成员。

class DeviceList {
  public:
    DeviceList(const QString &name, const QString &value, const QString unit);

    QString name() const {
        return m_name;
    }
    QString value() const {
        return m_value;
    }
    QString unit()const {
        return m_unit;
    }
  private:
    QString m_name;
    QString m_value;
    QString m_unit;
};
 
  • 创建数据模型

step2创建数据模型

数据模型必须具备两个条件:
1、必须继承QAbstractListModel这个类。目的是当数据发生变化时,能够自动的通知QML view。
2、由于会用到信号槽,所以要加入 Q_OBJECT宏

class DeviceListModel : public QAbstractListModel {
    Q_OBJECT
  public:
    enum AnimalRoles {
        nameRole = Qt::UserRole + 1,
        valueRole,
        nuitRole
    };

    DeviceListModel(QObject *parent = 0);
    //目的是添加新的设备
    void addDevice(const DeviceList &devicelist);
    //返回list节点个数
    int rowCount(const QModelIndex & parent = QModelIndex()) const;
    //返回数据
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

  protected:
  //Returns the model's role names.
    QHash<int, QByteArray> roleNames() const;
  private:
    QList<DeviceList> m_runTimeData;
};

DeviceListModel::DeviceListModel(QObject *parent)
    : QAbstractListModel(parent) {
}

void DeviceListModel::addDevice(const DeviceList &deviceList) {
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_runTimeData << deviceList;
    endInsertRows();
}

int DeviceListModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_runTimeData.count();
}

QVariant DeviceListModel::data(const QModelIndex & index, int role) const {
    if (index.row() < 0 || index.row() >= m_runTimeData.count())
        return QVariant();

    const DeviceList &deviceList = m_runTimeData[index.row()];
    if (role == nameRole)
        return deviceList.name();
    else if (role == valueRole)
        return deviceList.value();
    else if (role == nuitRole)
        return deviceList.unit();
    return QVariant();
}

QHash<int, QByteArray> DeviceListModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[nameRole] = "name";
    roles[valueRole] = "value";
    roles[nuitRole] = "unit";
    return roles;
}

DeviceList::DeviceList(const QString &name, const QString &value, const QString unit)
    : m_name(name), m_value(value), m_unit(unit) {

}
  • 把模型传入qml

int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);


    DeviceListModel model;
    model.addDevice(DeviceList("ch1局放强度", "1000", "mV"));
    model.addDevice(DeviceList("ch2局放强度", "500", "mV"));
    model.addDevice(DeviceList("ch3局放强度", "800", "mV"));
    model.addDevice(DeviceList("ch1局放能量", "10", "mW"));
    model.addDevice(DeviceList("ch2局放能量", "20", "mW"));
    model.addDevice(DeviceList("ch3局放能量", "15", "mW"));

    QQmlApplicationEngine engine;
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("myModel", &model);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}
import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    visible: true
    id:page
    Row{
        id:tableTitle
        Rectangle{
            width:page.width/3
            height:tableName.font.pixelSize
            Text{
                id:tableName
                text:"测点名称"
                anchors.centerIn: parent
            }
        }
        Rectangle{
            width:page.width/3
            height:tableName.font.pixelSize
            Text{
                id:value
                text:"测量值"
                anchors.centerIn: parent
            }
        }
        Rectangle{
            width:page.width/3
            height:tableName.font.pixelSize
            Text{
                id:unit
                text:"单位"
                anchors.centerIn: parent
            }
        }
    }
    ListView{
        anchors.top: tableTitle.bottom
        width: page.width
        height: page.height-tableTitle.height
        model:myModel
        delegate: myDeleagta
        Component{
        id:myDeleagta
            Row{
                Rectangle{
                    width:page.width/3
                    height:tableName.font.pixelSize
                    Text{
                        text :name
                        anchors.centerIn: parent
                    }
                }
                Rectangle{
                    width:page.width/3
                    height:tableName.font.pixelSize
                    Text{
                        text:value
                        anchors.centerIn: parent
                    }
                }
                Rectangle{
                    width:page.width/3
                    height:tableName.font.pixelSize
                    Text{
                        text:unit
                        anchors.centerIn: parent
                    }
                }
            }
        }


    }
}


本站由 困困鱼 使用 Stellar 创建。