首页 > 快讯 >

每日观点:将 C++ 类型的属性暴露给 QML

2023-06-28 16:48:10 来源:QT教程

可以使用 C++ 代码中定义的功能轻松扩展 QML。由于 QML 引擎与 Qt 元对象系统的紧密集成,QObject 派生类公开的任何功能都可以从 QML 代码访问。这使得 C++ 数据和函数可以直接从 QML 访问,通常几乎不需要修改。

QML 引擎能够通过元对象系统反射 QObject 实例。这意味着任何 QML 代码都可以访问 QObject 派生类的实例的以下成员:


(资料图)

属性 方法(前提是它们是 public slots 或用 Q_INVOKABLE 标记) 信号

(此外,如果枚举是用 Q_ENUMS 声明的,则也可以访问)

任何从 C++ 传输到 QML 的数据,无论是作为属性值、方法参数或返回值,还是信号参数值,都必须是 QML 引擎支持的类型。

默认情况下,引擎支持许多 Qt C++ 类型,并且可以在从 QML 使用时自动适当地转换它们。

、暴露属性

可以使用 Q_PROPERTY() 宏为任何 QObject 派生类指定属性。

例如,下面是一个具有作者属性的 Message 类。 正如 Q_PROPERTY 宏调用所指定的,这个属性可以通过 author() 方法读取,通过 setAuthor() 方法写入:

注意:不要使用 typedef 或 using 指定 Q_PROPERTY 类型,因为它们会混淆 moc。 这可能会使某些类型比较失败。

错误用法:

using FooEnum = Foo::Enum;class Bar : public QObject{Q_OBJECTQ_PROPERTY(FooEnum enum READ enum WRITE setEnum NOTIFY enumChanged)};

正确用法:

class Bar : public QObject{Q_OBJECTQ_PROPERTY(Foo::Enum enum READ enum WRITE setEnum NOTIFY enumChanged)};

暴露属性实例:

class Message : public QObject{Q_OBJECTQ_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)public:void setAuthor(const QString &a){if (a != m_author){m_author = a;emit authorChanged();}}QString author() const{return m_author;}signals:void authorChanged();private:QString m_author;};

如果在从 C++ 加载名为 的文件时将此类的实例设置为上下文属性:

int main(int argc, char *argv[]){QGuiApplication app(argc, argv);QQuickView view;Message msg;()->rootContext()->setContextProperty("msg", &msg);(QUrl::fromLocalFile(""));();return ();}

然后,可以从 中读取 author 属性:

//  QtQuick {width: 100; height: 100text:  // 调用 Message::author() 来获取这个值:{ = "Jonah" // 调用 Message::setAuthor()}}

为了实现C++与 QML 的最大互操作性,任何可写的属性都应该有一个关联的 NOTIFY 信号,该信号在属性值更改时发出。这允许属性与属性绑定一起使用,这是 QML 的一个基本特性,它通过在任何依赖项的值发生变化时自动更新属性来强制执行属性之间的关系。即发出信号会通知 QML 引擎更新任何涉及属性的绑定。

【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】

点击这里:

上面示例中如果 author 属性可写但没有关联的 NOTIFY 信号,则文本值将使用 Message::author() 返回的初始值进行初始化,但不会随此属性的任何后续更改而更新。此外,任何从 QML 绑定到属性的尝试都会从引擎产生运行时警告。

建议将 NOTIFY 信号命名为 Changed,其中 是属性的名称。QML 引擎生成的关联属性更改信号处理程序将始终采用 onChanged 形式,无论相关 C++ 信号的名称如何,因此建议信号名称遵循此约定以避免任何混淆。

、使用通知信号的注意事项

开发人员应确保仅在属性值实际更改时才发出属性更改信号。此外,如果一个属性或一组属性不经常使用,则允许对多个属性使用相同的 NOTIFY 信号。这应该小心完成以确保性能不会受到影响。

NOTIFY 信号的存在确实会产生很小的开销。在某些情况下,属性的值是在对象构造时设置的,随后不会更改。在这些情况下,可以将 CONSTANT 属性而不是 NOTIFY 信号添加到属性声明中。

CONSTANT 属性应仅用于其值仅在类构造函数中设置和最终确定的属性。

Qt属性系统。

、具有对象类型的属性

对象类型属性可从 QML 访问,前提是对象类型已正确注册到 QML 类型系统。

例如,Message 类型可能具有 MessageBody* 类型的 body 属性:

class Message : public QObject{Q_OBJECTQ_PROPERTY(MessageBody* body READ body WRITE setBody NOTIFY bodyChanged)public:MessageBody* body() const;void setBody(MessageBody* body);};class MessageBody : public QObject{Q_OBJECTQ_PROPERTY(QString text READ text WRITE text NOTIFY textChanged)// ...}假设 Message 类型已在 QML 类型系统中注册,允许将其用作 QML 代码中的对象类型:Message{// ...}

如果 MessageBody 类型也注册到类型系统,则可以将 MessageBody 分配给 Message 的 body 属性:

Message{body: MessageBody{text: "Hello, world!"}}

、具有对象列表类型的属性

包含 QObject 派生类型列表的属性也可以暴露给 QML。然而,应该使用 QQmlListProperty 而不是 QList作为属性类型。 这是因为 QList 不是 QObject 派生的类型,因此无法通过 Qt 元对象系统提供必要的 QML 属性特征,例如修改列表时的信号通知。

例如,下面的 MessageBoard 类有一个 QQmlListProperty 类型的消息属性,用于存储 Message 实例列表:

class MessageBoard : public QObject{Q_OBJECTQ_PROPERTY(QQmlListPropertymessages READ messages)public:QQmlListPropertymessages(){return QQmlListProperty(this, 0, &MessageBoard::append_message);}private:static void append_message(QQmlListProperty*list, Message *msg){MessageBoard *msgBoard = qobject_cast(list->object);if (msg)msgBoard->m_(msg);}QListm_messages;};

QQmlListProperty 的模板类类型(在本例中为 Message)必须在 QML 类型系统中注册。

、分组属性

任何只读的对象类型属性都可以作为分组属性从 QML 代码访问。这可用于公开一组相关属性,这些属性描述了类型的一组属性。

例如,假设 Message::author 属性的类型是 MessageAuthor 而不是简单的字符串,具有 name 和 email 的子属性:

class MessageAuthor : public QObject{Q_PROPERTY(QString name READ name WRITE setName)Q_PROPERTY(QString email READ email WRITE setEmail)public:...};class Message : public QObject{Q_OBJECTQ_PROPERTY(MessageAuthor* author READ author)public:Message(QObject *parent): QObject(parent), m_author(new MessageAuthor(this)){}MessageAuthor *author() const{return m_author;}private:MessageAuthor *m_author;};

可以使用 QML 中的分组属性语法编写 author 属性:

Message{: "Alexandra": "alexandra@"}

分组属性是只读的,并且在构造时由父对象初始化为有效值。

分组属性的子属性可以从 QML 修改,但分组属性对象本身永远不会改变,

二、暴露方法

QObject 派生类型的任何方法都可以从 QML 代码访问,只要它满足其中一项:

用 Q_INVOKABLE() 宏标记的公共方法

作为 public slot 的方法

例如,下面的 MessageBoard 类有一个使用 Q_INVOKABLE 宏标记的 postMessage() 方法,以及一个公共槽的 refresh() 方法:

class MessageBoard : public QObject{Q_OBJECTpublic:Q_INVOKABLE bool postMessage(const QString &msg){qDebug() << "Called the C++ method with" << msg;return true;}public slots:void refresh(){qDebug() << "Called the C++ slot";}};

如果将 MessageBoard 的实例设置为文件 的上下文数据,则 可以调用两个方法,如下例所示:

int main(int argc, char *argv[]){QGuiApplication app(argc, argv);MessageBoard msgBoard;QQuickView view;()->rootContext()->setContextProperty("msgBoard", &msgBoard);(QUrl::fromLocalFile(""));();return ();}//  QtQuick {width: 100; height: 100MouseArea{: parentonClicked:{var result = ("Hello from QML")("Result of postMessage():", result)();}}}

如果 C++ 方法具有 QObject* 类型的参数,则可以使用对象 id 或引用该对象的 JavaScript 变量值从 QML 传递参数值。

QML 支持调用重载的 C++ 函数。 如果存在多个同名但参数不同的 C++ 函数,则会根据提供的参数数量和类型调用正确的函数。

当从 QML 中的 JavaScript 表达式访问时,从 C++ 方法返回的值将转换为 JavaScript 值。

三、暴露信号

QObject 派生类型的任何公共信号都可以从 QML 代码访问。

QML 引擎自动为从 QML 使用的 QObject 派生类型的任何信号创建信号处理程序。信号处理程序始终命名为 on,其中 是信号的名称,首字母大写。 信号传递的所有参数都可以通过参数名称在信号处理程序中使用。

例如,假设 MessageBoard 类有一个带有单个参数主题的 newMessagePosted() 信号:

class MessageBoard : public QObject{Q_OBJECTpublic:// ...signals:void newMessagePosted(const QString &subject);};

如果 MessageBoard 类型已注册到 QML 类型系统,则在 QML 中声明的 MessageBoard 对象可以使用名为 onNewMessagePosted 的信号处理程序接收 newMessagePosted() 信号,并检查主题参数值:

MessageBoard{onNewMessagePosted: (subject)=>("New message received:", subject)}

与属性值和方法参数一样,信号参数必须具有 QML 引擎支持的类型。(使用未注册的类型不会产生错误,但处理程序将无法访问参数值。)

请注意,QML引擎无法区分名称相同但参数不同的信号,类可能有多个同名的信号,但只有最后一个信号可以作为 QML 信号访问。

【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】

点击这里:

上一篇:

克鲁赛德战记微博怎么充钱 克鲁赛德战记微博|当前滚动

下一篇:

最后一页

x
推荐阅读

每日观点:将 C++ 类型的属性暴露给 QML

克鲁赛德战记微博怎么充钱 克鲁赛德战记微博|当前滚动

人生阶段划分图_人生阶段划分_世界资讯

热头条丨​读书看《阿斯达年代记》的参考书目

申请法院强制执行的截止时间是什么时候

农机股尾盘异动拉升 智慧农业直线涨停-天天观焦点

柯力传感6月28日快速上涨_热推荐

单位帮扶工作情况汇报(单位帮扶工作总结)

焦点简讯:蜂助手:6月27日融资买入771.59万元,融资融券余额1.01亿元

焦点滚动:北京西城·首都高校发展联盟成立 与北大、清华等开展合作新模式

环球今头条!7月郑州推出9场线下招聘会

教育部:严打暑期隐形变异类校外培训-当前热讯

环球最资讯丨国内首款农业AI对话机器人“小田”发布

每日短讯:这份“免费早餐”,他们吃上了!

目的地感染-目的地英文

一致魔芋拟2100万出售子公司 聚焦精加工业务年盈利6530万 每日快播

观察:首批房企再融资正式落地!四家地产一起公告:获批!

提升中华文明的传播效能(新论)|今日热闻

全球快看:鹏鼎控股(002938):6月27日北向资金增持106.06万股

未安装adobe reader_adobe media encoder未安装

商都论坛快乐之旅 大河论坛快乐之旅|天天快报

北流火车站还开吗_北流火车站 每日播报

凭“双胞水”走红的云南墨江:水中并未检测出特殊物质,双胞产业却已规模化

ST蓝奥免去张启寿财务负责人职务 2022年公司净利30.25万

银行承兑汇票粘单右压左_银行承兑汇票粘单打印 每日聚焦

dnf2023年套至尊装扮哪套好看 国服最贵3套高级时装-天天最资讯

每日视点!新迎顺聘任李勇为公司副总经理 2022年公司净利1496.06万

焦点热文:黑龙江高考平行志愿怎么填?

奥特维(688516.SH)2022年度每股派1.5963元 股权登记日为7月3日

灏字取名的意思是什么_灏字的含义是什么

世界观点:辽宁省新宾满族自治县发布雷雨大风蓝色预警

环球简讯:南华大学船山学院开设专业有什么 南华大学船山学院优势专业是什么

快消息!揷

每日观察!wma格式转换mp3手机版 wma转换器

骑马与砍杀三国演义x9_骑马与砍杀三国

6月27日上证50涨幅达1%

4人团伙贩卖“K粉”14公斤 主犯被判无期徒刑

【天天新要闻】联想将在MWC上海首次大规模亮相3S全栈AI能力

快播:2023中国Mini LED行业发展潜力分析

锋利棱台怎么设置

盐湖提锂板块异动拉升 西藏珠峰冲击涨停 热资讯

apple safari浏览器_apple safari

焦点短讯!复合型医学人才,不仅仅能当医生

全球观热点:A股开盘速递 | 沪指高开0.09% 包装印刷、食品饮料等板块指数涨幅居前

今日热搜:国民老公2免费观看全集电视剧第二季

即时:华北黄淮等地高温将重启,新一轮降水来袭局地警惕强对流天气

怎么打出中间长杠_中间长横线怎么用键盘打出来

年内新增专项债发行突破2万亿元,专家预计三季度将迎来发行高峰

全球观察:sweet love什么品牌_sweet love什么意思

某幻君真名 五月儿的真名