一、適用情況
在C++里將數據生成,然后將這個數據設置為qml的上下文屬性,在qml里就能使用了
二、傳遞基礎類型
1、main.cpp
QQuickWidget *m_widget = new QQuickWidget(this); m_widget->setGeometry(0, 0, this->width(), this->height()); //關鍵代碼 QString str = "zhuxy"; m_widget->rootContext()->setContextProperty("Zhuxy",str); m_widget->setSource(QUrl("./main.qml")); m_widget->show();
2、main.qml
import QtQuick 2.0 Rectangle { id: mainWindow x: 30; y: 80; width: 1000; height: 800; Component.onCompleted: { console.log(Zhuxy); } }
這里直接能用Zhuxy這個上下文屬性
三、ListView+QStringList作為model
1、main.cpp
QStringList list; list << "1" << "2"; m_widget->rootContext()->setContextProperty("Zhuxy",QVariant::fromValue(list));//不能是Test?? m_widget->setSource(QUrl("./test.qml")); m_widget->show();
2、test.qml
import QtQuick 2.0
ListView { width: 100; height: 100 model: myModel delegate: Rectangle { height: 25 width: 100 Text { text: modelData } } }
注意:經過測試這個上下文屬性不能取名為Test(可能已經是內置上下文屬性)
四、ListView+qml可訪問的C++類
1、
mydata.h
#ifndef MYDATA_H #define MYDATA_H #include <QObject> class Mydata : public QObject { Q_OBJECT Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) public: Mydata(QObject *parent = nullptr); Mydata(const QString &value, const QString &name, QObject *parent = nullptr); QString value()const; void setValue(const QString &value); QString name()const; void setName(const QString& name); signals: void valueChanged(); void nameChanged(); private: QString m_value; QString m_name; }; #endif // MYDATA_H
value和name就是qml可訪問的值
mydata.cpp
#include "mydata.h" Mydata::Mydata(QObject *parent) : QObject(parent) { } Mydata::Mydata(const QString &value, const QString &name, QObject *parent) : QObject(parent),m_value(value),m_name(name) { } QString Mydata::value() const { return m_value; } void Mydata::setValue(const QString &value) { if(this->m_value != value) { this->m_value = value; emit valueChanged(); } } QString Mydata::name() const { return m_name; } void Mydata::setName(const QString &name) { if(this->m_name != name) { this->m_name = name; emit nameChanged(); } }
2、test.qml
import QtQuick 2.0 Rectangle { id: mainWindow x: 30; y: 80; width: 1000; height: 800; ListView { anchors.fill: parent; model: ParaListModel; delegate: delegate_list spacing: 20; orientation: ListView.Horizontal //委托 Component { id: delegate_list; Rectangle { id: rect; width: 80; height: width; color: "green"; Text { id: text1; text: value; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; font.pixelSize: 16; anchors.horizontalCenter: parent.horizontalCenter; anchors.top: parent.top; anchors.topMargin: 10; color: "white"; } Text { id: text2; text: name; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; font.pixelSize: 16; anchors.horizontalCenter: parent.horizontalCenter; anchors.bottom: parent.bottom; anchors.bottomMargin: 10; color: "white"; } } } } }
3、main.cpp
QList<QObject*> datalist; datalist.append(new Mydata("item1", "red")); datalist.append(new Mydata("item2", "green")); datalist.append(new Mydata("item3", "blue")); datalist.append(new Mydata("item4", "yellow")); m_widget->rootContext()->setContextProperty("ParaListModel",QVariant::fromValue(datalist));
注意必須是QObject指針類型才能放進list等容器里,因為QObject的賦值構造函數是delete的
五、ListView+QAbstractListModel子類
注意當list的個數增加或減少是不支持更新的。
1、C++模型類ParaListModel.h
#ifndef PARALISTMODEL_H #define PARALISTMODEL_H #include <QAbstractListModel> struct ParaModel { ParaModel() { value = ""; nodeName = ""; nodeType = ""; tableName = ""; fieldName = ""; module = ""; location = ""; rectRadius = -1; } //核心屬性 QString value; QString nodeName; QString nodeType; QString tableName; QString fieldName; //附加屬性 QString module; QString location; int rectRadius; }; class ParaListModel : public QAbstractListModel { Q_OBJECT public: ParaListModel(QObject* parent = 0); enum Roles//qml用來識別別名的規則 { valueRole = Qt::UserRole + 1, nodeNameRole, nodeTypeRole, tableNameRole, fieldNameRole, moduleRole, locationRole, rectRadiusRole }; void addModel(const ParaModel &deviceList);//C++設置值 void update(int index, const ParaModel ¶Model);//C++更新 int rowCount(const QModelIndex &parent = QModelIndex()) const;//qml內部調用,不用多管直接重寫即可 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;//qml內部調用,不用多管直接重寫即可 protected: QHash<int, QByteArray> roleNames() const;//qml內部調用,不用多管直接重寫即可 private: QList<ParaModel> m_data; }; #endif // PARALISTMODEL_H
C++模型類ParaListModel.cpp
#include "paralistmodel.h" ParaListModel::ParaListModel(QObject *parent) : QAbstractListModel(parent) { } void ParaListModel::addModel(const ParaModel ¶Model) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_data << paraModel; endInsertRows(); } int ParaListModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_data.count(); } QVariant ParaListModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= m_data.count()) return QVariant(); const ParaModel ¶Model = m_data[index.row()]; switch (role) { case valueRole: return paraModel.value; break; case nodeNameRole: return paraModel.nodeName; break; case nodeTypeRole: return paraModel.nodeType; break; case tableNameRole: return paraModel.tableName; break; case fieldNameRole: return paraModel.fieldName; break; case moduleRole: return paraModel.module; break; case locationRole: return paraModel.location; break; case rectRadiusRole: return paraModel.rectRadius; break; default: break; } return QVariant(); } void ParaListModel::update(int index, const ParaModel ¶Model) { if (index < 0 || index >= m_data.count()) return; ParaModel &srcModel = m_data[index]; if(paraModel.value != "") { srcModel.value = paraModel.value; } if(paraModel.nodeName != "") { srcModel.nodeName = paraModel.nodeName; } if(paraModel.nodeType != "") { srcModel.nodeType = paraModel.nodeType; } if(paraModel.tableName != "") { srcModel.tableName = paraModel.tableName; } if(paraModel.fieldName != "") { srcModel.fieldName = paraModel.fieldName; } if(paraModel.module != "") { srcModel.module = paraModel.module; } if(paraModel.location != "") { srcModel.location = paraModel.location; } if(paraModel.rectRadius != -1) { srcModel.rectRadius = paraModel.rectRadius; } } //qml通過這里的QByteArray來訪問數據 QHash<int, QByteArray> ParaListModel::roleNames() const { QHash<int, QByteArray> roles; roles[valueRole] = "value"; roles[nodeNameRole] = "nodeName"; roles[nodeTypeRole] = "nodeType"; roles[tableNameRole] = "tableName"; roles[fieldNameRole] = "fieldName"; roles[moduleRole] = "module"; roles[locationRole] = "location"; roles[rectRadiusRole] = "rectRadius"; return roles; }
qml通過3個重寫的函數來獲取每個model的值:
首先通過rouCount獲取model個數;
再通過roleNames獲取每個變量名和其role的值;
最后根據role的值訪問data函數,獲取到真實值
2、test.qml
import QtQuick 2.0 Rectangle { width: 800; height: 300; color: "#222648";//背景色 property int rect_width: 80;//參數寬度 property color text_color: "white";//字體顏色 ListView { width: parent.width; height: rect_width; anchors.centerIn: parent; model: ParaListModel; delegate: delegate_list spacing: 20; orientation: ListView.Horizontal } //委托 Component { id: delegate_list; Rectangle { id: rect; width: rect_width; height: width; radius: rectRadius; color: bkColor; property string q_tableName: tableName;//其他不用顯示的屬性 property string q_fieldName: fieldName; Text { id: text1; text: value; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; font.pixelSize: 16; anchors.horizontalCenter: parent.horizontalCenter; anchors.top: parent.top; anchors.topMargin: 10; color: text_color; } Text { id: text2; text: nodeName; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; font.pixelSize: 16; anchors.horizontalCenter: parent.horizontalCenter; anchors.bottom: parent.bottom; anchors.bottomMargin: 10; color: text_color; } MouseArea { anchors.fill: parent; hoverEnabled: true; cursorShape: (containsMouse? (pressed? Qt.ClosedHandCursor: Qt.OpenHandCursor): Qt.ArrowCursor);//設置鼠標樣式 onDoubleClicked: { console.log(q_tableName,q_fieldName); } } } } }
3、main.cpp
m_widget = new QQuickWidget(this); m_widget->setGeometry(0, 0, this->width(), this->height()); //關鍵代碼 ParaListModel modelList; for(int i=0;i<5;i++) { ParaModel model; model.value = "value:"+QString::number(i); model.nodeName = "nodeName:"+QString::number(i); model.nodeType = "nodeType:"+QString::number(i); model.tableName = "tableName:"+QString::number(i); model.fieldName = "fieldName:"+QString::number(i); model.rectRadius = 40; modelList.addModel(model); } m_widget->rootContext()->setContextProperty("ParaListModel",&modelList); //測試實時更新qml中的值 ParaModel model; model.value = "new"; model.nodeName = "new"; model.rectRadius = 10; modelList.update(4,model);
六、C++修改值QML自動更新
1、數據類
data.h
#ifndef DATA_H #define DATA_H #include <QObject> class Data : public QObject { Q_OBJECT Q_PROPERTY(QString count READ count WRITE setCount NOTIFY countChanged) public: Data(QObject *parent = nullptr); Data(const QString& count,QObject* parent = nullptr); QString count() const; void setCount(const QString& count); signals: void countChanged(); public slots: private: QString m_count = "0"; }; #endif // DATA_H
data.cpp
#include "data.h" Data::Data(QObject *parent) : QObject(parent) { } Data::Data(const QString &count, QObject *parent) : m_count(count), QObject(parent) { } QString Data::count() const { return m_count; } void Data::setCount(const QString &count) { if(m_count != count) { m_count = count; emit countChanged(); } }
2、在mainwindow里拖一個quickwidget,然后裝載qml文件,
核心代碼
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "data.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); private: Ui::MainWindow *ui; Data data; volatile int __count = 0; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QQuickWidget> #include <QQmlContext> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QUrl source("qrc:/qml/qml/Test.qml"); ui->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView ); ui->quickWidget->setSource(source); ui->quickWidget->setClearColor(QColor(Qt::transparent)); data.setCount("0"); ui->quickWidget->rootContext()->setContextProperty("Data",&data); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { __count++; data.setCount(QString::number(__count)); } void MainWindow::on_pushButton_2_clicked() { __count--; data.setCount(QString::number(__count)); }
界面:
3、qml
import QtQuick 2.7 Item { Text { id: txt; color: "red"; text: Data.count; anchors.centerIn: parent; font.pixelSize: 30; } }
作用就是在qml顯示一個數字,點擊+就加1,點擊-就減1
效果:
ps:
1、程序運行會打印xx沒有被定義,這是正常的現象,這個Data就是setContextProperty的參數
2、注意如果想要實現動態綁定,就必須要繼承QObject,並且讓屬性被Q_PROPERTY標記【實現其讀寫、變化函數】,
所以定義一個int、QString等類型,qml是無法與其進行動態綁定的,因為int和QString都沒有實現這個操作。
3、在qml里獲取C++的變量,就會對應調用C++的獲取xxx函數;在qml里設置這個變量,就會對應調用C++里的setXXX函數