Как получить экземпляр объекта C++ QQuickItem на стороне C++

У меня есть QtApp и чистая библиотека C++. Библиотека C++ предоставляет один простой класс с именем MyCppLibApiClass. QtApp имеет класс, встроенный в main.qml. Ниже приведен класс:

class MyQuickItem : public QQuickItem {
  MyQuickItem();
}

Следуя коду qml для quick item:

import MyQuickItem 1.0

MyQuickItem {
  id: myQuickItemID
  visible: true
  objectName: "myQuickItem"
}

Ниже приведен мой main.cpp, показывающий, что я загружаю элемент qml:

qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
return app.exec();

MyQuickItem требуется доступ к экземпляру MyCppLibApiClass. Как мне получить действительный экземпляр MyQuickItem в main.cpp? Мне нужно установить объект MyCppLibApiClass в качестве члена в MyQuickItem. Я могу сделать это, используя метод установки. Но прежде всего мне нужно получить действительный экземпляр для MyQuickItem. Итак, Как получить доступ к MyQuickItem в main.cpp?

EDIT:
Я долго искал, прежде чем задавать этот вопрос. Я прочитал это ссылка. Кроме того, Этот вопрос размещенный мной, не получил мне точного ответа. Следовательно, перефразируя мой вопрос более четко, чтобы попытаться получить ответ. Оцените предложения к этому ..


person TheWaterProgrammer    schedule 22.10.2016    source источник
comment
Чтобы представить свой класс в QML, вы должны получить его как минимум из QObject (или из QQuickItem, если это видимый элемент). В другом случае вы можете обернуть его в QObject и, таким образом, предоставить его QML, используя qmlRegisterType   -  person folibis    schedule 22.10.2016
comment
как вы видите в моем вопросе, я уже получил MyQuickItem из QQuickItem. Теперь, как мне получить доступ к экземпляру MyQuickItem в main.cpp?   -  person TheWaterProgrammer    schedule 22.10.2016
comment
что это значит? если вы предоставляете свой класс QML с помощью qmlRegisterType, вы не должны его использовать. Он будет создан QML.   -  person folibis    schedule 22.10.2016
comment
Мой вопрос: как мне получить доступ к этому экземпляру MyQuickItem, который QML создал после вызова qmlRegisterType.   -  person TheWaterProgrammer    schedule 22.10.2016
comment
Или есть другой способ экземпляра MyQuickItem в QML, чтобы я мог получить доступ к его объекту в main.cpp?   -  person TheWaterProgrammer    schedule 22.10.2016
comment
Ах .. получить его сейчас. Просто назначьте objectName элементу QML, а также QQuickItem *myItem = engine.rootObjects()[0]->findChild<QQuickItem *>("myQuickItem");   -  person folibis    schedule 22.10.2016
comment
Получив доступ к myItem описанным вами способом, смогу ли я вызвать метод, который я предоставил, для установки объекта чистого класса cpp? Вот так: myItem.setPureCppClassObject(cppObeject) ?   -  person TheWaterProgrammer    schedule 22.10.2016
comment
@NelsonP - конечно, это C ++, вы можете называть все, что общедоступно.   -  person dtech    schedule 22.10.2016
comment
@folibis спасибо. я попробую это   -  person TheWaterProgrammer    schedule 22.10.2016
comment
То есть, по сути, вы повторили вопрос в надежде получить ответы, которые вам больше нравятся? И оказалось, что ответы точно такие же, как у вас на предыдущий вопрос? Может быть, вы должны воспринять это как намек на то, что эти ответы и есть то, что вы ищете, даже если вы настаиваете на поиске чего-то другого?   -  person Kevin Krammer    schedule 23.10.2016
comment
@Кевин Краммер. Мой вопрос был другим. Я не хотел получить ответ на 2-3 дополнительных вопроса после того, как задал один. Следовательно, созданы отдельные отдельные вопросы   -  person TheWaterProgrammer    schedule 23.10.2016
comment
@KevinKrammer Не уверен, почему этот вопрос был отклонен. Это обсуждение на этой странице содержит много полезной информации по теме доступа к объекту QuickItem.   -  person TheWaterProgrammer    schedule 23.10.2016
comment
@folibis Я попробовал ваше предложение: QQuickItem *myItem = engine.rootObjects()[0]->findChild<QQuickItem *>("myQuickItem"); оно прекрасно работает. Спасибо   -  person TheWaterProgrammer    schedule 23.10.2016
comment
@NelsonP, вероятно, потому что это дубликат. Тратить время всех, постоянно задавая один и тот же вопрос, скорее всего, не осудят.   -  person Kevin Krammer    schedule 23.10.2016
comment
@KevinKrammer Из предыдущего вопроса ясно видно, что я вообще не получил никаких ответов. Тогда я задал этот вопрос. Если бы не это обсуждение, я бы не получил свой ответ. Я согласился, что это дублирующий вопрос, но это вопрос, который дал мне мой ответ, а также несколько вариантов :) Есть ли способ отметить вопрос, если я не привлекаю к ​​нему внимания?   -  person TheWaterProgrammer    schedule 24.10.2016
comment
@NelsonP Интересно. Каким-то образом мы получаем разные результаты. Я вижу ответ на другой вопрос, но, может быть, это потому, что ответ исходит от меня самого и каким-то образом скрыт от других? Хм, нет, вы прокомментировали это, так что вы, должно быть, видели это. В ответе даже есть комментарий, в котором упоминается хак, который вы, кажется, предпочитаете чистому и поддерживаемому решению. Ответ вдруг исчез для вас?   -  person Kevin Krammer    schedule 24.10.2016
comment
@Кевин Краммер. не уверен, что вы спрашиваете, но в любом случае я согласен. дублирующий вопрос - это дубликат по правилам :) Ага. Но в обоих моих вопросах было много хороших предложений. Мне нужно попробовать лучшее решение. на данный момент я просто делаю то, что работает   -  person TheWaterProgrammer    schedule 24.10.2016


