为什么我不能使用我的 QML 单例模块?

Why can I not use my QML singleton module?

我在 https://github.com/jh3010-qt-questions/font_test

有一个简单的测试项目

构建时出现错误:

qrc:/main.qml:5 module "Fonts" is not installed

我的目录结构如下:

font_test
├── assets
│   └── Fonts
│       ├── Art Brewery.ttf
│       ├── Fonts.qml
│       ├── Roboto-Light.ttf
│       ├── Roboto-Medium.ttf
│       ├── Roboto-Regular.ttf
│       └── qmldir
├── font_test.pro
├── font_test.pro.user
├── main.cpp
├── main.qml
└── qml.qrc

我的 qml.qrc 文件是:

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
    </qresource>
    <qresource prefix="/Fonts">
        <file alias="Art Brewery.ttf">assets/Fonts/Art Brewery.ttf</file>
        <file alias="Roboto-Light.ttf">assets/Fonts/Roboto-Light.ttf</file>
        <file alias="Roboto-Medium.ttf">assets/Fonts/Roboto-Medium.ttf</file>
        <file alias="Roboto-Regular.ttf">assets/Fonts/Roboto-Regular.ttf</file>
    </qresource>
</RCC>

我的project file是:

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/assets

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

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

DISTFILES += \
  assets/Fonts/Fonts.qml \
  assets/Fonts/qmldir

我的 Fonts.qml 文件是:

pragma Singleton
import QtQuick 2.12

Item
{
  readonly property FontLoader artBrewery: FontLoader { source: "qrc:/Fonts/Art Brewery.ttf" }
  readonly property FontLoader robotoLight: FontLoader { source: "qrc:/Fonts/Roboto-Light.ttf" }
  readonly property FontLoader robotoMedium: FontLoader { source: "qrc:/Fonts/Roboto-Medium.ttf" }
  readonly property FontLoader robotoRegular: FontLoader { source: "qrc:/Fonts/Roboto-Regular.ttf" }
}

我在 assets/fonts 文件夹中的 qmldir 是:

singleton Fonts 1.0 Fonts.qml

我尝试使用main.qml

中的字体
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

import Fonts 1.0

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

  Column
  {
    spacing: 8

    anchors.fill: parent
    anchors.margins: 8

    Label
    {
      text: "DEFAULT: Pack my box with five dozen liquor jugs"
    }

    Label
    {
      text: "ART BREWERY: Pack my box with five dozen liquor jugs"

      font.family: Fonts.artBrewery.name
      font.pixelSize: 36
    }

    Label
    {
      text: "ROBOTO: Pack my box with five dozen liquor jugs"
    }
  }
}

在我将 QML_IMPORT_PATH = $$PWD/assets 添加到我的项目文件之前,Qt Creator 会抱怨 import Fonts 1.0。需要这样做有意义吗?

我想知道 assets/fonts/qmldir 是否属于 DISTFILES...?

我不确定需要更改什么,所以 main.qml 中的 font.family: Fonts.artBrewery.name 会起作用。

如所述here,该模块必须在 QML 引擎的导入路径中可用:

To define a module, a developer should gather together the various QML documents, JavaScript resources and C++ plugins which belong in the module into a single directory, and write an appropriate module definition qmldir file which should also be placed into the directory. The directory can then be installed into the QML import path as a module.

您可以通过使用包含 qmldir 的目录的父目录的路径调用 addImportPath() 来完成此操作。当您使用

导入模块时
import Fonts 1.0

QML 引擎在每个导入路径中查找名为 Fonts 的目录,如果找到,则查找 qmldir 文件。由于您在 QRC 文件中使用了前缀,因此 qmldir 文件的最终路径是 :/Fonts/qmldirFonts的父目录(包含qmldir的目录)是根资源目录:/,所以:

diff --git a/main.cpp b/main.cpp
index 3d80569..de4efb7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -10,6 +10,7 @@ int main(int argc, char *argv[])
   QGuiApplication app(argc, argv);
 
   QQmlApplicationEngine engine;
+  engine.addImportPath(":/");
   const QUrl url(QStringLiteral("qrc:/main.qml"));
   QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                    &app, [url](QObject *obj, const QUrl &objUrl) {

您还需要确保您的模块使用的所有文件都可以作为资源使用。这意味着添加以下文件:

diff --git a/qml.qrc b/qml.qrc
index f212706..40cb8dc 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -3,6 +3,8 @@
         <file>main.qml</file>
     </qresource>
     <qresource prefix="/Fonts">
+        <file alias="qmldir">assets/Fonts/qmldir</file>
+        <file alias="Fonts.qml">assets/Fonts/Fonts.qml</file>
         <file alias="Art Brewery.ttf">assets/Fonts/Art Brewery.ttf</file>
         <file alias="Roboto-Light.ttf">assets/Fonts/Roboto-Light.ttf</file>
         <file alias="Roboto-Medium.ttf">assets/Fonts/Roboto-Medium.ttf</file>

几分钟后我看到另一个答案打败了我。那好吧。我会 post 我的以防万一。

如何通过目录导入解决问题:

  1. 将丢失的文件添加到 qml.qrc 文件中的资源列表:

    <qresource prefix="/Fonts">
     ...........
      <file alias="Fonts.qml">assets/Fonts/Fonts.qml</file>
      <file alias="qmldir">assets/Fonts/qmldir</file>
    

请注意aliases,否则路径会不同

如果您不将文件添加到资源中,它们将不会通过 qrc:// 可见,并且它们也不会包含在您编译的应用程序中,即您的代码只会 运行在您的计算机上,除非您使用应用程序手动安装丢失的文件

  1. main.qml 移除模块导入:

    //import Fonts 1.0
    

如果您通过 qmldir 文件

创建单例,则不需要(也不会起作用)

导入不会工作,因为 Qt 不会在 qrc:// 路径中寻找模块,除非您在 C++ 代码中明确指定 - 请参阅其他答案了解如何做到这一点

  1. 而是在 main.qml 的顶部添加一个 directory import:

    import "qrc:/Fonts/"
    

这会导入 qmldir file,它会按照您指定的方式从文件 Fonts.qml 创建一个名为 Fonts 的单例

请注意,虽然它在目录中导入 qmldir*.qml files,但它不会告诉 Qt 从同一目录加载 modules

  1. 我还必须将 QT += qml 添加到 font_test.pro,但如果它完全编译的话,您的 Qt/QML 版本可能不需要它

  2. 像您已经在尝试的那样使用您的单例:Fonts.artBrewery.name

参考资料

有关详细信息,请参阅 Qt 文档: