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
Related
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();
}
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
I have built a static Qt library and want to use it deploy my app with a standalone exe. After one day effort, I have known that the qtquick plugin can not be static include into exe.
I need copy some folders in qml folder to my exe directory to let the exe can show GUI.
So I want to know which file my exe need, I deleted files in those folders one by one to get it known. The real needed file is just a plugins.QMLTYPES file and a qmldir file.
And then I found the import path of QQmlApplicationEngine can be changed, I output the QQmlApplicationEngine.importPathList() and one of paths is just the qml folder in Qt installed path. So I think this is the place where Qt get the search path of plugins.QMLTYPES file and qmldir file.
If all I think is correct, I can just copy the folders I need into qrc file and use QQmlApplicationEngine.addImportPath("qrc:/foldersIwant") to let exe can import what it need on runtime. And because qrc is compiled into exe, I can get rid of those folders and let my exe standalone.
But after I do this in my code, app still can not find the files it need even the output of QQmlApplicationEngine.importPathList() has the path I put into and I have also checked my path according to Load qmldir from QRC file.
Here is the code:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.addImportPath(QStringLiteral("qrc:/import/qtquick/"));
qDebug()<<engine.importPathList();
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
return app.exec();
}
Here is a part of my qrc file
Is there anything wrong in my deductive?
Further research:
I have add
engine.addImportPath(QDir::currentPath() + QDir::separator() + "custom");
and move all folders into custom folders, it can run successfully. And the exe which doesn't have this line can not run with custom folder. So I'm wondering the "search" behavior can not be applied to qrc file ?
Finally, I get the answer. The result shows all my thoughts are correct!
Below is what I had tried and you can just read the end to get the clear steps.
My aim is to compile a standalone qml2 application exe.
In qml1, I can build static Qt library and compile my app with it.
In qml2, the exe can be compiled in same way. But if I run it without Qt-Runtime. It just do not have any window shown on Windows OS (and also show nothing in other OS). I have googled so many informations and found this problem troubled many people since Qt5.0. Now it is Qt5.5, they still haven't repaired it. So I need copy folders in QT_INSTALLED_PREFIX/qml to the root directory of my app to let my app show GUI.
Althrough the problem will be solved in Qt5.6 (https://codereview.qt-project.org/#/c/114835/), I can't wait for so long (Qt5.6 will be released at the end of this year). So I decide to package the files by myself.
And I see this question by chance :Load qmldir from QRC file. It told me that qmldir file can be include into qrc file and the Qml engine can search into those directory. So I think, the QML files can also be included into qrc file.
But the first thing is to find where the qml2 be imported, when I looking into QQmlApplicationEngine's document, I found addImportPath function and I told myself that it must be the key of finding the import path. The document tells me everything:
QStringList QQmlEngine::importPathList()
const Returns the list of
directories where the engine searches for installed modules in a
URL-based directory structure.
For example, if /opt/MyApp/lib/imports is in the path, then QML that
imports com.mycompany.Feature will cause the QQmlEngine to look in
/opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
provided by that module. A qmldir file is required for defining the
type version mapping and possibly QML extensions plugins.
By default, the list contains the directory of the application
executable, paths specified in the QML2_IMPORT_PATH environment
variable, and the builtin Qml2ImportsPath from QLibraryInfo.
After I delete the Qml2ImportsPath in importPathList at runtime, I made a recurrence of the bugs that app do not show any GUI.
And the document of addImportPath tells my that it can accept qrc url. So I add all the files in qml just like the question described above. But I still cannot see any GUI.
After several days of thinking. I found the pic I posted in question do not have qmldir files! That's a bug of Qt Creator. I add files using Add Existing Directory... and set the filter to *, it still cannot include qmldir file. So I add it into qrc file by xml code.
When I think this time it must work, it just gave me nothing. Just when I was going to give up, a thought occurred : it won't waste me more time to check whether qrc:/import/qtquick/ is valid.
The result is false, there must be a mistake in my qrc usage. I change the prefix and save the qrc with Qt Creator. I found the qrc file cannot use the path like D:/Qt/Qt-5.5-static/qml/Qt/labs/folderlistmodel/plugins.qmltypes, it is changed by Qt Creator to Qt/labs/folderlistmodel/plugins.qmltypes. At this time, everything works perfect!
Thanks for you reading my story. Here is a conclusion of steps for solving this problem:
Copy all folders in QT_INSTALLED_PREFIX/qml to your project folder, it is good to put them under a parent folder not the root folder.
Write some code to get all files' relative path except the .lib files and
.prl files.
Create a new .qrc file and include it in .pro file. Include all files into this .qrc file. I wrote a small program to generate the xml.
Add the import path using addImportPath method of QQmlApplicationEngine.
Build and enjoy.
So, I just made a standard, QtQuick 2 application, it has the default Recangle, Text and MouseArea. So, I just tried to compile the application in release mode, to see what files it would generate, and then I tried opening the application and this happened:
When I resize it, I cans see white space:
However it all works fine in debugging:
I am using Qt 5.0.1 and QtQuick2
Update
So, after running it through Dependency Walker it appears like there are three files missing: qt5quick.dll, qt5gui.dll, and qt5core.dll. Do I have to manually add them from somewhere?
The current directory structure is:
`test-build-Desktop_Qt_5_0_1_MSVC2010_32bit-Release/release
|+qml
|+test
|-main.qml
|-main.obj
|-moc_qtquick2applicationviewer.cpp
|-moc_qtquick2applicationviewer.obj
|-qtquick2applicationviewer.obj
|-test.exe
|-test.exe.embed.manifest
Note: I pasted the qml directory as suggested in Nemanja Boric's answer from the parent directory, but that didn't solve the problem! :(
Also, I was under the impression that none of the source (apart from JavaScript maybe) wouldn't be openly distributed with the app, but compiled or packed inside the application somehow (note the .cpp file and the qml directory)?
Update 2
The application works just fine when run from inside Qt 5 Creator:
Starting [...]\test-build-Desktop_Qt_5_0_1_MSVC2010_32bit-Release\release\test.exe...
QOpenGLShader::link: "(41,18): warning X3206: implicit truncation of vector type
"
[...]\test-build-Desktop_Qt_5_0_1_MSVC2010_32bit-Release\release\test.exe exited with code 0
Well, apart from that one awkward warning...
You need to copy qml files into your current directory. When you create release application with QtCreator, you will have this directory structure (or something like this):
example-build-Desktop_Qt_5_0_1_MSVC2010_32bit-Release
|- debug
|- qml
|- release // application executable is here
What you need to do is to copy qml folder to be in the same directory with your executable release file (simply copy qml folder into release folder).
About dll files - you can copy them manually from QtInstallDir/bin folder or you can add that directory into PATH, if you are developing on that machine - it could be easier.
You don't need to publish cpp files, but you need to publish qml files. What you can do, through I never succeed, but it seems to be possible is to bundle qml files into Resource file, and to load it from resources, but that can be extracted easily, too - so - don't put your logic or confidential informations in qml files.
Also, you need to copy all required dll files into directory with exe: qt5quick.dll, qt5gui.dll, qt5core.dll and libEGL.dll.
I'm trying to subclass from ProjectExplorer::ProjectExplorerPlugin but I'm getting error telling me about undefined references. Any ideas how to fix it?
class MyPluginPlugin : public ProjectExplorer::ProjectExplorerPlugin
{
Q_OBJECT
...
};
error: undefined reference to `imp__ZN15ProjectExplorer21ProjectExplorerPluginC2Ev'
The fact that you don't get a compilation error, but an undefined reference usually means that your project knows where the header files are, but it doesn't know where the library is which contains the already compiled source code.
I've never written a plugin for Qt Creator but I've taken a quick look at its source code structure and I see the following options:
Option A)
There is a projectexplorer.pro file in Qt Creator's source under src/plugins/projectexplorer. You could manually build that project in order to get a ProjectExplorer.lib (plus a .dll or a .a) and then reference this library.Example: Assuming the library would be created in the same directory as its .pro file (I have no idea if it is like that) and you created your plugin withing Qt Creator's source under src/plugins/myplugin, you would define your LIBS variable like this:
LIBS += -L../projectexplorer \
-lProjectExplorer
The first line adds "../projectexplorer" as an additional library directory and the second line adds "ProjectExplorer" as a library to search in any of the defined directories (it automatically adds the OS-specific file extensions like .lib on windows etc).
Obviously if your project or the library is located somewhere else, you need to change the first line accordingly.
Option B)
You could include the source and header files of the projectexplorer directory to your own .pro file using the HEADERS and SOURCES variables. I'm not sure if this wouldn't interfere with any other plugins (including projectexplorer itself) though.
Option C)
There probably is a way to include the projectexplorer.pro file so that you have a master project which first builds the project explorer library and then your own plugin. This would be the safest way to go as it ensures the Project Explorer library is built and up-to-date before your own project is linked against it.
However I have limited experience on this.
If anyone reading this can give a detailed explanation on this option, feel free to edit or provide your own answer.
If you are using Qt Creator built from source coded after April 2013 which includes Commit: #66a3553 - make library and plugin dependencies declarative, then you can simply specify dependencies for your plugin in its .pro file:
# myplugin.pro
QTC_PLUGIN_DEPENDS += \
coreplugin \
projectexplorer