JohnnyWaker
JohnnyWaker

Reputation: 33

How to use MqttClientSingletonClass from GitHub Project MosQtitto?

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

Answers (3)

Miguel Angel Pons
Miguel Angel Pons

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

Alessandro Pezzato
Alessandro Pezzato

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

derM
derM

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 is QObject*. So make sure that the value returned, is of type QObject*. This means you need to inherit QObject and you need to use the Q_OBJECT macro in your class to make it work. Also you need to create Q_PROPERTIES to access values and Q_INVOCABLES to make functions callable from QML

Upvotes: 0

Related Questions