Reputation: 33
I'am trying to figure out how to implement multiple MqttClients with the GitHub Project MosQtitto from Alepez.
https://github.com/alepez/MosQtitto
One Client is created with the MqttClient Class, but I don't know how to use the MqttClientSingleton Class to create multiple Clients in main.qml(App.qml in the Project).
MqttClientSingleton.hpp
#ifndef MQTTCLIENTSINGLETON_HPP
#define MQTTCLIENTSINGLETON_HPP
#include "MqttClient.hpp"
class MqttClientSingleton {
public:
static MqttClient* get();
static void set(MqttClient*);
};
#endif // MQTTCLIENTSINGLETON_HPP
MqttClientSingleton.cpp
#include "MqttClientSingleton.hpp"
#include <QDebug>
static MqttClient* instance{nullptr};
MqttClient* MqttClientSingleton::get() {
return instance;
}
void MqttClientSingleton::set(MqttClient* newInstance) {
instance = newInstance;
}
I think the Class has to be registered with
qmlRegisterSingletonType
to use it in main.qml. Does someone know how to register it and how to implement multiple clients with it?
Upvotes: 1
Views: 362
Reputation: 1152
You can use a singleton object with two instances:
QObject* MqttClientSingleton::singletonProvider(QQmlEngine*, QJSEngine*)
{
return MqttClientSingleton::instance();
}
and
QObject* MqttClientSingleton::singletonProvider2(QQmlEngine*, QJSEngine*)
{
return MqttClientSingleton::instance2();
}
and declare it
qmlRegisterSingletonType<MqttClientSingleton>("MqttClientSingleton1", 1, 0, "MqttClientSingleton1", MqttClientSingleton::singletonProvider);
qmlRegisterSingletonType<MqttClientSingleton>("MqttClientSingleton2", 1, 0, "MqttClientSingleton2", MqttClientSingleton::singletonProvider2);
This is a very good tip: sometimes I declare normal C++ objects as singleton QML objects (using C++11 lambda declaration) , to share the C++ class instace in QML:
static classname *static_pointer=&non_singleton_QObject;
qmlRegisterSingletonType<classname>("ClassName", 1, 0, "ClassName", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine) Q_UNUSED(scriptEngine) return static_pointer;});
Then , its easy to have one or more shared objects:
static classname *static_pointer1=&non_singleton_QObject1;
static classname *static_pointer2=&non_singleton_QObject2;
static classname *static_pointer3=&non_singleton_QObject3;
qmlRegisterSingletonType<classname>("ClassName1", 1, 0, "ClassName1", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine) Q_UNUSED(scriptEngine) return static_pointer1;});
qmlRegisterSingletonType<classname>("ClassName2", 1, 0, "ClassName2", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine) Q_UNUSED(scriptEngine) return static_pointer2;});
qmlRegisterSingletonType<classname>("ClassName3", 1, 0, "ClassName3", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine) Q_UNUSED(scriptEngine) return static_pointer3;});
Upvotes: 0
Reputation: 8802
I'm the author of MosQtitto. MqttClient
is the right class to be used when you want multiple instances. MqttClientSingleton
exists to have only one instance (and one tcp connection) to be used both in qml and c++ at the same time.
Only if you need a single instance, shared between qml and c++ code, you can use the singleton. This is an extract of a qt plugin I wrote:
void MyPlugin::initializeEngine(QQmlEngine* engine, const char* uri) {
Q_UNUSED(engine);
Q_UNUSED(uri);
/* First, instantiate MQTT Singleton */
MqttClientSingleton::set(new MqttClient{});
engine->setObjectOwnership(MqttClientSingleton::get(), QQmlEngine::CppOwnership);
}
void MyPlugin::registerTypes(const char* uri) {
Q_UNUSED(uri);
qmlRegisterSingletonType<MqttClient>(uri, 1, 0, "MqttClientSingleton", [](QQmlEngine*, QJSEngine*) -> QObject* {
return MqttClientSingleton::get();
});
If you don't need a plugin, just create the instance and register the type on the main function, as you can find in main.cpp
example in the project.
Make sure you call mosquitto_lib_init();
before instantiating any MqttClient and call mosquitto_lib_cleanup();
when the program ends, after all MqttClient instances have been deleted.
Upvotes: 1
Reputation: 13701
If you want to register it as a singleton, available for QML the call is
int qmlRegisterSingletonType<T>(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(* ) ( QQmlEngine *, QJSEngine * ) callback)
as described in the documentation.
So for your class it might be something like this:
qmlRegisterSingletonType<MqttClientSingleton>("MqttClientSingleton", 1, 0, "MqttClientSingleton", MqttClientSingleton::singletonProvider);
The last part of this call is a function pointer to a method that has the specific signature:
static QObject* singletonProvider(QQmlEngine*, QJSEngine*)
This method shall return the instance. So you can write
QObject* MqttClientSingleton::singletonProvider(QQmlEngine*, QJSEngine*)
{
return MqttClientSingleton::instance();
}
But to the second part of your question:
and how to implement multiple clients with it?
I need to say - I don't know the details of the MqttClientSingleton
, but as it is a Singleton
this is likely not possible. The whole purpose of a Singleton
is, that you can take it for granted that at all times there is one and only one instance of this class. So you can't have multiple instances. If you don't need multiple instances for mulitple clients - well then it might work.
If you have access to the code, you might see, if you can refactor it to get rid of the singleton, register it as common QML type and be happy...
Don't forget that the return type of the
singletonProvider
isQObject*
. So make sure that the value returned, is of typeQObject*
. This means you need to inheritQObject
and you need to use theQ_OBJECT
macro in your class to make it work. Also you need to createQ_PROPERTIES
to access values andQ_INVOCABLES
to make functions callable from QML
Upvotes: 0