Ответы (2)


Если у вас есть один экземпляр вашего библиотечного объекта, вы можете сделать это двумя способами в зависимости от того, какой доступ вам нужен:

  • иметь экземпляр в качестве статического члена класса MyQuickItem, инициализировать его в main.cpp перед созданием приложения QML, после чего вы можете получить к нему доступ изнутри MyQuickItem в C++.

  • пусть экземпляр наследует QObject и выставляет его как свойство контекста, таким образом, к нему можно получить доступ из QML.

Если это не одноэлементный объект, у вас есть два варианта действий:

  • создайте объект QML из С++, он даст вам прямой указатель на него
  • найдите объект QML в дереве объектов, используя QQmlApplicationEngine::rootObjects().at(0).findChild() для типа и имя объекта, если оно найдено, у вас будет указатель на объект

Однако, как подсказывает один из ответов на понравившиеся вам вопросы, на самом деле это не считается рекомендуемой практикой. Вероятно, есть лучший способ сделать это, вам не следует устанавливать свойства объекта QML в main.cpp, это должно быть либо в конструкторе, либо в открытом интерфейсе MyQuickItem.

person dtech    schedule 22.10.2016
comment
Спасибо за внимание. Могу ли я раскрыть setproperty в MyQuickItem, который принимает чистый класс C++? Не могли бы вы предоставить несколько справочных проектов на github или где-нибудь, кто делает то же самое? - person TheWaterProgrammer; 22.10.2016
comment
Вы можете передавать непрозрачные типы C++, не производные от QObject, в QML в качестве параметра и возвращать значения, если вы Q_DECLARE_METATYPE(YourType) То есть, если вам нужно сделать это из QML, из C++ у вас есть полный доступ к общедоступному интерфейсу объекта, вы можете делать, как вам угодно . Но опять же, вы делаете это неправильно. Сейчас это может быть неважно, но рано или поздно будет. Плохой дизайн всегда ужасен в долгосрочной перспективе. - person dtech; 22.10.2016
comment
Что вы порекомендуете, как лучше всего это сделать? У меня есть pure C++ library, предоставляющий чистый класс cpp с API. Я не могу позволить себе поставить qt в библиотеку cpp. Все, что мне нужно, это установить этот класс библиотеки cpp в класс быстрого элемента qml. Есть ли примеры кода на github, на которые я могу сослаться? было бы здорово, если бы вы могли предоставить несколько примеров кода, пожалуйста - person TheWaterProgrammer; 22.10.2016
comment
@NelsonP - ваш сценарий использования неизвестен, поэтому я не могу получить конкретный совет. Однако что плохого в том, чтобы использовать вашу библиотеку из С++ ВНУТРИ MyQuickItem вместо main.cpp? Похоже, это то, что вы должны делать. - person dtech; 22.10.2016
comment
Я новичок в Qt. Я должен попробовать предложения, прежде чем я отвечу или попрошу любую другую информацию. Я вернусь после того, как попробую вещи. большое спасибо за внимание к этому. - person TheWaterProgrammer; 22.10.2016
comment
@NelsonP - если вы можете сделать это в main.cpp, вы можете сделать это в конструкторе или в слоте MyQuickItem. - person dtech; 22.10.2016
comment
Последний вопрос: если сделать слот в MyQuickItem для приема экземпляра MyPureCppClassObeject, то могу ли я сделать слот с типом MyPureCppClassObeject или мне нужно использовать QVariant? - person TheWaterProgrammer; 22.10.2016
comment
Вам нужна вариантная оболочка только в том случае, если вы звоните из QML и передаете туда параметр. На стороне С++ вам не нужен этот сахар. - person dtech; 22.10.2016
comment
@ddriver пустая трата времени, он застрял в своих размышлениях, что не может понять, как ваш ценный вклад может привести его к действительно ремонтопригодному решению. - person Kevin Krammer; 23.10.2016
comment
@KevinKrammer Знания являются продуктом опыта, но не заменяют его. Некоторым вещам нельзя научиться, обучая, так, как их можно узнать, пытаясь. - person dtech; 23.10.2016

