Solved Using qmlscene with QObject singleton type
-
Hello,
I have a qml app which use a QObject singleton in order to use existing C++ functionnalities.
My API is defined in C++ and imported in qml as described in qmlRegisterSingletonType documentation, and it works well when I run my application.
But when I want to use qmlscene, my module is not installed, and I don't know how to import it. In the documentation, the -I argument seems only applicable to qml module (in *.qml file). Any idea on how to import C++ QObject singleton type in qmlscene ?Thanks !
-
@Sh_sch You have to create a plugin and then use the -I option.
Demo:
TEMPLATE = lib TARGET = FooPlugin QT += qml quick CONFIG += plugin c++11 TARGET = $$qtLibraryTarget($$TARGET) uri = com.mycompany.qmlcomponents # Input SOURCES += \ fooplugin_plugin.cpp \ foo.cpp HEADERS += \ fooplugin_plugin.h \ foo.h DISTFILES = qmldir !equals(_PRO_FILE_PWD_, $$OUT_PWD) { copy_qmldir.target = $$OUT_PWD/qmldir copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir copy_qmldir.commands = $(COPY_FILE) "$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)" "$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)" QMAKE_EXTRA_TARGETS += copy_qmldir PRE_TARGETDEPS += $$copy_qmldir.target } qmldir.files = qmldir unix { installPath = $$[QT_INSTALL_QML]/$$replace(uri, \., /) qmldir.path = $$installPath target.path = $$installPath INSTALLS += target qmldir }
foo.h
#ifndef FOO_H #define FOO_H #include <QObject> class Foo : public QObject { Q_OBJECT Q_DISABLE_COPY(Foo) public: explicit Foo(QObject *parent = nullptr); ~Foo() override; Q_INVOKABLE QString bar() const; }; #endif // FOO_H
#include "foo.h" Foo::Foo(QObject *parent) : QObject(parent) { } Foo::~Foo() { } QString Foo::bar() const { return "baz"; }
fooplugin_plugin.h
#ifndef FOOPLUGIN_PLUGIN_H #define FOOPLUGIN_PLUGIN_H #include <QQmlExtensionPlugin> class FooPluginPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif // FOOPLUGIN_PLUGIN_H
fooplugin_plugin.cpp
#include "fooplugin_plugin.h" #include "foo.h" #include <qqml.h> static QObject *singletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) Foo *foo = new Foo(); return foo; } void FooPluginPlugin::registerTypes(const char *uri) { // @uri com.mycompany.qmlcomponents // qmlRegisterType<Foo>(uri, 1, 0, "Foo"); qmlRegisterSingletonType<Foo>(uri, 1, 0, "Foo", singletonProvider); }
So you create a folder with the following structure:
imports └── com └── mycompany └── qmlcomponents ├── libFooPlugin.so └── qmldir
Then you import the module in your main.qml:
import QtQuick 2.15 import QtQuick.Window 2.15 import com.mycompany.qmlcomponents 1.0 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") Component.onCompleted: console.log(Foo.bar()) }
And then you finally run:
qmlscene -I /path/of/imports main.qml
-
@Sh_sch
you need to create a QML plugin, that can be loaded by any QML application (such as qmlscene)
https://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html
or
https://doc.qt.io/archives/qt-5.9/qqmlextensionplugin.html -
@Sh_sch You have to create a plugin and then use the -I option.
Demo:
TEMPLATE = lib TARGET = FooPlugin QT += qml quick CONFIG += plugin c++11 TARGET = $$qtLibraryTarget($$TARGET) uri = com.mycompany.qmlcomponents # Input SOURCES += \ fooplugin_plugin.cpp \ foo.cpp HEADERS += \ fooplugin_plugin.h \ foo.h DISTFILES = qmldir !equals(_PRO_FILE_PWD_, $$OUT_PWD) { copy_qmldir.target = $$OUT_PWD/qmldir copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir copy_qmldir.commands = $(COPY_FILE) "$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)" "$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)" QMAKE_EXTRA_TARGETS += copy_qmldir PRE_TARGETDEPS += $$copy_qmldir.target } qmldir.files = qmldir unix { installPath = $$[QT_INSTALL_QML]/$$replace(uri, \., /) qmldir.path = $$installPath target.path = $$installPath INSTALLS += target qmldir }
foo.h
#ifndef FOO_H #define FOO_H #include <QObject> class Foo : public QObject { Q_OBJECT Q_DISABLE_COPY(Foo) public: explicit Foo(QObject *parent = nullptr); ~Foo() override; Q_INVOKABLE QString bar() const; }; #endif // FOO_H
#include "foo.h" Foo::Foo(QObject *parent) : QObject(parent) { } Foo::~Foo() { } QString Foo::bar() const { return "baz"; }
fooplugin_plugin.h
#ifndef FOOPLUGIN_PLUGIN_H #define FOOPLUGIN_PLUGIN_H #include <QQmlExtensionPlugin> class FooPluginPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif // FOOPLUGIN_PLUGIN_H
fooplugin_plugin.cpp
#include "fooplugin_plugin.h" #include "foo.h" #include <qqml.h> static QObject *singletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) Foo *foo = new Foo(); return foo; } void FooPluginPlugin::registerTypes(const char *uri) { // @uri com.mycompany.qmlcomponents // qmlRegisterType<Foo>(uri, 1, 0, "Foo"); qmlRegisterSingletonType<Foo>(uri, 1, 0, "Foo", singletonProvider); }
So you create a folder with the following structure:
imports └── com └── mycompany └── qmlcomponents ├── libFooPlugin.so └── qmldir
Then you import the module in your main.qml:
import QtQuick 2.15 import QtQuick.Window 2.15 import com.mycompany.qmlcomponents 1.0 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") Component.onCompleted: console.log(Foo.bar()) }
And then you finally run:
qmlscene -I /path/of/imports main.qml