从 C++ 对象动态创建 qml 对象(通过使用 setContextProperty)
Create qml object dynamically from c++ object (by using setContextProperty)
我正在尝试使用 c++ class 的对象在 c++ 中动态创建一个 qml 对象。下面是我的方法的最小代码。执行此代码并单击后,应用程序崩溃(请参阅 main.qml 中的评论)。
我已经把下面的代码贴出来了,可以下载了here。
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "scene.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
scene sc(engine);
QQmlContext* context = engine.rootContext();
context->setContextProperty("sc", &sc);
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
scene.h
#ifndef SCENE_H
#define SCENE_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
class scene : public QObject
{
Q_OBJECT
public:
explicit scene(QQmlApplicationEngine& engine, QObject *parent = nullptr);
QQmlApplicationEngine& engine;
public slots:
void create_rect_object();
};
#endif // SCENE_H
scene.cpp
#include "scene.h"
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
{
}
void scene::create_rect_object()
{
QQmlComponent component(&engine, QUrl::fromLocalFile("myrect.qml"));
QObject *object = component.create();
object->setProperty("width", 200);
object->setProperty("height", 150);
object->setProperty("color", "blue");
}
main.qml
import QtQuick 2.11
import QtQuick.Window 2.11
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
anchors.fill: parent
color: "red"
MouseArea{
anchors.fill: parent
onClicked: {
console.log("Before click");
sc.create_rect_object(); // application is crashing here
console.log("after click");
}
}
}
}
myrect.qml
import QtQuick 2.0
Rectangle {
id:id_rec
width: 100
height: 100
color: "green"
x:0
y:0
}
更新
要创建的对象不是 main window 的根的子对象,而是 mainwindow 的子项链中的一项的子项。伪结构如下所示。
main.qml
Window {
customitem1{
id:id_ci1
}
customitem2{
id:id_ci1
}
}
customitem1.qml
Item {
customitem3{
id:id_ci3
}
customitem3{
id:id_ci4
}
}
[已更新]
您有两个崩溃错误和一个不显示矩形的错误
1.Your scene
的 构造函数成员初始化列表 是假的,导致应用程序崩溃
(提示:为 class 的成员使用不同的命名方式,方法是在他们前面加上 m_
前缀,例如:m_engine
for 可读性并且不会混淆)
//Correct WAY
class Something
{
private:
int m_value1;
double m_value2;
char m_value3;
public:
//################# YOUR CASE ###############################
Something(int number) : m_value1(number), m_value2(2.2), m_value3('c') // directly initialize our member variables
{
// No need for assignment here
}
//#############################################################
Something() : m_value1(1), m_value2(2.2), m_value3('c') // directly initialize our member variables
{
// No need for assignment here
}
void print()
{
std::cout << "Something(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
}
}
应该是这样的:
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(engine),QObject(parent)
而不是
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
2.The url
of myrect.qml
你从本地文件中得到的 在 运行时 导致应用程序崩溃,补救措施之一是从您的 qrc
文件
加载它
QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));
3.And 你会注意到点击后你没有矩形,这是因为创建的矩形没有父级并且通过更改你的 create_rect_object()
(在这个例子中父级是不可见的我们的根 window contentItem
) 你会得到一些矩形 :)
//A QQuickWindow always has a single invisible root item containing all of its content.
//To add items to this window, reparent the items to the contentItem or to an existing item in the scene.
//http://doc.qt.io/qt-5/qquickwindow.html#contentItem-prop
void scene::create_rect_object()
{
QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));
QObject *object = component.create();
QQuickItem *item = qobject_cast<QQuickItem*>(object);
// Set the parent of our created qml rect
item->setParentItem((QQuickItem*)((QQuickWindow *) engine.rootObjects()[0])->contentItem());
//Set some random position and color
item->setProperty("color", QColor::fromRgb(QRandomGenerator::global()->generate()));
item->setX(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
item->setY(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
}
从 C++ 中查找 QML 对象
要查找对象并将其用作 parentItem
,您必须设置 qml 对象的 objectName
Rectangle {
...
objectName : "rect_1"
...
}
在 C++ 中
QObject* obj = dynamic_cast<QObject*>(engine.rootObjects()[0]).findChild("rect_1");
我正在尝试使用 c++ class 的对象在 c++ 中动态创建一个 qml 对象。下面是我的方法的最小代码。执行此代码并单击后,应用程序崩溃(请参阅 main.qml 中的评论)。
我已经把下面的代码贴出来了,可以下载了here。
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "scene.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
scene sc(engine);
QQmlContext* context = engine.rootContext();
context->setContextProperty("sc", &sc);
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
scene.h
#ifndef SCENE_H
#define SCENE_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
class scene : public QObject
{
Q_OBJECT
public:
explicit scene(QQmlApplicationEngine& engine, QObject *parent = nullptr);
QQmlApplicationEngine& engine;
public slots:
void create_rect_object();
};
#endif // SCENE_H
scene.cpp
#include "scene.h"
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
{
}
void scene::create_rect_object()
{
QQmlComponent component(&engine, QUrl::fromLocalFile("myrect.qml"));
QObject *object = component.create();
object->setProperty("width", 200);
object->setProperty("height", 150);
object->setProperty("color", "blue");
}
main.qml
import QtQuick 2.11
import QtQuick.Window 2.11
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
anchors.fill: parent
color: "red"
MouseArea{
anchors.fill: parent
onClicked: {
console.log("Before click");
sc.create_rect_object(); // application is crashing here
console.log("after click");
}
}
}
}
myrect.qml
import QtQuick 2.0
Rectangle {
id:id_rec
width: 100
height: 100
color: "green"
x:0
y:0
}
更新
要创建的对象不是 main window 的根的子对象,而是 mainwindow 的子项链中的一项的子项。伪结构如下所示。
main.qml
Window {
customitem1{
id:id_ci1
}
customitem2{
id:id_ci1
}
}
customitem1.qml
Item {
customitem3{
id:id_ci3
}
customitem3{
id:id_ci4
}
}
[已更新]
您有两个崩溃错误和一个不显示矩形的错误
1.Your scene
的 构造函数成员初始化列表 是假的,导致应用程序崩溃
(提示:为 class 的成员使用不同的命名方式,方法是在他们前面加上 m_
前缀,例如:m_engine
for 可读性并且不会混淆)
//Correct WAY
class Something
{
private:
int m_value1;
double m_value2;
char m_value3;
public:
//################# YOUR CASE ###############################
Something(int number) : m_value1(number), m_value2(2.2), m_value3('c') // directly initialize our member variables
{
// No need for assignment here
}
//#############################################################
Something() : m_value1(1), m_value2(2.2), m_value3('c') // directly initialize our member variables
{
// No need for assignment here
}
void print()
{
std::cout << "Something(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
}
}
应该是这样的:
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(engine),QObject(parent)
而不是
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
2.The url
of myrect.qml
你从本地文件中得到的 在 运行时 导致应用程序崩溃,补救措施之一是从您的 qrc
文件
QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));
3.And 你会注意到点击后你没有矩形,这是因为创建的矩形没有父级并且通过更改你的 create_rect_object()
(在这个例子中父级是不可见的我们的根 window contentItem
) 你会得到一些矩形 :)
//A QQuickWindow always has a single invisible root item containing all of its content.
//To add items to this window, reparent the items to the contentItem or to an existing item in the scene.
//http://doc.qt.io/qt-5/qquickwindow.html#contentItem-prop
void scene::create_rect_object()
{
QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));
QObject *object = component.create();
QQuickItem *item = qobject_cast<QQuickItem*>(object);
// Set the parent of our created qml rect
item->setParentItem((QQuickItem*)((QQuickWindow *) engine.rootObjects()[0])->contentItem());
//Set some random position and color
item->setProperty("color", QColor::fromRgb(QRandomGenerator::global()->generate()));
item->setX(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
item->setY(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
}
从 C++ 中查找 QML 对象
要查找对象并将其用作 parentItem
,您必须设置 qml 对象的 objectName
Rectangle {
...
objectName : "rect_1"
...
}
在 C++ 中
QObject* obj = dynamic_cast<QObject*>(engine.rootObjects()[0]).findChild("rect_1");