How to use/include qml module in CMake desktop application - qt

I’m relatively new to Qt and QtQick in particular and am trying to render a PDF file in my qml application (OS: Win10, platform: Desktop). To achieve this I built QtPdf following the instructions in the Qt Wiki.
My project structure is as follows:
|myProject
|-- qml
|-- QtQuick
|-- Pdf
qmldir
plugins.qmltypes
pdfplugin.dll
[...]
main.cpp
main.qml
someComponent.qml
[...]
I’m building with CMake and added the import path like it is described here:
set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/qml ${CMAKE_BINARY_DIR}/imports CACHE STRING "" FORCE)
And I imported the module in my qml files using
import QtQuick.Pdf 5.15
Sadly I get a “QML module not found” exception. Obviously I’m missing something important and would be grateful if someone could point me to it.
If something is unclear or you need more information or code snippets from any files, I'm happy to provide the information needed.

Related

How do I make my own directory in QT QML?

I'm trying to make a directory of a singleton QML File "All.qml" which I can import anywhere else into my project so that I can access its objects (namely the drawer). I made a qmldir file, in the same folder as the "All.qml", and even add the directory to the .qrc file.
The contents of the directory is as follows:
Module App.Drawer
singleton All 1.0 All.qml
But when I type in
import App.Drawer. 1.0
It says "module 'App.Drawer' not installed". I can't find any other way to access that drawer, as the project is huge with multiple folders and directories. Can anyone help me?
Also, this project has C++ integrated with it. I tried going and finding some file where maybe the other directories (there are other custom directories, which were made beforehand) have been installed, but couldn't find any.
You have to make sure that QEngine can find the qmldir file, and it has some specific requirements on where it will look.
First to make QEngine aware of the qmldir file you have to add an import path:
engine.addImportPath("qrc:/");
Your path may vary, read on:
The qmldir file has to placed in the folder structure dictated by module name. In your case it is <rootPath>/App/Drawer/qmldir. The "rootPath" is unknown to me, but let's assume you have the following in your qrc file:
<RCC>
<qresource prefix="/ProjectX/App/Drawer">
<file>Drawer.qml</file>
<file>qmldir</file>
</qresource>
</RCC>
Then "rootPath" is qrc:/ProjectX and the import call becomes:
engine.addImportPath("qrc:/ProjectX");
Also, the module declaration in qmldir should be the same as the folder structure where the qmldir file is placed. (And I think it should be lowercase)
module App.Drawer
singleton Drawer 1.0 Drawer.qml
If you want Qt Creator to also find the stuff you can use the QML2_IMPORT_PATH environment variable and set it to the correct folder using the same logic.
You can also place the files in the <Qt_installation_folder>/qml/App/Drawer but this means every project can use it and you have to keep it up-to-date during development, which might be overdone.
Edit
To see if your files are lined up correctly, you can add this debug code:
QDirIterator it(":", QDirIterator::Subdirectories);
while (it.hasNext()) {
qDebug() << it.next();
}

Is there any way to import a folder containing Qml files, which is outside of project directory?

I have a set of Qmls which are available in a folder. Now I want to use these Qml files in a Qt project. Is there any way to import those QMLs in my project without copying the Qml folder to my project directory?
My .pro file looks like this:
RESOURCES += qml.qrc
RESOURCES += $$PWD/../QML_Assets
QML_IMPORT_PATH = $$PWD/../QML_Assets
QML2_IMPORT_PATH = $$PWD/../QML_Assets
The immediate qrc generates like this :
D:/Qt_Projects/Dummy_sample/QML_Assets/QML_2.qml
D:/Qt_Projects/Dummy_sample/QML_Assets/QML_1.qml
If i add import "../QML_Assets/" then my application starts & exits immediatly.
If I dont import this & comment the components which are used from QML_Assets folder then it works.
There is are couple of possibilities to do that in Qt.
First you can set variables in your Qt project file (.pro) to add QML imports paths.
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
QML2_IMPORT_PATH =
You can also do that directly in c++ code with QQmlEngine::addImportPath before constructing/starting your Qml view
You can then check wich import paths are set for your app with QQmlEngine::importPathList
Here is Qt documentation about Import Statements and QML Import Path specifically
And even more specific: Importing QML Document Directories

