Пользовательский тип C++ из модуля QML не определен при использовании внутри файла QML

В моем проекте я пытаюсь предоставить одноэлементный тип QML из C++. Сначала я зарегистрировал его с помощью qmlRegisterSingletonInstance, и все работало нормально. Но когда я попытался заменить таким образом макросы QML_ELEMENT и QML_SINGLETON, он компилируется нормально, но когда QML пытается использовать класс, он жалуется, что тип не определен.

В моем проекте есть два модуля, один состоит исключительно из файлов qml, а второй - из файлов C++, из которых я пытаюсь выставить класс и использовать его в первом модуле. Структура немного сложна, поэтому я воспроизвел проблему с помощью более простого тестового проекта. Я заметил, что QML не может распознать ни одноэлементный тип, ни не-одиночный тип.

Проект имеет следующую структуру:

│   CMakeLists.txt
│   main.cpp
│
└───logicmodule
        CMakeLists.txt
        Main.qml
        Message.h
        MySingleton.h

Код:

// logicmodule/MySingleton.h
#pragma once

#include <QObject>
#include <QQmlEngine>
#include <QString>

class MySingleton : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
public:
    MySingleton(QObject *parent = nullptr)
        : QObject{parent}
    {}

public slots:
    QString exec(const QString &str) { return "somestring"; }
};
// logicmodule/Message.h
#pragma once

#include <QObject>
#include <QQmlEngine>
#include <QString>

class Message : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    Q_PROPERTY(QString author MEMBER m_author NOTIFY authorChanged)
public:
    Message() {}

signals:
    void authorChanged();

private:
    QString m_author;
};
// logicmodule/Main.qml
import QtQuick
import QtQuick.Controls

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    // property Message msg: Message {}
    Button {
        id: button
        anchors.centerIn: parent
        text: "Click me"
        onClicked: {
            label.text = MySingleton.exec(label.text)
        }
    }
    Label {
        id: label
        anchors.top: button.bottom
    }
}
// logicmodule/CMakeLists.txt
project(logicmodule VERSION 0.1 LANGUAGES CXX)

qt_add_library(${PROJECT_NAME} STATIC)
qt6_add_qml_module(${PROJECT_NAME}
    URI Main
    VERSION 1.0
    NO_PLUGIN
    RESOURCE_PREFIX "/qt/qml"
    QML_FILES
        Main.qml
    SOURCES
        MySingleton.h
        Message.h
)

target_link_libraries(${PROJECT_NAME} PUBLIC
    Qt6::Core
    Qt6::Gui
    Qt6::Qml
    Qt6::Quick
)

target_include_directories(${PROJECT_NAME}
    PUBLIC
        .
)
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "Message.h"
#include "MySingleton.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    const QUrl url(u"qrc:/qt/qml/Main/Main.qml"_qs);
    QObject::connect(
        &engine,
        &QQmlApplicationEngine::objectCreated,
        &app,
        [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        },
        Qt::QueuedConnection);

    engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml");
    engine.addImportPath(":/");

    engine.load(url);

    if (engine.rootObjects().isEmpty()) {
        return -1;
    }

    return app.exec();
}
// CMakeLists.txt
cmake_minimum_required(VERSION 3.16)

project(typetest VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)

qt_standard_project_setup(REQUIRES 6.5)

add_subdirectory(logicmodule)

qt_add_executable(apptypetest
    main.cpp
)

target_link_libraries(apptypetest PUBLIC
    logicmodule
)

# No effect
# target_include_directories(apptypetest
#   PUBLIC
#       "${PROJECT_SOURCE_DIR}/logicmodule"
#       logicmodule
# )
# include_directories(logicmodule)

Все компилируется нормально, но во время выполнения я получаю сообщение об ошибке при попытке вызвать MySingleton:

qrc:/qt/qml/Main/Main.qml:16: ReferenceError: MySingleton is not defined

Я пытался изучить эту проблему, но не смог найти именно мой случай. Самое близкое, что я получил, это вот этот: qmltyperegistration включает путь, не признающий подкаталоги

Но файлы с пользовательскими типами, похоже, включаются без каких-либо префиксов.

Я также заметил, что в папке сборки у меня есть файл build\Debug\logicmodule\logicmodule_qmltyperegistrations.cpp и он содержит вызовы qmlRegisterTypesAndRevisions, но кажется, что это не имеет эффекта?

Также попробовал структуру проекта без каких-либо дополнительных библиотек (то есть без logicmodule lib, все находится в корне проекта, и у меня есть только один CMakeLists), и вроде бы все работает нормально, и все пользовательские типы распознаются QML.

