Creating custom modules
-
Thanks for the help, I appreciate it. First time using modules and I'm learning a lot
What I've learnt so far:
- Using qt_add_qml_module automatically makes a qmldir and QResources file
- Cmake file for our project needs this to include a module with our library
add_subdirectory(<FolderOfModule>) target_link_libraries(<applicationLibrary> PRIVATE <UriOfModule>plugin)
- Our module needs to be in it's own folder. Put CMake file, QML files, and resource files we're using for that module
- Cmake file for our QML module needs this
qt_add_qml_module(<NameOfModule>) URI <ImportNameOfModule> VERSION <VersionNumber> RESOURCE_PREFIX <Prefix> QML_FILES <QML_Files> RESOURCES <Resource_Files>
- Perhaps it also needs this
qt_add_library(<NameOfModule> STATIC) set_target_properties(<NameOfModule> PROPERTIES AUTOMOC ON) target_link_libraries(<NameOfModule> PRIVATE Qt6::Quick )
-
Can optionally specify an output directory too it seems
-
QML file where we include our module needs this
import <ImportNameOfModule> <VersionNumber>
Then if we want to use a custom QML element from our module, we refer to it by it's like filename without the extension
Will also need to make this addition to our main.cpp file
engine.addImportPath("qrc:/");
Without this, we'll get a "is not a type" error
If there's anything else I might not know about modules, let me know and I'll check it out. Think I've made some progress with them now at least. Was using import paths before but modules are what I'm trying to replace all of that with
Got a module in one's actual project to work as opposed to a project consisting merely of a test module. So many things to get right between the cpp, qml, cmakelists, auto generated QResourceFile, and sci file too in this case
My module was a text input module. It has a text input base QML file and email text input QML file that inherits from this base. And it uses a border image so that's why there's a .sci resource for that
Now I'll have to do all of the other modules too
-
Good morning,
On a general note, please don’t expect volunteers to cross read an entire github project. Instead, please isolate your issue in a minimal reproducer.
Have you read this documentation about creating QML modules?
It’s a good step-by-step tutorial covering both QML and C++ based modules.
Without having read through your entire code I would say that there is something wrong in the file structure.
-
Thanks for the help Axel, I tried following that example instead of trying to make use of qmldir files and whatnot, and then trying to use AI for debugging - it has no idea what it's doing. And some progress was made with that approach. Now have working code on how to add a custom QML module but the IDE still whinges for some reason but it runs so I'm assuming there's no problems
ExtraModule/CmakeLists.txt
qt_add_library(extra_module STATIC) qt_add_qml_module(extra_module URI "ExtraModule" VERSION 1.0 QML_FILES Extra.qml RESOURCE_PREFIX / )
ExtraModule/Extra.qml
import QtQuick Rectangle { width: 200 height: 50 color: "transparent" Text { anchors.centerIn: parent text: "Hello World" color: "red" font.pixelSize: 24 } }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml/QQmlExtensionPlugin> Q_IMPORT_QML_PLUGIN(ExtraModulePlugin) int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("testproj2", "Main"); return app.exec(); }
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(testproj2 VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.5 REQUIRED COMPONENTS Quick) qt_standard_project_setup(REQUIRES 6.5) qt_add_executable(apptestproj2 main.cpp ) qt_add_qml_module(apptestproj2 URI testproj2 VERSION 1.0 QML_FILES Main.qml ) add_subdirectory(ExtraModule) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. set_target_properties(apptestproj2 PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.apptestproj2 MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) target_link_libraries(apptestproj2 PRIVATE Qt6::Quick ) target_link_libraries(apptestproj2 PRIVATE extra_moduleplugin) include(GNUInstallDirs) install(TARGETS apptestproj2 BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
Main.qml
import QtQuick import ExtraModule Window { width: 640 height: 480 visible: true title: qsTr("Hello World") Extra { x: 200 y: 50 } }
What I see:
C:\Users\Certa\Desktop\projects\testproj2\Main.qml:3: warning: Warnings occurred while importing module "ExtraModule": [import] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:1: warning: Failed to import ExtraModule. Are your import paths set up properly? [import] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:13: warning: Extra was not found. Did you add all imports and dependencies? [import] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:13: warning: 'Extra' is used but it is not resolved [unresolved-type] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:13: warning: 'Extra' is used but it is not resolved [unresolved-type] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:13: warning: Type Extra is used but it is not resolved [unresolved-type] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:14: warning: Property "x" does not exist. [missing-property] C:\Users\Certa\Desktop\projects\testproj2\Main.qml:15: warning: Property "y" does not exist. [missing-property]
But when I run the program, it appears to be working
I suppose if we wanted to, we could add a qmldir file in ExtraModule folder. I assume it would look like this for our use case
module ExtraModule 1.0 Extra 1.0 Extra.qml
Just trying to understand the purpose of these files. I think I assumed it did more magic than what it does. But it's Cmake making it all work at compile time like we don't seem to need that file at all for it to run.
Based on documentation, it sounds like we could have two different versions of the module so I'll test that out
module ExtraModule Extra 1.0 Extra.qml Extra 2.0 Extra2.qml
https://doc.qt.io/qt-6/qtqml-modules-qmldir.html
Perhaps one with blue text and one with red text
CmakeLists.txt file in ExtraModule/
qt_add_library(extra_module STATIC) # Add the first version of the module qt_add_qml_module(extra_module URI "ExtraModule" VERSION 1.0 QML_FILES Extra.qml RESOURCE_PREFIX / OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/ExtraModule/v1/ExtraModule" ) # Add the second version of the module qt_add_qml_module(extra_module_v2 URI "ExtraModule" VERSION 2.0 QML_FILES Extra2.qml RESOURCE_PREFIX / OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/ExtraModule/v2/ExtraModule" )
Our Main.qml file, trying to have blue text with the v2.0
import QtQuick import ExtraModule 2.0 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") Extra { x: 200 y: 50 } }
Our ExtraModule/Extra2.qml file
import QtQuick Rectangle { width: 200 height: 50 color: "transparent" Text { anchors.centerIn: parent text: "Hello World" color: "blue" font.pixelSize: 24 } }
Then I see this error upon attempting to run that
Anyone have any insight on what I'm doing wrong there? And let me know if there's more applications for qmldir files than what I'm aware of, I mean aside from having two different versions of a module
-
The yellow warnings are a bug in Qt Creator's language server.
You can work around it by adding a boolean variable QT_QML_GENERATE_QMLLS_INI in your CMake config and set it totrue
.The static plugin error looks like something in your local configuration.
-
Okay, I suppose the versioning thing is a bit busted for me but I suppose if you really wanted to call a different file for the module, you could just refer to it by name instead of hoping that the version number would automatically grab it
Like supposedly import ExtraModule 1.0 should grab Extra.qml and import ExtraModule 2.0 should grab Extra2.qml but you can just use import ExtraModule 2.0 and call Extra or Extra2 in QML based on what you want instead of hoping that it can automatically get you the latest version based on your import statement
ExtraModule/qmldir
module ExtraModule Extra 1.0 Extra.qml Extra 2.0 Extra2.qml
ExtraModule/Cmakelists.txt
qt_add_library(extra_module STATIC) # Define the QML module with two versions qt_add_qml_module(extra_module URI "ExtraModule" VERSION 2.0 # The highest version you support QML_FILES Extra.qml # Version 1.0 Extra2.qml # Version 2.0 RESOURCE_PREFIX / ) # Install QML files and qmldir for both versions install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Extra.qml ${CMAKE_CURRENT_SOURCE_DIR}/Extra2.qml ${CMAKE_CURRENT_SOURCE_DIR}/qmldir DESTINATION ${CMAKE_INSTALL_PREFIX}/qml/ExtraModule # This is where the QML files are installed )
Main.qml
import QtQuick import ExtraModule 2.0 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") Extra2 { x: 200 y: 50 } }
So what I'm saying is can just say "Extra2", instead of leaving it as "Extra" and hoping that it'd like automatically get Extra2.qml file by typing Extra because we have ExtraModule 2.0, not ExtraModule 1.0
That gets us our blue text
-
Honestly, I have never come as far as to a use case where I needed a version dispatch to different files.
Somebody more experienced than me needs to answer this question....
Maybe @cristian-adam ? -
@Kory
I tried to understand the issue faced. Due to many things could not understand the real issue. Also git example was not accessible. Your interest is- Build the module with qml files.
- Use the module in another application. You would like to access the qml using qrc as well.
I have example to build module & use. It is in git. See if this meets your requirement.
https://github.com/QtDheeru/QtExamples/tree/master/QML/160067_Kory_Module -
Thanks for the help, I appreciate it. First time using modules and I'm learning a lot
What I've learnt so far:
- Using qt_add_qml_module automatically makes a qmldir and QResources file
- Cmake file for our project needs this to include a module with our library
add_subdirectory(<FolderOfModule>) target_link_libraries(<applicationLibrary> PRIVATE <UriOfModule>plugin)
- Our module needs to be in it's own folder. Put CMake file, QML files, and resource files we're using for that module
- Cmake file for our QML module needs this
qt_add_qml_module(<NameOfModule>) URI <ImportNameOfModule> VERSION <VersionNumber> RESOURCE_PREFIX <Prefix> QML_FILES <QML_Files> RESOURCES <Resource_Files>
- Perhaps it also needs this
qt_add_library(<NameOfModule> STATIC) set_target_properties(<NameOfModule> PROPERTIES AUTOMOC ON) target_link_libraries(<NameOfModule> PRIVATE Qt6::Quick )
-
Can optionally specify an output directory too it seems
-
QML file where we include our module needs this
import <ImportNameOfModule> <VersionNumber>
Then if we want to use a custom QML element from our module, we refer to it by it's like filename without the extension
Will also need to make this addition to our main.cpp file
engine.addImportPath("qrc:/");
Without this, we'll get a "is not a type" error
If there's anything else I might not know about modules, let me know and I'll check it out. Think I've made some progress with them now at least. Was using import paths before but modules are what I'm trying to replace all of that with
Got a module in one's actual project to work as opposed to a project consisting merely of a test module. So many things to get right between the cpp, qml, cmakelists, auto generated QResourceFile, and sci file too in this case
My module was a text input module. It has a text input base QML file and email text input QML file that inherits from this base. And it uses a border image so that's why there's a .sci resource for that
Now I'll have to do all of the other modules too
-