Qt QML include from different directory problem - qt

I have a directory structure like so for my QML files:
qml.qrc
main.qml
LockScreen/
LockScreen.qml
QuickMenu/
QuickMenu.qml
misc/
KeyboardInput.qml
(there are other files I have excluded, but that's not relevant)
I have added all the above files to my qrc file, with prefixes for each directory:
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>qtquickcontrols2.conf</file>
<file>MessagePopup.qml</file>
<file>MessagePopupForm.ui.qml</file>
</qresource>
<qresource prefix="/LockScreen">
<file>LockScreen/LockScreen.qml</file>
<file>LockScreen/fingerprint.png</file>
<file>LockScreen/fingerprint_highlighted.png</file>
</qresource>
<qresource prefix="/MainPages">
<file>MainPages/LibraryPage.qml</file>
<file>MainPages/CameraPage.qml</file>
<file>MainPages/MessagesPage.qml</file>
<file>MainPages/HomePage.qml</file>
<file>MainPages/saturn.jpg</file>
</qresource>
<qresource prefix="/QuickMenu">
<file>QuickMenu/QuickMenu.qml</file>
</qresource>
<qresource prefix="/misc">
<file>misc/KeyboardInput.qml</file>
</qresource>
</RCC>
My problem is that when I import each prefix like this
import "misc"
import "MainPages"
import "QuickMenu"
import "LockScreen"
in my main.qml, I get an error saying one of my QML objects is not a type.
QQmlApplicationEngine failed to load component
qrc:/main.qml:67 LockScreen is not a type
The strange thing is that I can access all my objects using the intellisense of QtCreator, everything seems to be imported fine until I build and run the app. Is there a way that the qrc paths are outdated or something? Or old cache files?

The problem is caused by the prefix that seems to add a level in the path, so in your case the import should be:
import "./LockScreen/LockScreen"
Although the editor loses the autocomplete and throws the warning. So it seems that the problem is with the editor who has problems interpreting the qresource alias.
A better option is to use an alias for the .qml file:
...
<qresource prefix="/LockScreen">
<file alias="LockScreen.qml">LockScreen/LockScreen.qml</file>
...
main.qml
import "LockScreen"
LockScreen{
// ...
}
Note: the alias must have a .qml extension otherwise Qt Creator will not recognize it correctly

Related

Why can I not use my QML singleton module?

I have a simple test project at https://github.com/jh3010-qt-questions/font_test
When I build it, I get the error:
qrc:/main.qml:5 module "Fonts" is not installed
My directory structure looks like:
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
my qml.qrc file is:
<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>
my project file is:
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
My Fonts.qml file is:
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" }
}
My qmldir inside of the assets/fonts folder is:
singleton Fonts 1.0 Fonts.qml
I try to use the font in 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"
}
}
}
Before I added QML_IMPORT_PATH = $$PWD/assets to my project file, Qt Creator would complain about import Fonts 1.0. Does it make sense this would be required?
I am wondering if assets/fonts/qmldir belongs in DISTFILES...?
I am not sure what needs to be changed so font.family: Fonts.artBrewery.name in main.qml will work.
As described here, the module has to be available in the QML engine's import path:
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.
You can do this by calling addImportPath() with the path to the parent directory of the directory that contains the qmldir. When you import your module with
import Fonts 1.0
the QML engine looks through each import path for a directory called Fonts, and if it finds it, looks for a qmldir file. Since you use a prefix in your QRC file, the final path to the qmldir file is :/Fonts/qmldir. The parent directory of Fonts (the directory that contains the qmldir) is the root resource directory :/, so:
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) {
You also need to ensure that all of the files your module uses are available as resources. That means adding the following files:
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>
I see another answer beat me in a couple of minutes. Oh well. I'll post mine just in case.
How to fix the problem through directory import:
Add missing files to resource list in qml.qrc file:
<qresource prefix="/Fonts">
...........
<file alias="Fonts.qml">assets/Fonts/Fonts.qml</file>
<file alias="qmldir">assets/Fonts/qmldir</file>
please note the aliases, otherwise paths will be different
If you do not add the files to resources, they won't be visible through qrc://, and also they won't be included into your compiled application i.e. your code will only run on your computer unless you install missing files manually with your application
Remove module import from main.qml:
//import Fonts 1.0
This is not needed (and will not work) if you create your singleton through qmldir file
The import won't work because Qt won't be looking for modules within qrc:// path unless you explicitly specify so in C++ code - see the other answer on how to do that
Instead add a directory import to the top of main.qml:
import "qrc:/Fonts/"
this imports qmldir file which creates a singleton named Fonts from file Fonts.qml as you specified
Please note that although it imports qmldir and *.qml files inside the directory, it does not tell Qt to load modules from that same directory.
I also had to add QT += qml to font_test.pro but it's probably not needed for your version of Qt/QML if it compiles at all
Use your singleton like you are already trying to do: Fonts.artBrewery.name
References
See Qt documentation for more information:
QML directory import including directory definition qmldir files
module definition qmldir files

How to rightly add resources in Qt application

I am trying to deploy windows application in Qt, so I change mode to release, but when I execute it, all it writes is
file::/qml/Main.qml: File is empty
I have already tried multiple times to rework resources.qrc, but with no success.
resources.qrc
<RCC>
<qresource prefix="/">
<file>qml/Pages/DetailPage.qml</file>
<file>qml/Pages/IntroPage.qml</file>
<file>qml/Pages/LibaryPage.qml</file>
<file>qml/Pages/Page.qml</file>
<file>qml/Pages/PageView.qml</file>
<file>qml/Controls/ControlSlider.qml</file>
<file>qml/Models/CityModel.qml</file>
<file>images/heatmapicon.png</file>
<file>qml/Main.qml</file>
</qresource>
</RCC>
I have tried to copy qml and images folder (they are in same folder as main.cpp and resources.qrc), but no success too.
This is how I set main source for QQuickView :
view_->setSource(QUrl::fromLocalFile(QStringLiteral(":/qml/Main.qml")));
In debug mode, there is no problem and everything start as it should.
How can I change resource/code to make it work?
Thanks for your help!
//EDIT:
I have manage to solve it with view_>setSource(QUrl(QStringLiteral("qrc:/qml/Main.qml")));
You do not have to use QUrl::fromLocalFile(), that function is indicating that you are looking for a local file, but the paths handled by a .qrc are virtual.
Use:
view_->setSource(QUrl(QStringLiteral("qrc:/qml/Main.qml")));

QResource register multiple resources, resource loading principle, which is the last available resource?

Let's say I have 3 qrc files. The first 2 contain the same resource path and the 3rd one doesn't contain that path, for eg:
qrc1:
<RCC>
<qresource prefix="/">
<file>res/image.png</file>
</qresource>
</RCC>
qrc2:
<RCC>
<qresource prefix="/">
<file>res/image.png</file>
</qresource>
qrc3:
<RCC>
<qresource prefix="/">
</qresource>
Loading the resources is done as follows:
QResource::registerResource("qrc1.rcc");
QResource::registerResource("qrc2.rcc");
QResource::registerResource("qrc3.rcc");
so the rcc files are registered in the above order. So when someone tries to get qrc:/res/image.png, which file it will get? from the first rcc that contains the respective resource(from qrc1) or from the last successfully loaded rcc (from qrc2)? I couldn't find an answer in the docs.
My tests show that it takes the resource from the first successful loaded rcc, even though I was expecting to get it from the last rcc. What should I do in order to take the resource from the last successful loaded rcc? Any ideas? Did somebody understand the resource loading principle in terms of order? Thanks.

QML importing module

I want to import a custom module in my main.qml file. Main.qml is located under "/" prefix of my qml.qrc resource.
My custom module Config.qml is located within Config subdirectory. (Config directory is where main.qml is, i.e. /path/to/main/Config/Config.qml.
The config.qml and qmldir files are stored under the prefix myPrefix in the qml.qrc file.
Project
|- Config
|- Config.qml
|- qmldir
|- main.qml
Also I created a qmldir file which is according to the documentation http://doc.qt.io/qt-5/qtqml-modules-identifiedmodules.html necessary. Here are my Config.qml and qmldir files.
Config.qml
pragma Singleton
import QtQuick 2.0
QtObject {
property int myVariable: 10
}
qmldir
singleton Config 1.0 Config.qml
When I want to import my custom module asMyModule in the main.qml file.
import "???" as MyModule
How can I do that? Does someone have a suggestion?
Edit:
qrc file
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
<qresource prefix="/myPrefix">
<file>Config/qmldir</file>
<file>Config/Config.qml</file>
</qresource>
** Question has been changed after the answer of Arpegius to raise another issue, I answer this new issue. **
This has nothing to do with qrc-prefix.
I believe your are mixing two different methods to import.
With or without prefix, to import a module you need to set the import-path of the QtQuick engine accordingly.
In your case, because your module directory is in the project-root directory :
engine.addImportPath("qrc:/");
// Now engine will look for subfolders which could be modules == with a qmldir
And in your main.qml you do the import using the prefix path instead of the filesystem path :
import myPrefix 1.0 as MyNamespace
You can also import simple QML files and not as a module :
// Because the path is relative to main.qml even in a qrc
import "myPrefix" as MyNamespace
Then you don't need the qmldir at all.
From documentation:
The module's qmldir file must reside in a directory structure within the import path that reflects the URI dotted identifier string, where each dot (".") in the identifier reflects a sub-level in the directory tree. For example, the qmldir file of the module com.mycompany.mymodule must be located in the sub-path com/mycompany/mymodule/qmldir somewhere in the import path.
So you should change module MyModule to module Config or import it within specific path:
import "./Config" as MyModule
if this is still an issue for anyone, you to right click on the file and select add file to directory. then you select the directory you wish to add the qml file in. this directory should be the same as the main qml file. doing this solved my problem

How can I organize files under the qml.qrc folder in Qt Creator?

If I have a bunch of resources (images, fonts, etc.) in different folders under my qml.qrc file, is there a way to organize this within Qt Creator?
For example, if I have the following in my qml.qrc file:
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>pages/MainPage.qml</file>
<file>pages/NewContactPage.qml</file>
<file>images/plus.png</file>
<file>images/minus.png</file>
<file>images/exit.png</file>
</qresource>
</RCC>
It will show up as a long list in Qt Creator, like this:
Resources
qml.qrc
/
main.qml
pages/MainPage.qml
pages/NewContactPage.qml
images/plus.png
images/minus.png
images/exit.png
Since this list can get really long over the duration of the project, it would be nice if these were organized better and split into folders like they are in my directory. Any ideas?
Actually, I'd highly recommend that non .qml assets to be put in a different resource file altogether, because large files will gut application build times. What happens is even a tiny change to a qml source will result in recompilation of the entire resource file. If assets are in a different resource file they are not continuously recompiled.
This will also effectively achieve organization in addition to significantly improving build times.
I just discovered an awesome way to do it. What's weird is that nobody else suggested it, when it's so completely trivial. Perhaps it didn't work in old versions of Qt/Qt Creator but now it does.
Here it is:
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>test/test.txt</file>
</qresource>
</RCC>
The test dir needs to exist and needs to contain test.txt.
No need for creating separate <qresource> tags with different prefixes. No need for alias attributes.
The files are cleanly organized in the filesystem and in the project explorer and you can access them from code with clean paths like :/test/test.txt.
(this screenshot is of a project that has some extra files as well - ignore those)
Bonus: You can rightclick on the "test" folder in the project explorer in Qt Creator and choose "Add new...", this does put the newly created file in the right place in the filesystem. Unfortunately it doesn't appear in the qrc subtree in the project explorer, only in a separate "Other files" subtree. You need to rightclick "qrc.qml" in the project explorer and choose "Add existing files" to make the file appear in the qrc subtree like it should. So it's a bit buggy/messy but when you learn how to use it, it's workable.
Bonus 2: You can import (add) an existing file/dir (which reside in any (sub-)sub-dir of the qrc file) and the right XML syntax will be generated, resulting in the right tree structure in the project explorer.
What I think doesn't work well:
Creating a file from Qt Creator from File -> New file or project (or Ctrl-N). This doesn't let you put the file in an arbitrary dir in the filesystem, only in the root project dir.
Files that you've put in subdirs aren't included in Qt Creator's project-wide search (Ctrl+Shift+F).
Edit: I just noticed the OP is doing exactly what I suggest. In that case, he probably is using an older Qt Creator version. Mine is 4.1.0.
If you want to use qrc files but don't like paths like "images/icons/images/icons/icon.png/" use alias as described here
<qresource prefix="/images">
<file alias="cut.png">images/cut.png</file>
</qresource>
With alias you can use your file by neatly writing /images/cut-img.png instead of /images/images/cut.png
From the Qt documentation: The Qt Resource System
By default, resources are accessible in the application under the same file name as they have in the source tree, with a :/ prefix, or by a URL with a qrc scheme.
It is also possible to specify a path prefix for all files in the .qrc file using the qresource tag's prefix attribute:
this example show how to do it:
<RCC>
<qresource prefix="/pages">
<file >pages/MainPage.qml</file>
</qresource>
<qresource prefix="/images">
<file >images/plus.png</file>
</qresource>
</RCC>
Another nice way to view your project files / folders as they appear on your File System is to do this:
Open your project
Click on the drop down menu which is above your project name, as demonstrated in the image below:
Done, now you can see your files and folders as they appear on your FS

Resources