Может ли кто-нибудь указать мне, что я делаю не так с библиотекой? Почему QML не может распознать тип, если он определен внутри библиотеки?

Я не очень знаком с v6 Qt, но, возможно, вы сможете найти решение, проверив журналы при запуске приложения с переменной среды QT_DEBUG_PLUGINS=1?

Amfasis 13.06.2024 08:59

У меня были похожие проблемы при использовании подкаталогов с синглтонами. Вместо этого я использовал qmlRegisterSingletonInstance и стал намного счастливее.

Tomasz Kalisiak 13.06.2024 19:52

@Amfasis Спасибо за предложение, попробовал, получил немало логов, но, к сожалению, ничего не связанного с моим модулем. Я вижу несколько ошибок, таких как: qt.core.plugin.factoryloader: "The plugin 'W:/Programs/Qt/6.7.0/msvc2019_64/plugins/platforms/qdirect2‌​d.dll' uses incompatible Qt library. (Cannot mix debug and release libraries.)" not a plugin но все они связаны с библиотеками qt. Все остальные журналы имеют вид: qt.core.library: "W:/Programs/Qt/6.7.0/msvc2019_64/qml/QtQuick/Controls/qtqui‌​ckcontrols2plugind.d‌​ll" loaded library и прикреплены некоторые метаданные.

monkeber 13.06.2024 22:50

@TomaszKalisiak Да, спасибо, наверное, qmlRegisterSingletonInstance это то, что я сейчас буду использовать, но хотел немного углубиться в эту проблему и надеюсь, что макросы QML_* заработают.

monkeber 13.06.2024 22:52

Также попытался установить QML_IMPORT_TRACE=1, получил кучу журналов, но ничего не связанного с моим модулем.

monkeber 13.06.2024 23:05

Вы пробовали импортировать модуль? import Main

JarMan 18.06.2024 00:35

@JarMan Да, хотя Qt Creator жалуется, что QML module not found приложение компилируется и запускается нормально, но я получаю ту же ошибку qrc:/qt/qml/Main/Main.qml:18: ReferenceError: MySingleton is not defined.

monkeber 18.06.2024 00:52

Модуль не найден? Ну тогда в этом проблема. Попробуйте сделать это в файле CMakeLists.txt: target_link_libraries(apptypetest PUBLIC logicmodulePlugin)

JarMan 18.06.2024 01:16

@JarMan К сожалению, такого файла нет fatal error LNK1104: cannot open file 'logicmodulePlugin.lib' . Я думаю, что сам Qt Creator не может разрешить импорт, поскольку приложение компилируется нормально. Или, может быть, я не могу импортировать Main, поскольку все файлы qml уже находятся в модуле Main.

monkeber 18.06.2024 23:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема заключалась в использовании NO_PLUGIN в qt_add_qml_module() вызове. После его удаления и связывания исполняемого файла с целью *plugin вместо поддержки библиотеки все заработало.

Итоговые списки CMakeLists:

# logicmodule/CMakeLists.txt
project(logicmodulelib VERSION 0.1 LANGUAGES CXX)

qt_add_library(${PROJECT_NAME} STATIC)
qt_add_qml_module(${PROJECT_NAME}
    URI logicmodule
    VERSION 1.0
    RESOURCE_PREFIX "/qt/qml"
    QML_FILES
        Main.qml
    SOURCES
        MySingleton.h
        Message.h
)

target_link_libraries(${PROJECT_NAME} PUBLIC
    Qt6::Core
    Qt6::Gui
    Qt6::Qml
    Qt6::Quick
)

target_include_directories(${PROJECT_NAME}
    PUBLIC
        .
)
# CmakeLists.txt
cmake_minimum_required(VERSION 3.16)

project(typetest VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
qt_policy(SET QTP0001 NEW)
set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qt/qml)
set(QML_IMPORT_PATH "${CMAKE_BINARY_DIR}/qt/qml" CACHE STRING "Qt Creator extra qml import paths"
    FORCE)

qt_standard_project_setup(REQUIRES 6.5)

add_subdirectory(logicmodule)

qt_add_executable(apptypetest
    main.cpp
)

target_link_libraries(apptypetest PUBLIC
    Qt6::Gui
    Qt6::Qml
    logicmodulelibplugin
)

Спасибо людям на форуме qt, которые помогли мне решить эту проблему:

https://forum.qt.io/topic/157297/custom-c-type-from-a-qml-module-is-not-defined-when-used-inside-qml-file

Другие вопросы по теме

Похожие вопросы