QML界面与Qt/C++代码进行数据交互
主要实现2点:
1,c++ 数据传递到QML界面使用
2,QML界面的数据传递到c++代码使用
为了方便说明,我使用QML创建了一个ListView视图,用于展示商品名字和价格(name, value)。
一开始的时候这个界面没有任何数据,截图如下:
这个视图的QML代码如下:
import QtQuick 2.5 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.4 Window { id: mainWindow width: 600 height: 300 visible: true property var myModel: "" signal printMyModel(var model) signal printItem(var item) //list view ListView { id: view anchors.fill: parent header: myHeader footer: myFooter model: myModel delegate: myDelegate } //header, 被双击的时候发送打印myModel信号 Component { id: myHeader Rectangle { implicitHeight: 25 implicitWidth: view.width color: "gray" Text { anchors.centerIn: parent text: "示例所用的ListView" color: "darkblue" } MouseArea { anchors.fill: parent onDoubleClicked: printMyModel(myModel) } } } //footer, 被双击的时候发送打印myModel信号 Component { id: myFooter Rectangle { implicitHeight: 25 implicitWidth: view.width color: "lightblue" Text { anchors.right: parent.right anchors.rightMargin: 20 anchors.verticalCenter: parent.verticalCenter text: "created by Eosin_Sky" color: "gray" } MouseArea { anchors.fill: parent onDoubleClicked: printMyModel(myModel) } } } //delegate, 被双击的时候发送打印item信号 Component { id: myDelegate Rectangle // container { id: container implicitHeight: 25 implicitWidth: view.width color: index %2 == 0 ? "darkgray" : "lightblue" RowLayout //layout { anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: parent.left anchors.leftMargin: 20 anchors.right: parent.right anchors.rightMargin: 20 Rectangle //name { implicitWidth: name.width Layout.fillHeight: true color: container.color Text { id: name anchors.centerIn: parent text: modelData.name } } //spacer Rectangle { Layout.fillWidth: true Layout.fillHeight: true Layout.topMargin: 2 Layout.bottomMargin: 2 color: Qt.darker(container.color) opacity: 0.7 Text { anchors.centerIn: parent text: "点击打印该条目" } MouseArea { anchors.fill: parent onDoubleClicked: printItem(myModel[index]) } } Rectangle //value { implicitWidth: value.width implicitHeight: value.height TextField { id: value anchors.centerIn: parent height: 20 text: modelData.value validator: DoubleValidator{bottom: 0.01;top: 9999.99; decimals: 2;} style:TextFieldStyle { background:Rectangle { border.width: 1 border.color: Qt.darker(color) color: Qt.darker(container.color) } } } } Rectangle //¥ { implicitWidth: yuan.width Layout.fillHeight: true color: container.color Text { id: yuan anchors.centerIn: parent text: "¥" } } } } } } 其中mainWindow中定义的var类型的myModel就是用于给ListView提供数据的。 当点击ListView的Header和Footer
的时候会发送打印myModel的信号,这时候使用c++将数据打印出来;当点击ListView的条目的时候会发送打印item
的信号,这时候使用c++将这个条目打印出来。
现在这个ListView是空的,因为一开始myModel是空的。我们准备使用c++将数据设置给myModel。
首先我们先实现一个类(MyQmlGUI)用来控制这个mainWindow,代码如下:
#ifndef MYQMLGUI_H #define MYQMLGUI_H #include <QJSEngine> #include <QJSValue> #include <QDebug> class MyQmlGUI: public QObject { Q_OBJECT private: QObject* qmlRoot; public: MyQmlGUI(QObject* root):qmlRoot(root) { connect(qmlRoot, SIGNAL(printMyModel(QVariant)), this, SLOT(printModel(QVariant))); connect(qmlRoot, SIGNAL(printItem(QVariant)), this, SLOT(printItem(QVariant))); } public slots: void initModel() { /** create 3 items for list view (name - value) **/ int rowCount = 3; QJSEngine JS; QJSValue array = JS.newArray(rowCount); for(int i = 0; i < 3; i++) { QJSValue item = JS.newObject(); item.setProperty("name", "goods " + QString::number(i)); item.setProperty("value", i * 3); array.setProperty(i, item); } /** update model to qml object **/ qmlRoot->setProperty("myModel", array.toVariant()); } void printModel(QVariant model) { qDebug() << "print model:"; /** this model is an Array **/ QJSValue array = model.value<QJSValue>(); int rowCount = array.property("length").toInt(); for(int i = 0; i < rowCount; i++) { QString name = array.property(i).property("name").toString(); QString value = array.property(i).property("value").toString(); qDebug() << "row at " << i << ":" << "name=" << name << ", value=" << value; } } void printItem(QVariant item) { /** this item is a js object **/ QJSValue obj = item.value<QJSValue>(); QString name = obj.property("name").toString(); QString value = obj.property("value").toString(); qDebug() << "print item:" << "name=" << name << ", value=" << value; } }; #endif // MYQMLGUI_H 这个类在实例化的时候会将传入的mainWindow对象进行信号绑定,printModel槽会绑定mainWindow
的printMyModel信号;printItem槽会绑定mainWindow的printItem信号。
然后这个类实现了一个InitModel的方法,当被调用的时候会生成ListView所需要的Model并设置到mainWindow
中的myModel中去。
我们来启动一下:
QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(QUrl::fromLocalFile("D:/QtProject/DataExchange/main.qml")); if(!component.isReady()) return -1; QQuickWindow* mainWindow = qobject_cast<QQuickWindow*>(component.create()); if(mainWindow == NULL){ return -2; } mainWindow->show(); MyQmlGUI gui(mainWindow); gui.initModel();
当mainWindow显示的 时候初始化gui并调用gui的initModel。
得到界面如图:
现在点击Header或者是Footer可以看到std out 输出内容:
点击单个条目可以看到如下的输出内容:
至此,我们的QML界面与Qt/c++ 代码进行的数据交互就结束了。
原理:
QML中能处理JS的数据类型,Qt中也能处理JS的数据类型(QJSValue & QJSEngine)
当然,除了这种方式还有其他方式。欢迎交流!