James Hudson
James Hudson

Reputation: 904

How to use QML Loader when the loaded component references another internal component

I have a repo at https://github.com/jh3010-qt-questions/qml_location/tree/loader_with_another_component

I am using Loader to load the MyDeeperComponent into main.qml's Column. However, MyDeeperComponent references another internal component called MySquare. When it loads, I get the error MySquare is not a type and the program quits. Of course, if I comment out MySquare from MyDeeperComponentForm.ui.qml, everything works and MyDeeperComponent loads successfully.

What needs to be changed so MyDeeperComponent can use MySquare and be dynamically loaded?

The directory structure is:

$ tree qml_location/
qml_location/
├── MySquare.qml
├── MySquareForm.ui.qml
├── main.cpp
├── main.qml
├── qml
│   └── more
│       ├── MyDeeperComponent.qml
│       └── MyDeeperComponentForm.ui.qml
├── qml.qrc
├── qml_location.pro
└── qml_location.pro.user

qml_location.pro

QT += quick

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH = $$PWD/qml

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH = $$PWD/qml

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

qml.qrc

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
        <file>qml/more/MyDeeperComponent.qml</file>
        <file>qml/more/MyDeeperComponentForm.ui.qml</file>
        <file>MySquare.qml</file>
        <file>MySquareForm.ui.qml</file>
    </qresource>
</RCC>

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true

  title: qsTr("Hello World")

  Column
  {
    MySquare {}

    Loader {
        source: "qrc:/qml/more/MyDeeperComponent.qml"
    }
  }
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

  QGuiApplication app(argc, argv);

  QQmlApplicationEngine engine;

  engine.addImportPath( "qrc:/qml" );

  const QUrl url(QStringLiteral("qrc:/main.qml"));

  QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                   &app, [url](QObject *obj, const QUrl &objUrl) {
    if (!obj && url == objUrl)
      QCoreApplication::exit(-1);
  }, Qt::QueuedConnection);
  engine.load(url);

  return app.exec();
}

MySquare.qml

import QtQuick 2.4

MySquareForm {
}

MySquareForm.ui.qml

import QtQuick 2.4

Rectangle {
  width: 40
  height: 40

  color: "blue"
}

Upvotes: 0

Views: 1514

Answers (1)

talamaki
talamaki

Reputation: 5472

Alternatively edit MyDeeperComponentForm.ui.qml by changing

MySquare {}

to

Loader {
  source: "../../MySquare.qml"
}

or by adding (as already mentioned in the comments)

import "../.."

Note however, that your use case looks pretty weird from the dependency point of view... I suppose you are already familiar with different import mechanisms in QML but adding the link anyway for reference.

Upvotes: 1

Related Questions