一.使用rootobject例程
1.运行
2.main.cpp
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
#include <qqmlcomponent>
#include <qdebug>
int main(int argc, char *argv[]) {
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty()) {
qdebug() << "no root objects found.";
return -1;
}
qobject *rootobject = engine.rootobjects().first();
qobject *rectangle = rootobject->findchild<qobject*>("myrectangle", qt::findchildrenrecursively);
if (rectangle) {
// 修改属性
rectangle->setproperty("width", 200);
// 调用方法
qvariant newcolor = "blue";
qmetaobject::invokemethod(rectangle, "changecolor", q_arg(qvariant, newcolor));
} else {
qdebug() << "rectangle object not found.";
return -1;
}
return app.exec();
}
3.main.qml
import qtquick 2.0
import qtquick.controls 2.5
applicationwindow {
visible: true
width: 640
height: 480
title: "hello world"
rectangle {
id: myrectangle
objectname: "myrectangle" // 添加 objectname
width: 100
height: 100
color: "red"
function changecolor(newcolor) {
console.log("changing color to: " + newcolor)
color = newcolor;
}
}
}
3.用于debug的加长版main.cpp
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
#include <qqmlcomponent>
#include <qdebug>
void printobjecttree(qobject *object, int level = 0) {
if (!object) return;
qstring indent(level * 2, ' ');
qdebug() << indent << object->objectname() << "(" << object->metaobject()->classname() << ")";
const qobjectlist children = object->children();
for (qobject *child : children) {
printobjecttree(child, level + 1);
}
}
int main(int argc, char *argv[]) {
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty()) {
qdebug() << "no root objects found.";
return -1;
}
qobject *rootobject = engine.rootobjects().first();
if (!rootobject) {
qdebug() << "root object not found.";
return -1;
}
qdebug() << "root object found. printing object tree:";
printobjecttree(rootobject);
qobject *rectangle = rootobject->findchild<qobject*>("myrectangle", qt::findchildrenrecursively);
if (!rectangle) {
qdebug() << "rectangle object not found.";
return -1;
} else {
qdebug() << "rectangle object found.";
}
// 修改属性
if (rectangle->setproperty("width", 200)) {
qdebug() << "width changed successfully.";
} else {
qdebug() << "failed to change width.";
}
// 调用方法
qvariant newcolor = "blue";
if (qmetaobject::invokemethod(rectangle, "changecolor", q_arg(qvariant, newcolor))) {
qdebug() << "changecolor method called successfully.";
} else {
qdebug() << "failed to call changecolor method.";
}
return app.exec();
}
运行打印
root object found. printing object tree:
"" "" ( applicationwindow_qmltype_0 )
" " "" ( qquickrootitem )
" " "" ( qquickoverlay )
" " "" ( qqmlcomponent )
" " "" ( qqmlcomponent )
" " "applicationwindow" ( qquickcontentitem )
" " "myrectangle" ( qquickrectangle_qml_3 )
rectangle object found.
width changed successfully.
qml: changing color to: blue
changecolor method called successfully.
二.qml文件的根对象详解
在 qml(qt meta language)中,qml 文件的根对象是整个用户界面组件的基础。根对象定义了该文件中所有子对象的上下文和作用域。通常,根对象是一个 ui 组件,比如 rectangle
、item
、applicationwindow
等,以下是对 qml 文件根对象的详解:
基本概念
-
唯一性:
- 每个 qml 文件必须且只能有一个根对象。这是 qml 文件的入口点,所有其他元素都必须嵌套在这个根对象之内。
-
类型选择:
- 根对象可以是任何 qml 类型,但通常会选择合适的 ui 组件,根据需要创建不同类型的根对象。例如,可以使用
rectangle
创建一个矩形区域,或者使用applicationwindow
创建一个完整的应用窗口。
- 根对象可以是任何 qml 类型,但通常会选择合适的 ui 组件,根据需要创建不同类型的根对象。例如,可以使用
-
作用域:
- 根对象定义了一个新的作用域,文件内的所有子对象都在这个作用域内。这意味着根对象的属性和方法可以被子对象访问和修改。
常见根对象类型
rectangle
rectangle {
width: 200
height: 200
color: "lightblue"
text {
text: "hello, qml!"
anchors.centerin: parent
}
}
rectangle
是一个常见的根对象类型,用于定义一个矩形区域。
applicationwindow
import qtquick 2.15
import qtquick.controls 2.15
applicationwindow {
visible: true
width: 640
height: 480
title: "qml application"
button {
text: "click me"
anchors.centerin: parent
}
}
applicationwindow
用于创建一个完整的应用窗口,通常用于更复杂的应用程序。
属性和方法
根对象可以包含属性和方法,这些属性和方法可以在子对象中访问。例如:
rectangle {
id: root
width: 300
height: 300
color: "lightgreen"
function changecolor(newcolor) {
root.color = newcolor
}
mousearea {
anchors.fill: parent
onclicked: root.changecolor("lightcoral")
}
}
作用域和继承
根对象中的属性和方法可以被子对象继承和使用。例如:
rectangle {
id: root
width: 400
height: 400
color: "lightyellow"
property string message: "hello from root"
text {
text: root.message
anchors.centerin: parent
}
}
三.使用rootobject
通过qobject
的setproperty
方法,可以设置qml对象的属性
。rootobjects
和 qmetaobject::invokemethod
的结合使用调用qml中的方法
3.1.运行
3.2.main.cpp
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
#include <qquickitem>
#include <qmetaobject>
int main(int argc, char *argv[])
{
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty())
return -1;
qobject *rootobject = engine.rootobjects().first();
qobject *rectangle = rootobject->findchild<qobject*>("myrectangle");
if (rectangle) {
qdebug() << "rectangle found!";
rectangle->setproperty("width", 300);
rectangle->setproperty("color", "red");
qmetaobject::invokemethod(rectangle, "changecolor", q_arg(qvariant, "green"));
} else {
qdebug() << "rectangle not found!";
}
return app.exec();
}
3.3.main.qml
import qtquick 2.0
import qtquick.controls 2.5
applicationwindow {
visible: true
width: 640
height: 480
rectangle {
id: myrectangle
objectname: "myrectangle" // 添加 objectname
width: 200
height: 200
color: "blue"
function changecolor(newcolor) {
color = newcolor;
}
}
}
四.理解rootobjects
和qmetaobject::invokemethod
的结合使用
rootobjects
和 qmetaobject::invokemethod
可以结合使用,特别是在需要从 c++ 调用 qml 中的方法时。让我们详细解释一下这个过程,并澄清为什么 qmetaobject::invokemethod
不能单独用于调用 qml 中的方法。
理解 rootobjects
和 qmetaobject::invokemethod
的结合使用
-
获取 qml 根对象:
- 使用
rootobjects
获取 qml 加载后的根对象。这一步是必要的,因为需要一个具体的 qml 对象实例来调用其方法。
- 使用
-
使用
qmetaobject::invokemethod
调用 qml 方法:- 一旦有了 qml 的根对象(或任何需要调用方法的对象),可以使用
qmetaobject::invokemethod
动态调用其方法。
- 一旦有了 qml 的根对象(或任何需要调用方法的对象),可以使用
详细示例
假设有一个简单的 qml 文件 main.qml
,其中定义了一个方法 myqmlmethod
:
import qtquick 2.0
rectangle {
width: 200
height: 200
function myqmlmethod() {
console.log("myqmlmethod called")
}
}
在 c++ 中,可以按以下步骤调用这个方法:
1. 加载 qml 文件并获取根对象
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qobject>
#include <qmetaobject>
int main(int argc, char *argv[])
{
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty())
return -1;
qobject *rootobject = engine.rootobjects().first();
// now use qmetaobject::invokemethod to call the qml method
qmetaobject::invokemethod(rootobject, "myqmlmethod");
return app.exec();
}
2. 动态调用 qml 方法
// assuming rootobject is already obtained as shown above
qmetaobject::invokemethod(rootobject, "myqmlmethod");
为什么 qmetaobject::invokemethod
不能单独使用?
qmetaobject::invokemethod
需要一个具体的对象实例以及方法名称来调用方法。它不直接与 qml 交互,而是用于调用任何 qobject
派生类的实例方法。因此,必须首先通过 rootobjects
获取 qml 加载后的对象实例,然后才能使用 qmetaobject::invokemethod
调用该对象的方法。
总结
rootobjects
: 用于获取 qml 加载后的根对象。qmetaobject::invokemethod
: 用于动态调用qobject
实例的方法。
这两者结合使用时,首先通过 rootobjects
获取 qml 对象实例,然后使用 qmetaobject::invokemethod
调用该对象的方法。这样可以在 c++ 代码中灵活地调用 qml 中定义的方法。
五.rootobjects
是一个qobject列表
,包含了通过该引擎加载的qml文档的根对象
属性/方法 | 描述 |
---|---|
rootobjects | 返回一个包含所有通过该引擎加载的 qml 根对象的列表。 |
append() | 添加一个对象到 rootobjects 列表。 |
at(int index) | 返回 rootobjects 列表中指定索引处的对象。 |
clear() | 清空 rootobjects 列表。 |
contains(qobject* obj) | 检查 rootobjects 列表是否包含指定的对象。 |
indexof(qobject* obj) | 返回指定对象在 rootobjects 列表中的索引,如果不包含返回 -1。 |
removeat(int index) | 移除 rootobjects 列表中指定索引处的对象。 |
size() | 返回 rootobjects 列表的大小。 |
first() | 返回 rootobjects 列表中的第一个对象。 |
last() | 返回 rootobjects 列表中的最后一个对象。 |
作用
- 访问根对象: 可以方便地访问通过 qml 加载的主界面对象,通常用于设置属性或调用方法。
- 对象管理: 允许在运行时动态地管理 qml 根对象,例如添加、移除或替换根对象。
- 调试和测试: 在调试和测试过程中,可以通过
rootobjects
访问和操作 qml 对象树进行检查和验证。
示例代码
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
#include <qdebug>
int main(int argc, char *argv[])
{
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty())
return -1;
// 获取第一个根对象
qobject *rootobject = engine.rootobjects().first();
qdebug() << "root object:" << rootobject;
return app.exec();
}
在这个示例中,engine.rootobjects().first()
获取并打印了加载的 qml 文档的根对象。
六.为什么findchild<qobject*>(“myrectangle”) 不起作用:id
vs objectname
在 qt 中,findchild
方法用于查找对象树中的子对象。默认情况下,它只会查找直接的子对象,而不会递归地查找整个对象树。此外,findchild
方法通常依赖于对象的 objectname
属性,而不是 id
属性。
id
vs. objectname
id
:在 qml 中,id
是一个局部标识符,用于在 qml 文件中引用对象。它在 c++ 层不可见。objectname
:这是一个标准的 qt 属性,可用于在 c++ 和 qml 层之间进行对象查找和引用。
为什么 findchild<qobject*>("myrectangle")
不起作用
提到的代码:
qobject *rectangle = rootobject->findchild<qobject*>("myrectangle");
如果没有设置 objectname
,这个方法不会成功,因为它只查找对象的 objectname
属性,而不是 id
。
为什么 objectname
有效
当将 objectname
设置为 "myrectangle"
时,findchild
方法可以成功找到对象:
rectangle {
id: myrectangle
objectname: "myrectangle" // 添加 objectname
...
}
在 c++ 中:
qobject *rectangle = rootobject->findchild<qobject*>("myrectangle", qt::findchildrenrecursively);
使用 qt::findchildrenrecursively
标志可以确保在对象树中递归查找。
如何仅使用 findchild<qobject*>("myrectangle")
如果希望不使用递归查找,且对象位于 rootobject
的直接子对象中,需要确保对象的 objectname
已正确设置,并且对象确实是 rootobject
的直接子对象。
示例
qml 文件:main.qml
import qtquick 2.0
import qtquick.controls 2.5
applicationwindow {
visible: true
width: 640
height: 480
rectangle {
id: myrectangle
objectname: "myrectangle" // 添加 objectname
width: 200
height: 200
color: "blue"
function changecolor(newcolor) {
color = newcolor;
}
}
}
c++ 文件:main.cpp
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
#include <qquickitem>
#include <qmetaobject>
int main(int argc, char *argv[])
{
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty())
return -1;
qobject *rootobject = engine.rootobjects().first();
qobject *rectangle = rootobject->findchild<qobject*>("myrectangle");
if (rectangle) {
qdebug() << "rectangle found!";
rectangle->setproperty("width", 300);
rectangle->setproperty("color", "red");
qmetaobject::invokemethod(rectangle, "changecolor", q_arg(qvariant, "green"));
} else {
qdebug() << "rectangle not found!";
}
return app.exec();
}
总结
为了在 c++ 代码中成功找到 qml 对象,需要确保以下几点:
- 在 qml 中设置对象的
objectname
属性。 - 使用
findchild
方法进行对象查找时,查找的是objectname
,而不是id
。 - 如果对象不是直接子对象,使用
qt::findchildrenrecursively
标志进行递归查找。
这样做可以确保能够在 c++ 代码中准确查找到所需的 qml 对象。
发表评论