в вашем main.cpp:

qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
QQmlApplicationEngine engine;
MyQuickItem myItem;
engine.rootContext()->setContextProperty("myItem", &myItem);
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));

Теперь вы можете получить доступ к myItem из C++ и получить доступ к тому же самому myItem из QML, просто установив свойство «myItem» на корневом уровне контекста QML как ссылку на ваш пользовательский объект.

ИЗМЕНИТЬ

Я добавил в ответ объявление qmlRegisterType.

Согласно запросу в комментарии:

Использование qmlRegisterType‹>() используется для регистрации определенного типа в QML, который затем может быть создан/доступен из QML.

Используя метод engine.rootContext()->setContextProperty("myItem", &myItem), вы фактически создаете myItem на C++ и устанавливаете право собственности на myItem на C++.

Поскольку QML предназначен для работы с C++, можно просто назначить myItem в качестве свойства в QML, а поскольку QML автоматически наследует свойства/объекты от родительских объектов, то myItem становится доступным во всем контексте QML.

Ни один из двух примеров не тестировался и предназначен только для демонстрации идеи

Пример main.qml

import MyQuickItem 1.0

Item {
   Component.onCompleted {
        myItem.visible = true;
        myItem.myCustomMethod();
   }
}

Пример класса C++

class MyQuickItem : public QQuickItem {


     MyQuickItem();

 public slots: 
    void myCustomMethod() { /* do some C++ stuff here */ }

 }
person mike510a    schedule 22.10.2016
comment
мой ответ на самом деле был просто ответом ddriver, только написанным в коде, поэтому, чтобы понять его, лучше обратитесь к ответу ddriver выше - person mike510a; 23.10.2016
comment
спасибо за код. Я вижу, что вы не делаете qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem"). Если я этого не сделаю, Qt не позволит мне сделать import MyQuickItem 1.0. следовательно, запрещает мне объявлять MyQuickItem в main.qml вообще. qmlRegisterType больше не требуется? Не могли бы вы предоставить qml часть кода вокруг MyQuickItem? - person TheWaterProgrammer; 23.10.2016