QML module not found when using KDE Kirigami

So I decided to use KDE Kirigami UI framework in my app so I followed the instructions here. I cloned the repo in my app directory and then added it with a simple include(kirigami/kirigami.pri) in my project file.
Now this works, however the problem I encountered is that in QML there is always the error: QML module not found when I import the plugin (import org.kde.kirigami 2.9). The project still compiles and runs just fine and I am able to use the UI components I need, however the major issue is that code completion and syntax highlighting for the Kirigami plugin do not work.
A similar question has been asked before here, I have tried all the suggestions in the answers of that thread but none of them worked:
I imported QQmlEngine::addImportPath the kirigami/src/controls folders using absolute and relative paths. I also tried with qrc:/.
I added a QML_IMPORT_PATH += $$PWD/kirigami/src/controls $$PWD/kirigami line to my project file.
When you mouse over the "module org.kde.kirigami not found" error marker in a QML file, the popup tells you that Qt Creator is looking in QML_IMPORT_PATH for these files. It also tells you how to set this.
By adding QML_IMPORT_PATH += … to your project file, you have set it for a qmake based build process. However, Kirigami projects usually use CMake, and that might be the reason why your previous attempts did not work out.
To set QML_IMPORT_PATH for a CMake based build system, you would open the CMakeLists.txt file from the root of your project tree and add the following section on top:
# ------------------------- BEGIN: lists to maintain manually -------------------------
# Directories where Qt Creator can find QML files of Kirigami etc. on your system.
# (This setting is cached in variable QML_IMPORT_DIR, see below. Delete
# ${BUIL_DIR}/CMakeCache.txt to make make changes here effective.)
list(APPEND QML_DIRS "/usr/lib/x86_64-linux-gnu/qt5/qml")
# ------------------------- END: lists to maintain manually -------------------------
# Tell Qt Creator where to find QML files.
# (The build process will work without this, but no code completion etc..)
set(
QML_IMPORT_PATH "${QML_DIRS}"
CACHE STRING "Qt Creator 4.1 extra qml import paths"
)
Of course, adapt it to the correct directory for your system. On a Debian / Ubuntu based system, the following will determine the directory containing Kirigami QML files installed from the repositories:
dpkg -L qml-module-org-kde-kirigami2 | grep "\.qml"
Source: another answer on StackOverflow

Use a precompiled plugin (via a shared library) in a QML application

I have a QML plugin compiled (to a .so) by another project. I want to re-use this in my own QML application without re-building it each time. I want to copy the .so over and, with minimal additional code, be able to write:
import QQuickMapboxGL 1.0
at the top of my QML files and have it work.
Where do I need to copy the .so in my QML project, and how do I need to add it to the project so that the QML runtime can find it?
What I've tried:
Create a QQuickMapboxGL directory with libqmapboxgl.so in it.
Create a qmldir file in that directory with the contents:
plugin qmapboxgl
Add the following to my .pro file:
INSTALL_DIR = $$PWD/../install
target.path = $$INSTALL_DIR
# Copy the QQuickMapboxGL folder to the install directory
plugin.files = QQuickMapboxGL/*
plugin.path = $$INSTALL_DIR/QQuickMapboxGL
INSTALLS += target plugin
Add a make install build step.
The result of this mad hackery was:
plugin cannot be loaded for module "QQuickMapboxGL": Plugin verification data mismatch in '/my/build/QQuickMapboxGL/libqmapboxgl.so'
I have verified that the plugin and my application are both being compiled with the same version of g++ (g++-5 (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904) and the same Qt download (5.7.0).
The main problem is that the .so is not a QML Plugin; no class inherits from QQmlExtensionPlugin or related. It is just a shared library of code.
Was able to workaround this by:
Adding the header files for MapboxGL to my project
In my main.cpp:
#include "3rdparty/mapbox-gl-native/platform/qt/include/qmapbox.hpp"
Calling QMapbox::registerTypes(); (inside main)
Copying libmapboxgl.so (built via Mapbox's make/cmake) inside a libs directory.
In myproject.pro adding: LIBS += -L./libs -lqmapboxgl
In my QML code import QQuickMapboxGL 1.0 and then using MapboxMap
Copying libmapboxgl.so to somewhere that is referenced by LD_LIBRARY_PATH

Qt5 QML module is not installed

I'm confused about modules in Qt QML. I've read all the docs, but it doesn't make clear some basic ideas.
I understand that i can put a bunch of QML files into a directory and add a qmldir file to describe an identified module. When i do this and adjust the QML_IMPORT_PATH, QtCreator is happy and stops underlining the import ModuleName 1.0 line.
So creator is happy, but it does not work. I get module is not installed.
my questions are:
what does it mean by "installed". I have directory of files, but i haven't "installed" them anywhere.
should i be building/compiling the module to make a DLL/.so ?
does the module QML files go into the resources of the main app, otherwise where are they to be found?
my main.qml file is part of the app resources, how does the app locate the resources of the module at runtime.
Sorry, for all these questions, but the basics of these modules is just not clear. I don't understand if a "module" is just the sharing of files or is it a compiled unit.
thanks for any help.
I'll try to answer your questions:
I think installed means they are located in the proper paths, so
that they can be found at runtime
You should not necessarily create/build a QmlExtensionPlugin for that purpose. You can also use as a module plain QML files in one
directory with a qmldir describing this module. It is a matter of
distributing your code. With QmlExtensionPlugin you provide the
module compiled, if you want to hide the code.
The modules can be in resources system or as files on disk, it is up to you.
The app looks for modules in predefined paths - in your app's directory, in Qt plugins path, in QML2_IMPORT_PATH, in directories that you added using engine->addImportPath()
There are a bunch of things that can lead to a module not being loaded. You can check the following:
Module identifier in qmldir should be the same as the directory
name, where the module actually resides. For example if your module
has module identifier module Test.Module in qmldir, your module's
relative path must be Test/Module.
If it is a QML extension
plugin (shared library), make sure that plugin's directory name is
the same as plugin's name.
export QML2_IMPORT_PATH (make sure there is 2 in the name) env variable to point to directory containing your module. There is also a QQmlEngine::addImportPath method, which adds the directory to the list to lookup for plugins.
If it is a qml extension plugin (shared library), then there might be missing dependencies for it. You can check it by Dependency Walker on Windows or ldd command on Linux.
Setting QT_PLUGIN_PATH runtime variable may help to load plugins. It should point to a directory containing you plugin's directory, not the plugin's directory itself.
You can also enable traces to see what's going on while plugins are loaded for better understanding of the problem - export QT_DEBUG_PLUGINS=1 and QML_IMPORT_TRACE=1 environment variables
You can also read this link:
https://doc.qt.io/qt-5/qtqml-modules-identifiedmodules.html
In my case (I have all QML files in qrc resources) worked to add qmldir to resources also and call method addImportPath("qrc:/") of QQmlApplicationEngine.
My main.cpp looks like:
QQmlApplicationEngine engine;
engine.addImportPath("qrc:/");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
Important parts of my .pro file looks like:
RESOURCES += qml.qrc \
MyModule/mymodule.qrc
QML_IMPORT_PATH += $$PWD
My qmldir:
module MyModule
MyItem 2.0 MyItem20.qml
MyItem 2.1 MyItem21.qml
My qrc:
<RCC>
<qresource prefix="/MyModule">
<file>MyItem20.qml</file>
<file>MyItem21.qml</file>
<file>qmldir</file>
</qresource>
</RCC>
And finally my main.qml:
import QtQuick 2.5
import QtQuick.Window 2.2
import MyModule 2.0
Window {
visible: true
width: 640
height: 480
MyItem {
anchors.fill: parent
}
}
QtCreator is happy (not underlining components and imports) and module is loaded.
Hope this helps.
I want to expand on arxarian's answer - which I think is the best technique for integrating modules - but couldn't fit those thoughts in a comment, so here's a new answer.
It's important to first understand that qml modules and their associated resources are runtime entities and are assumed to separately exist at some location relative to the executable unless they're included in the application resources. By including them in the resources, they are still runtime entities, but they exist under the qrc:/ root path within the application binary. This hiding of the modules is the primary reason why I think this is the best technique, unless you want your modules to be open to revision after deployment, or to be independently deployable as precompiled plugins (i.e., in the resource storage of a dynamically linked library).
So here's my explanation of the important elements of arxarian's answer:
engine.addImportPath("qrc:/"); is needed in the C++ code prior to loading the qml to instruct the engine to look for qml modules in the application resource storage.
RESOURCES += MyModule/mymodule.qrc is needed in the project (.pro) file to add the module's files to the application resource storage.
QML_IMPORT_PATH += $$PWD in the project file tells Qt Creator to look for the module starting from the root of the project source tree. In my case I had to set this to a subdirectory (e.g., "ui/modules") because my module directories started there. The import path should include the root(s) beneath all module directories. As far as I can tell, this instruction is only for the Qt Creator IDE and does not impact the build - that's why #1 is needed.
The contents of the qmldir file is as is standard for all qml modules, but it's inclusion in the module's .qrc resource file is not intuitive until you think about what's happening with runtime storage. It needs to be in the .qrc so that it is included in the application resource storage, so that the engine can find it at runtime to define the module. <qresource prefix="/MyModule"> in the module's .qrc file defines the module subdirectory relative to the qrc:/ root in the application resource storage.
The import MyModule <version> statement in qml is now setup for success. On startup the engine will have located the module in its directory under qrc:/, parsed the qmldir file there to define the module and established the name and version from those entries.
Hopefully this helps others understand what's going on, and please let me know if I've misunderstood anything.
A similar issue cost me a bit of time so I just post it here to perhaps save the next guy some effort.
My problem was that an invisible character had sneaked into the module name. Probably through copy and paste. Here my issue:
Example error output:
MyEngine failed to load component
qrc:/qml/main.qml:53 Type MyComponent unavailable
file:///Users/<pathToProject>/MyProject/qml/MyModule/MyComponent.qml:-1 No such file or directory
It all looks fine and the path displayed is indeed the correct one. So what is wrong?
Now, copy that path to a Terminal window:
file:///Users/<pathToProject>/MyProject/qml/MyModule/<feff>MyComponent.qml
There it is, the:
"<feff>"
Solved the issue by manually retyping the component name in the qmldir file, and thus effectively deleting the invisible character.
I had the same problem and have now fixed it. I found a QML plugin for iOS. There are several things that need to be taken care of:
1. The plugin pro file needs an addition:
uri = IosTestPulgin
# this for error:
# static plugin for module “QtQuick” with name “IosTestPulgin”
# has no metadata URI
QMAKE_MOC_OPTIONS += -Muri=$$uri
# thanks from:https://github.com/wang-bin/QtAV/issues/368
2. The QML plugin qmldir file needs an additional line like this:
classname IosqmlpluginPlugin
# for ERROR: Plugin iostestqmlplugin is missing a classname entry,
# please add one to the qmldir file.
# look for qt document http://doc.qt.io/qt-5.6/qtqml-modules-qmldir.html
3 The client project pro file needs an addition like this:
ios {
IOSTestPlugin_BUNDLE.files += $$files($$[QT_INSTALL_QML]/IosTestPulgin/qmldir)
IOSTestPlugin_BUNDLE.path = IosTestPulgin
QMAKE_BUNDLE_DATA += IOSTestPlugin_BUNDLE
}
# for ios error: module is not installed
# this means external qml static plugin must add the plugin dir by manual
# in the app root dir

Resources