2

If I use import MyModule 1.0 I got an error message what MyModule is not installed.

QQmlApplicationEngine failed to load component
qrc:/main.qml:3:1: module "MyModule" is not installed

But I correctly wrote qmldir file and resources file. And if I use import "MyModule" all is Ok. But I need to use import without quotes and import my modules in all files in different directories.

How to correctly import custom Qml element?

File structure

QMLDIRTEST
│   CMakeLists.txt
│   main.cpp
│   main.qml
│   qml.qrc
│
└───MyModule
        qmldir
        RedRectangle.qml

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(QmlDirTest VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt5 COMPONENTS Core Quick REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick REQUIRED)

set(PROJECT_SOURCES main.cpp qml.qrc)
add_executable(QmlDirTest ${PROJECT_SOURCES})
target_link_libraries(QmlDirTest PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick)

qml.qrc

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
        <file>MyModule/RedRectangle.qml</file>
        <file>MyModule/qmldir</file>
    </qresource>
</RCC>

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;
    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.addImportPath("qrc:/Ui");
    engine.load(url);

    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import MyModule 1.0
//import "MyModule"

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    RedRectangle { anchors.centerIn: parent }
}

RedRectangle.qml

import QtQuick 2.15

Rectangle {
    width: 200
    height: 100
    color: "red"
}

qmldir

Module MyModule

RedRectangle 1.0 RedRectangle.qml
4
  • 1
    Try adding engine.addImportPath("qrc:/");. Commented Jan 22, 2024 at 14:33
  • 1
    In qmldir module keyword must be lowercase Commented Jan 23, 2024 at 4:55
  • @Mike I changed, but it does not helped me Commented Jan 23, 2024 at 6:08
  • @smr Your comment is correct. Please write as answer. And can you explain why this works? Can I realized it in CMake file? Commented Jan 23, 2024 at 6:11

1 Answer 1

1

According to the documentation, addImportPath is needed to tell the engine where to search for the new modules that you have provided.

QQmlEngine::addImportPath states:

Adds a path as a directory where the engine searches for installed modules in a URL-based directory structure. The path may be a local filesystem directory, a Qt Resource path (:/imports), a Qt Resource URL (qrc:/imports), or a URL.

After Qt 6.*, there is a qt_add_qml_module function in CMake that you can use to add new modules using only CMake. This function will automatically generate the qmldir and resource files.

qt_add_qml_module(${PROJECT_NAME}
    URI module.uri
    QML_FILES Component1.qml Component2.qml
)

In Qt 6.*, there is a qrc:/qt/qml in the default import path list. By using qt_policy(SET QTP0001 NEW) in your CMake file, the generated resources (using qt_add_qml_module) will have /qt/qml as their default prefix. This allows the engine to detect your module without needing to add any new import paths. (ref: QTP0001)

You can check this by printing engine.importPathList(), and you will see qrc:/qt/qml in the output list.

qDebug << engine.importPathList();
// Output:
// ("path/to/build-directory/", "path/to/Qt/6.6.1/current-kit/qml", "qrc:/qt-project.org/imports", "qrc:/qt/qml")

The Qt 5.* solution

You can use the same trick in Qt 5 as well.
By printing importPathList, you will see that there is /qt-project.org/imports as the default resource path in the import path list:

qDebug << engine.importPathList();
// Output: 
QList(
    "path/to/build-directory/",
    "path/to/Qt/5.15.2/current-kit/qml",
    "qrc:/qt-project.org/imports",
)

So, by adding /qt-project.org/imports to your resource prefix, you can make the engine recognize your provided module. For example:

qml.qrc

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
    </qresource>
    <qresource prefix="/qt-project.org/imports">
        <file>MyModule/RedRectangle.qml</file>
        <file>MyModule/qmldir</file>
    </qresource>
</RCC>

To ensure that the linter recognizes your modules, you can also set the QML_IMPORT_PATH variable in your CMake file.

list(APPEND QML_DIRS "${CMAKE_SOURCE_DIR}/.")
set(QML_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator extra qml import paths")
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.