版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/r5014/article/details/71159279
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();
得到界面如图:
现在点击Header或者是Footer可以看到std out 输出内容:
点击单个条目可以看到如下的输出内容:
至此,我们的QML界面与Qt/c++ 代码进行的数据交互就结束了。
原理:
QML中能处理JS的数据类型,Qt中也能处理JS的数据类型(QJSValue & QJSEngine)
当然,除了这种方式还有其他方式。欢迎交流!