设为首页 加入收藏

TOP

QML与C++数据绑定教程(一)
2018-03-22 08:49:22 】 浏览:542
Tags:QML 数据 绑定 教程

QML与C++数据绑定教程

参照 View-Model 模型,QML作为 View,C++中的对象作为 Model,实现业务逻辑和界面的分离。

暴露单个C++类的属性

通过这种方法,QML中可以直接访问注册到上下文中的C++类实例,并且是注册到QML的全局(具体是注册到一个 QQuickView 或者 engine)。以自定义一个 Name 类,类包括一个 data 属性为例。

类定义

需要暴露给QML访问的类需要有特殊的定义:

/*name.h*/
#include 
  
   

class Name : public QObject //继承自QObject
{
    Q_OBJECT//QObject宏
    Q_PROPERTY(QString data READ data WRITE setData NOTIFY dataChanged)
public:
    Name(QObject *parent = nullptr);//默认构造函数
    Name(QString _name);//构造函数

    QString data() const;//READ 接口
    void setData(const QString& _data);//WRITE 接口

signals:
    QString dataChanged();//NOTIFY 信号(不需实现)

private:
    QString m_data;//私有属性
};

  

可以通过右键项目->新建文件->C++ Class 来添加新类,继承自 QObject 并且自动添加文件到项目中。

Warning:不要在 cpp 文件中直接定义类,因为 Q_OBJECT 宏需要经过 moc 处理,非.h文件不会被 moc 处理,编译时出现“无法识别的符号”错误

Q_PROPERTY(QString data READ data WRITE setData NOTIFY dataChanged)

这一行代码定义了暴露给QML访问的接口,这里我们提供的对象是一个 QString,READ 接口是一个名为 data 的函数, WRITE 接口是一个名为 setData 的函数,NOTIFY 接口用于通知的绑定,只有设置了 NOTIFY 接口,QML 才能自动与 C++ 中的属性同步。这里的命名方式最好与默认的统一。

类实现

/*name.cpp*/
#include "name.h"

Name::Name(QObject *parent) : QObject(parent)
{//默认构造函数
}

Name::Name(QString _data) : m_data(_data)
{//自定义构造函数,初始化私有对象m_data
}

QString Name::data() const
{
    return m_data;//READ 接口实现,返回私有对象
}

void Name::setData(const QString& _data)
{
    if(_data != m_data){//WRITE 接口实现,更新m_data并发出信号
        m_data = _data;
        emit dataChanged();
    }
}

在 setData 中,必须判断数据是否更新,只有当数据真正改变时才发出信号,否则有无限递归的风险。

注册到上下文

然后是实例化一个 Name 类并注册到上下文。注册需要在读取.qml文件之前完成。

/*main.cpp*/
Name a_name("test");

QQmlApplicationEngine engine;
QQmlContext* rootContex = engine.rootContext();//拿到engine的根上下文
rootContex->setContextProperty("name",  QVariant::fromValue(a_name));//注册
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

在 QML 中读取

QML 中可以读取到接口返回的属性,直接给属性赋值,并且监听到属性变化。

/*main.qml*/
Rectangle {
    Text {
        text:name.data //相当于调用name.data()这个接口

        Connections {//建立一个到NOTIFY接口的连接
            target: name
            onDataChanged:{//对应NOTIFY接口
                console.log("data has beed changed!");
            }
        }
    }

    Button {
        text:"changeData"
        onClicked: {
            name.data = "hasChanged!";
        }
    }
}

当点击按钮时,Text 的文字会发生变化,同时控制台输出 “data has beed changed!”,闭环达成。

Connections 用来监听事件,监听的 target 是定义了 NOTIFY 的对象(注意 onDataChanged 这个 event handler 的驼峰命名法和原 NOTIFY 定义时的命名。

使用 QList 作为 Model

更常见的需求是,暴露一组对象的属性,并通过 QML 中的 View 来自动渲染。例如我们把 Name 类放进一个 QList 列表,作为 Model 传给 QML 中的 ListView。

/*main.cpp*/
QList
  
    NameList;
NameList.append(new Name("name1"));
NameList.append(new Name("name2"));//增加两个Name对象在数组中

QQmlApplicationEngine engine;
QQmlContext* rootContex = engine.rootContext();//拿到engine的根上下文
rootContex->setContextProperty("nameList",  QVariant::fromValue(NameList));//注册
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

  
/*main.qml*/
ListView{
    width: parent.width
    height: 300
    model: nameList
    delegate: Rectangle {
        height: 30
        width: parent.width
        color: "#000000"
        Text {
            text: model.data //调用每个对象的data()方法
            color: "#FFFFFF"
            Connections{
                target: model //监听这个对象
                onDataChanged:{
                    console.log("changed
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇唯一的雪花(Unique snowflakes,U.. 下一篇C++怎么定义未知元素个数的数组?

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目