在 QML 文件中使用时,未定义 QML 模块中的自定义 C++ 类型

问题描述 投票:0回答:1

在我的项目中,我试图将单例类型从 C++ 公开到 QML。最初我用

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 无法识别在库中定义的类型?

c++ qt qml
1个回答
0
投票

问题出在

NO_PLUGIN
调用中使用
qt_add_qml_module()
。删除它并将可执行文件链接到 *plugin 目标而不是支持 lib 后,一切正常。

最终 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-define-when-used-inside-qml-file

© www.soinside.com 2019 - 2024. All rights reserved.