В моем проекте я пытаюсь предоставить одноэлементный тип 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 не может распознать тип, если он определен внутри библиотеки?
У меня были похожие проблемы при использовании подкаталогов с синглтонами. Вместо этого я использовал qmlRegisterSingletonInstance и стал намного счастливее.
@Amfasis Спасибо за предложение, попробовал, получил немало логов, но, к сожалению, ничего не связанного с моим модулем. Я вижу несколько ошибок, таких как: qt.core.plugin.factoryloader: "The plugin 'W:/Programs/Qt/6.7.0/msvc2019_64/plugins/platforms/qdirect2d.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/qtquickcontrols2plugind.dll" loaded library и прикреплены некоторые метаданные.
@TomaszKalisiak Да, спасибо, наверное, qmlRegisterSingletonInstance это то, что я сейчас буду использовать, но хотел немного углубиться в эту проблему и надеюсь, что макросы QML_* заработают.
Также попытался установить QML_IMPORT_TRACE=1, получил кучу журналов, но ничего не связанного с моим модулем.
Вы пробовали импортировать модуль? import Main
@JarMan Да, хотя Qt Creator жалуется, что QML module not found приложение компилируется и запускается нормально, но я получаю ту же ошибку qrc:/qt/qml/Main/Main.qml:18: ReferenceError: MySingleton is not defined.
Модуль не найден? Ну тогда в этом проблема. Попробуйте сделать это в файле CMakeLists.txt: target_link_libraries(apptypetest PUBLIC logicmodulePlugin)
@JarMan К сожалению, такого файла нет fatal error LNK1104: cannot open file 'logicmodulePlugin.lib' . Я думаю, что сам Qt Creator не может разрешить импорт, поскольку приложение компилируется нормально. Или, может быть, я не могу импортировать Main, поскольку все файлы qml уже находятся в модуле Main.





Проблема заключалась в использовании 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, которые помогли мне решить эту проблему:
Я не очень знаком с v6 Qt, но, возможно, вы сможете найти решение, проверив журналы при запуске приложения с переменной среды QT_DEBUG_PLUGINS=1?