Register custom qml component using plugins
-
I recently started learning QT6 for a project I am working on.
I am trying to create a GUI that contains some buttons and eventually text boxes too. In order to create the buttons, I created my custom qml component.
The code for this button is as following:import QtQuick 6.6 import QtQuick.Controls import QtQuick.Controls.Material import MyCustomButton Item { width: 300; height: 200 objectName: "root item" MyCustomButton { id: button Material.background: Material.Red width: 50 height: 50 name: "test" objectName: "MyCustomButton" } Text { id: name text: button.name // Bind to the parent's text property color: "black" anchors.centerIn: button // Center text within the button objectName: "MyCustomButtonText" } MouseArea { id: mouseArea anchors.fill: button onClicked: { button.buttonClicked() } objectName: "MyCustomButtonMouseArea" } }
At first I had this inside the project I was working on. But I want to be able to register it as a custom component. So in order to do this, I tried to create a plugin from it. So I created a new project with qt quick2 plugin as a template.
So the above code is now inside its own project. The custom button also contains some c++ code, which are also now inside the plugin project.
MyCustomButton.hpp:#ifndef MYCUSTOMBUTTON_HPP #define MYCUSTOMBUTTON_HPP #include <QObject> #include <QtQuick/QQuickPaintedItem> class MyCustomButton : public QQuickPaintedItem { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName FINAL) Q_PROPERTY(QColor color READ color WRITE setColor FINAL) QML_ELEMENT public: MyCustomButton(QQuickItem *parent = nullptr); void paint(QPainter *painter) override; QString name() const; void setName(const QString &name); QColor color() const; void setColor(const QColor &color); Q_INVOKABLE void buttonClicked(); void changeValue(); private: QString m_name; QColor m_color = Qt::red; bool m_value = false; public slots: void ButtonClicked(); }; #endif // MYCUSTOMBUTTON_HPP
And the MyCustomButton.cpp
#include "mycustombutton.h" #include <QPainter> #include <QDebug> MyCustomButton::MyCustomButton(QQuickItem *parent) : QQuickPaintedItem(parent) { } void MyCustomButton::paint(QPainter *painter) { QPen pen(m_color, 2); painter->setPen(pen); painter->setBrush(m_color); painter->setRenderHints(QPainter::Antialiasing, true); painter->drawEllipse(boundingRect().adjusted(1, 1, -1, -1)); } QString MyCustomButton::name() const { return m_name; } void MyCustomButton::setName(const QString &name) { m_name = name; } QColor MyCustomButton::color() const { return m_color; } void MyCustomButton::setColor(const QColor &color) { m_color = color; } void MyCustomButton::buttonClicked() { qInfo() << "m_value before: " << m_value; m_value = !m_value; m_color = m_value ? Qt::green : Qt::red; update(); qInfo() << "m_value after: " << m_value; } void MyCustomButton::changeValue() { buttonClicked(); } void MyCustomButton::ButtonClicked() { buttonClicked(); }
It successfully builds. However, when I try to load the plugin from my other project, it is unable to load it.
MyCustomButton.qml from other project:import QtQuick 6.6 import QtQuick.Controls import QtQuick.Controls.Material // import MyCustomButton import com.wago.MyCustomButtinLibrary Item { width: 300; height: 200 objectName: "root item" MyCustomButton { id: button Material.background: Material.Red width: 50 height: 50 name: "test" objectName: "MyCustomButton" } }
I get the following error
module "com.wago.MyCustomButtinLibrary" is not installed
I tried to follow the tutorials mentioned in here, but unfortunately I was not successful. From what I understand, the custom plugin should be located in the installation path from QT. However, I was unable to find it in there. Anyone got any clue where this might go wrong?
-
- Create the directory called com/wago/MyCustomButtinLibrary
- Do you have qmldir with description of plugin ?
- Did you copy this to com/wago/MyCustomButtinLibrary ?
- Did you import the path where plugin is kept ?
-
Thank you for your help. I didn't know that if the URI is for example com.example.button that com and example were subfolders. I must have missed that somewhere.
It was indeed not in subfolders, so I tried to add the subfolders without success.
So I tried removing the subfolders and also setting the URI to MyCustomButton2.
This works, however now I don't have the subfolders. However, I still want it to organize the components.So now my CMakeLists.txt looks the following:
cmake_minimum_required(VERSION 3.16) project(MyCustomButton2 VERSION 0.1 LANGUAGES CXX) set(CMAKE_AUTOMOC ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) find_package(Qt6 6.2 COMPONENTS Quick REQUIRED) qt_add_library(MyCustomButton2 STATIC) qt_add_qml_module(MyCustomButton2 URI MyCustomButton2 VERSION 1.0 QML_FILES MyCustomButton2Controls.qml SOURCES mycustombutton2.cpp mycustombutton2.h SOURCES mycustombutton2.cpp ) set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/plugins ${CMAKE_BINARY_DIR}/plugins CACHE STRING "" FORCE) set_target_properties(MyCustomButton2 PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) target_compile_definitions(MyCustomButton2 PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>) target_link_libraries(MyCustomButton2 PRIVATE Qt6::Quick) target_include_directories(MyCustomButton2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # Example Project qt_add_executable(ExampleProject example/example.cpp) qt_add_qml_module(ExampleProject URI ExampleProjectApp VERSION 1.0 QML_FILES example/example.qml ) target_link_libraries(ExampleProject PRIVATE Qt6::Quick MyCustomButton2plugin) target_compile_definitions(ExampleProject PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
From what I understand, I only have to change the following line:
qt_add_qml_module(MyCustomButton2 URI MyCustomButton2 VERSION 1.0 QML_FILES MyCustomButton2Controls.qml SOURCES mycustombutton2.cpp mycustombutton2.h SOURCES mycustombutton2.cpp )
To
qt_add_qml_module(MyCustomButton2 URI plugins.MyCustomButton2 #[[ Note I have changed this line]] VERSION 1.0 QML_FILES MyCustomButton2Controls.qml SOURCES mycustombutton2.cpp mycustombutton2.h SOURCES mycustombutton2.cpp )
In the example.cpp I have changed
Q_IMPORT_QML_PLUGIN(MyCustomButton2Plugin)
to
Q_IMPORT_QML_PLUGIN(plugins_MyCustomButton2Plugin)
and finally I changed inside the example.qml this line:
import MyCustomButton2
to
import plugins.MyCustomButton2
The folder structure looks like this:
However, when I try to run it I get the following error:
09:32:28: Starting C:\Users\dismienk\Documents\build-MyCustomButton2-Desktop_Qt_6_6_2_MinGW_64_bit-Debug\ExampleProject.exe... QQmlApplicationEngine failed to load component qrc:/ExampleProjectApp/example/example.qml:13:5: Type MyCustomButton2Controls unavailable qrc:/plugins/MyCustomButton2/MyCustomButton2Controls.qml:4:1: module "MyCustomButton2" plugin "MyCustomButton2plugin" not found
I also followed the following page. I set the path as following
set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/plugins ${CMAKE_BINARY_DIR}/plugins CACHE STRING "" FORCE)
This fixed the issue inside the Qt Creator itself (I got a warning that it was unable to find the plugin), but unfortunately not when running the program.
Again, thank you for your time to help me :)
-
So I solved the issue kind of. Instead of having 2 different project, I just moved them to 1 single project and now it works. I have another issue, but I'll make a new thread since this one is solved.
-