为啥我不能使用我的 QML 单例模块?
Posted
技术标签:
【中文标题】为啥我不能使用我的 QML 单例模块?【英文标题】:Why can I not use my QML singleton module?为什么我不能使用我的 QML 单例模块? 【发布时间】:2021-03-05 18:50:19 【问题描述】:我在https://github.com/jh3010-qt-questions/font_test有一个简单的测试项目
当我构建它时,我得到了错误:
qrc:/main.qml:5 模块“字体”未安装
我的目录结构如下:
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
可以工作。
【问题讨论】:
文件夹名称和导入名称大小写不匹配,这是问题中的错误,还是实际情况如何?他们应该匹配 这不是问题中的错误,可以通过访问 GitHub 存储库来确认。我已经更正了,但问题仍然存在。还有其他事情发生。 【参考方案1】:如here 所述,该模块必须在 QML 引擎的导入路径中可用:
要定义一个模块,开发者应该将模块中的各种 QML 文档、javascript 资源和 C++ 插件收集到一个目录中,并编写一个适当的模块定义 qmldir 文件,该文件也应该放入该目录中。然后可以将该目录作为模块安装到 QML 导入路径中。
您可以通过使用包含qmldir
的目录的父目录的路径调用addImportPath() 来执行此操作。当您使用
import Fonts 1.0
QML 引擎在每个导入路径中查找名为Fonts
的目录,如果找到,则查找qmldir
文件。由于您在 QRC 文件中使用了前缀,因此 qmldir
文件的最终路径是 :/Fonts/qmldir
。 Fonts
的父目录(包含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>
【讨论】:
太棒了。这样可行。我很惊讶 QML_IMPORT_PATH 与 engine.addImportPath 的用途不同。我从 .pro 文件中删除了 QML_IMPORT_PATH 并从 .pro 文件中删除了 DISTFILES +=。 您是否尝试过使用QML2_IMPORT_PATH
?
我刚刚做了,而且效果也很好。我想我比一行 c++ 代码更喜欢这个解决方案。我想在其他因素影响只能由代码知道和确定的路径的情况下,c++ 解决方案会更好。
不! QML_IMPORT_PATH
/ QML2_IMPORT_PATH
仅用于 QtCreator。它使 QtCreator 识别模块,自动完成它们的内容,而不是把它们都标为错误。 QML_IMPORT_PATH
存在是因为 QtCreator 无法执行 C++ 代码来了解模块的位置。如果您不使用engine.addImportPath()
,它只会在从 QtCreator 中启动时起作用,或者如果您从预先明确设置 QML2_IMPORT_PATH 的批处理脚本运行它。这是一个坏主意。如果您使用此方法,则运行时需要 engine.addImportPath() 和 QtCreator 需要 QML_IMPORT_PATH
。
哦,有趣。感谢您提供更多信息。【参考方案2】:
我看到另一个答案在几分钟内击败了我。那好吧。我会发布我的以防万一。
如何通过目录导入解决问题:
将丢失的文件添加到qml.qrc
文件中的资源列表:
<qresource prefix="/Fonts">
...........
<file alias="Fonts.qml">assets/Fonts/Fonts.qml</file>
<file alias="qmldir">assets/Fonts/qmldir</file>
请注意alias
es,否则路径会不同
如果您不将文件添加到资源中,它们将不会通过qrc://
可见,并且它们也不会包含在您编译的应用程序中,即您的代码只能在您的计算机上运行,除非您安装丢失的文件手动使用您的应用程序
从main.qml
移除模块导入:
//import Fonts 1.0
如果您通过 qmldir
文件创建单例,则不需要(并且不会工作)
导入将不起作用,因为 Qt 不会在 qrc://
路径中查找模块,除非您在 C++ 代码中明确指定 - 请参阅其他答案以了解如何执行此操作
而是在main.qml
的顶部添加一个directory import:
import "qrc:/Fonts/"
这会导入 qmldir
file,它会根据您的指定从文件 Fonts.qml
创建一个名为 Fonts
的单例
请注意,虽然它在目录中导入了qmldir
和*.qml
文件,但它并没有告诉Qt 加载模块 来自同一个目录。
我还必须将QT += qml
添加到font_test.pro
,但如果您的 Qt/QML 版本完全可以编译,则可能不需要它
像你已经尝试的那样使用你的单例:Fonts.artBrewery.name
参考文献
更多信息请参见 Qt 文档:
QML directory import 包括directory definitionqmldir
files
module definition qmldir
files
【讨论】:
+1 用于提及目录导入。也许您想链接到doc.qt.io/qt-5/qtqml-syntax-directoryimports.html 以获取更多信息。 谢谢。在答案末尾添加了参考。 太棒了。这样可行。我很惊讶 QML_IMPORT_PATH 与 engine.addImportPath 的用途不同。我从 .pro 文件中删除了 QML_IMPORT_PATH ,还从 .pro 文件中删除了 DISTFILES += 。奇怪的是,放置import Fonts 1.0
确实允许它工作,但 Qt Creator 抱怨找不到模块。我猜这是一个错误。使用 import "qrc:/Fonts/"
也可以,并且是正确的解决方案。
就我而言,我认为 .pro 文件中的QML2_IMPORT_PATH
是更好的解决方案。 doc.qt.io/qt-5/qtqml-syntax-imports.html 的文档也与此问题相关以上是关于为啥我不能使用我的 QML 单例模块?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能在类方法中使用 python 模块 concurrent.futures?
PYTHON 为啥我的 python IDLE 不能将 numpy 识别为模块,尽管在 cmd 中运行 pythob 时可以正常使用 numpy?