关于获取可用QML类型列表的技术咨询(含导入类型与本地声明组件)
嘿,我完全理解你的需求:既要拿到通过import引入的非限定命名空间里的QML类型(比如QtQuick自带的Item、Rectangle),又要获取当前文档里自己声明的自定义组件(比如你例子里的Royalty_Button),而且希望得到两个对应列表——一个是类型名称列表,另一个是对应的类型格式标识,方便后续区分使用。
先聊聊你当前的实现思路,这个通过default property Component peer逐个捕获组件、再创建临时对象解析类型名称的方法,确实是个很巧妙的workaround!毕竟直接获取list<Component>的默认属性存在限制,你用逐个接收再存入列表的方式完美绕开了这个问题。不过这里有几个可以优化或者需要注意的点:
你当前的核心实现代码是这样的:
OtObject{ default property Component peer onPeerChanged: delegate.push(peer) property list<Component> delegate /* 利用default property特性绕开直接获取list<Component>的限制——逐个接收Component并存入列表 */ onDelegateChanged: { if(complete) { // ... 你的其他业务逻辑 let object = Qt.createObject(parent, delegate[index], establishment) let component_detector = name(object) Qt.destroy(object) // ... 你的其他业务逻辑 } } function name(object) { let name = object.toString() let typename = name.substring(0, name.length -15 - object["objectName"].length - (object["objectName"].length>0)*4 ) let liter_position = typename.indexOf("_QML") if( liter_position !== -1 ) { typename = typename.substring(0, liter_position ) } return typename } }
现有方案的优化点
类型解析的稳定性:你通过
object.toString()截取字符串的方式依赖Qt内部的对象字符串格式,不同Qt版本可能会有格式变化,存在兼容性风险。可以改用元对象API来获取更可靠的类型信息:function name(object) { let metaObj = object.metaObject; let className = metaObj.className(); // 截取掉_QMLTYPE_开头的后缀 let qmlSuffixIdx = className.indexOf("_QMLTYPE_"); if (qmlSuffixIdx !== -1) { className = className.substring(0, qmlSuffixIdx); } return className; }这种方式基于Qt元对象系统,比字符串截取更稳定。
性能开销:每次创建临时对象再销毁,如果你的组件初始化逻辑比较重,可能会带来不必要的性能损耗。如果只是为了获取类型信息,可以考虑提前在组件声明时绑定类型标识,避免临时对象的创建。
分场景实现你的需求
一、获取通过Import引入的全局QML类型
纯QML层面没有直接枚举所有导入类型的API,但可以通过两种方式实现:
- 预定义内置类型列表:提前维护一份对应Qt版本的内置类型白名单(比如Item、Rectangle、MouseArea等),这种方式简单但不够灵活,无法覆盖自定义导入的第三方模块。
- 结合C++辅助:如果项目允许混合C++开发,可以通过
QQmlEngine的typeLoader()接口枚举所有已注册的QML类型,再导出到QML中使用,这种方式能覆盖所有导入的类型,是最全面的方案。
二、获取当前文档内的自定义组件
你当前的默认属性捕获方案是纯QML环境下最可行的方式,结合优化后的类型解析逻辑,就能生成你想要的两个列表:
- 第一个列表:存储所有捕获到的类型名称(内置类型+自定义组件)
- 第二个列表:存储对应的类型类别(比如内置类型用自身名称,自定义组件标记为
Component)
比如你期望的输出格式:
[Item, Rectangle, MouseArea, Royalty_Button][Item, Rectangle, MouseArea, Component]
可以通过添加类型判断逻辑实现:
// 内置类型白名单,可根据Qt版本扩展 const builtinTypes = ["Item", "Rectangle", "MouseArea", "Text", "Image"]; function getTypeCategory(object) { let typeName = name(object); return builtinTypes.includes(typeName) ? typeName : "Component"; }
在onDelegateChanged逻辑里,把类型名称和类别分别存入对应的列表即可。
总的来说,你当前的方案在纯QML环境下已经非常实用,优化类型解析逻辑后会更稳定可靠;如果需要更全面的全局类型枚举,结合C++辅助会是最佳选择。
内容来源于stack exchange

