繁体   English   中英

来自C ++的QQuickItem实例化和设置难题(不允许将任何东西传递给构造函数)

[英]QQuickItem instantiation from C++ and setup conundrum (not allowed to pass anything to the constructor)

我发现自己很想从C ++动态实例化自定义QML元素。

因此,要布置问题:

  • 我有一个轻量级的Node对象数据结构,该结构是从任何UI提取的。
  • 由于QObject和派生类占用大量内存,因此必须按需实例化UI元素。
  • 每个Node都有一个_ui*成员,每个UI都有一个_node*成员。
  • 每个Node都有一个唯一的_id ,每个UI都有一个ID PROPERTY ,该PROPERTY是从_node*传递的。 ID属性是只读的,因为ID是在Node实例化时设置的,因此不可修改。
  • QML元素只能具有带有默认参数的构造函数,例如,不能将任何东西传递给构造函数。
  • 创建QML元素时, _node*成员为NULL ,因此UI任何尝试访问ID属性的QML子元素都不能,因为_node*不在实例化时设置,只能通过aux方法设置,但是由于该属性实际上是一个只读常量,因此在实例化后实际设置UI_node*成员时不会再对其进行更新。

因此,基本上,我需要能够在创建时将链接设置为每个UI的相应Node ,以便UI QML元素可以访问该链接,但是由于属性是只读的,因此无法将其传递给构造函数。当_node* UI成员仍然为NULL时,在UI实例化时,它仅被读取一次,因此无法访问ID值。

我想到的一种快速而又肮脏的解决方案是,在设置_node*成员实例化后添加一个NOTIFY idChanged()信号,即使ID属性从不真正更改,不能也不应更改,并添加对ID的检查_node*如果_node*NULL ,则返回假的伪任意值,否则从_node*成员获取ID值。 不用说,这不是很优雅,并且会增加一些开销,并且虚拟ID值可能是蠕虫的潜在威胁,因此,欢迎提出任何方法来击败QML内部结构的不良设计。

我只是提供了一个解决方案,一个相当简单的解决方案。 考虑到QtQuick的设计方式不允许指定构造函数参数,并且考虑到“创建并设置”方法在我的特定使用场景中具有巨大的意义,因此我决定简单地使该值甚至可用于UI构造函数如果没有作为参数传递到那里。

因此,我不是“创建并设置”,而是执行“设置并创建”并使用在创建每个项目之前设置的静态类成员,该静态类成员在项目构造函数中用于及时设置数据。

class UI : public QQuickItem
{
    Q_OBJECT
public:
    explicit UI(QQuickItem * parent = 0);
    ...
private:
    Object * object;
    static UI * rootUI;
};

Object * UI::protoObject = 0;

UI::UI(QQuickItem * parent) : QQuickItem(parent), object(protoObject) {
    if (!protoObject) qDebug() << "ERROR: prototype object is 0, unexpected";
    ...
}

和实际的对象创建:

UI::setProtoObject(obj);
// create QQmlComponent with obj set being set in the constructor
UI::setProtoObject(0);

此外,另一种适用于在构造器中不需要设置对象的情况下适用的方法是创建QQmlComponentbeginCreate() ,设置所需的属性,并使用completeCreate()

由于QML组件始终是没有特定数据的遗传结构,因此无法避免两个步骤:实例化和填充。

ui.qml

import MyModules 1.0

MyUIRoot {
    id: root

    // all the visual stuff
    Rectangle {
        Text {
            text: root.nodeId // binding should be set up automatically
        }
    }
}

然后在c ++中的myuiroot.hmyuiroot.cpp中构建一个MyUIRoot类, myuiroot.cpp继承了QQuickItem函数

public:
    Q_PROPERTY(int nodeId READ nodeId NOTIFY nodeIdChanged);
    int nodeId();
    void setNode(Node* node);

signals:
    void nodeIdChanged();

private:
    Node* _node;

myuiroot.cpp您有

MyUIRoot::MyUIRoot(QQuickItem *parent) :
    QQuickItem(parent)
{
}

int nodeId()
{
    if (_node)
        // make sure that every valid ID is > 0
        return _node.id();
    else
        return -1;
}

void setNode(Node* node)
{
    if (_node != node)
    {
        _node = node;
        emit nodeIdChanged();
    }
}

main.cpp注册您的组件

qmlRegisterType<MyUIRoot>("MyModules", 1, 0, "MyUIRoot");

并用

QQmlComponent c(_view->engine(), path);
QObject *o = c.create();
MyUIRoot *item = qobject_cast<MyUIRoot*>(o);
item.setNode(....);

我看到的从C ++创建可视化Qt Quick元素的另一种方法是使用“自定义场景图项目”,而无需QML即可创建可视化项目。 请参阅http://qt-project.org/doc/qt-5.0/qtquick/qquickitem.html#custom-scene-graph-items

添加第二个构造函数并从C ++创建元素

ui.h

#include <QQuickItem>
#include "node.h"

class UI : public QQuickItem
{
    Q_OBJECT
public:
    explicit UI(QQuickItem *parent = 0);
    explicit UI(QQuickItem *parent = 0, Node *node = 0);

signals:

public slots:

private:
    Node* _node;

};

ui.cpp

#include "ui.h"

UI::UI(QQuickItem *parent) :
    QQuickItem(parent)
{
}

UI::UI(QQuickItem *parent, Node *node) :
    QQuickItem(parent)
  , _node(node)
{
    qDebug() << "My ID is" << node->id();
}

用创建

Node *node = new Node();
UI ui(0, node); // or parent QQuickItem instead of '0'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM