Accessing QML plug-in code as C++ object - c++

I have created two QML plugins with C++. Plugin A represents some specific UI item types and plugin B represents own "storage" singleton QML item type. The original motivation was to create QML storage singleton and use it through the most of QML UI code. Now I also want a direct interaction between A and B meaning they interact with each other just in C++ code bypassing QML. Only A needs to know about B, not the other way around. How can I achieve that?
No rootObject->findChild type of solution needed. The question is somewhat similar to Accessing QML objects from C++ except I need to be able to instantiate the object from QML PlugIn dynamic library in C++. I see the on-surface solution with dynamic library used by both QML and C++ code. But it is a bit more complicated: it has to be just one instance of code with data. Also there is probably a way to somehow "cast" the instance QML of plugin object to normal Qt plugin and then call whatever I want from it.

I think this should also work for Plugins and not only for registered types. I can't try it right now, I will remove this line once I tried it out later that day:
Each QML Singleton, defined in C++ needs to have a static method with the signature:
static QObject* someName(QQmlEngine *, QJSEngine *);
that returns a pointer to the single instance of this class.
I think usually you don't need the QQmlEngine or QJSEngine to make it work, so you can easily implement the full Singleton-Pattern by adding a second static method:
static QObject* instance();
which returns exactly the same.
You might alternatively have a
static MySingletonObject* instance();
so you don't need to cast afterwards.
Now you can just import your class, and you will have access to the very same instance, by calling this static method.
If above does not work, you might do it the hacky way:
You can alternatively use your root node and set a property:
property QtObject mySingleton: MySingleton
Then you can use findChild to grab your root node and read the very same property. To be able to do this you might need to access something of the singleton before, as otherwise the instance might be missing.
property Item singl: MySingleton
Component.onCompleted: {
// MySingleton.color = 'green' // If this line is commented out, it will fail for me for a QML-defined Singleton at least.
singl.color = 'red'
}
This solution works for me for QML-defined qmldir-registered singletons, as well as C++-defined and qmlRegisterSingleton(...)-registered singletons. With QML-defined singletons you might need access the singleton once, before you can assign it. I don't know the internal reasons for that.

Related

How to pass pass a bound method of a pointer as an argument?

If I am given a pointer to an object and I need to pass one of that object's methods as an argument to another function, is that possible?
A very simplified example would look like this:
void consumeAFunction(Function func) {
auto value = func();
// do some stuff //
}
void main(Object *pointerToObject) {
consumeAFunction(pointerToObject->someMethod)
}
I've tried the following, but I think my understanding of pointers and references is flawed. I'm 3 weeks old in my c++ journey.
​Object someObject = pointerToObject​ and Object someObject = *pointerToObject​
The specific context of the question is that I have a pointer to an object created by some other library and I need to use QtConcurrent::run on that object's methods.
Additional context
consumeAFunction is QtConcurrent::run
Function func is a method of an Engine that simply performs some logic. I am handed a pointer to Engine by a third party library.
I cannot avoid using a pointer to Engine, because it is all I am given to work with.
As much of the specific code as I am allowed to show:
// engine is the pointer to someObject:
auto engine = lui::QueryInterop<wise::Engine>(lui::GetLUI());
if (engine) {
connect(&m_modelsLoadedWatcher, &QFutureWatcher<bool>::finished, this, &ConfigDialog::onNNModelsLoaded);
// This is the call to consumeAFunction (qtconcurrent::run)
m_modelsLoadedFuture = QtConcurrent::run(engine->loadPytorchModels);
m_modelsLoadedWatcher.setFuture(m_modelsLoadedFuture);
Because this is a Qt question, I highly recommend you get an understanding of QObject and QMetaObject::invokeMethod().
Because QObject is pre-processing via the moc-compiler, a lot of public interfaces, such as properties, methods are exposed in such a way that the object's properties and methods can be inspected at runtime by another plugin and that it doesn't need to know or have access to the header files. This is why something like QMetaObject::invokeMethod() can work because it has access to the metadata.
Alternatively, if you are using Javascript a lot in QML, you may be interested in passing a Javascript callback function to C++. That function is accessible via QJSValue. QJSValue usually is used to hold simple types such as strings and numbers. When it holds more complex Javascript types such as arrays, objects, or functions you can use quite a few QJSValue methods to unlock their capabilities. In the case of Javascript functions you can verify if it is a Javascript function with QJSValue.isCallable() == true and can you can execute it with QJSValue.call(...).

Qt/QML qmlRegisterType vs. setContextProperty (difference)

In Qt/QML application (this code usually resides in main.cpp of QtCreator project), what is the difference between following ways of exposing C++ class to QML:
qmlRegisterType<UePeopleModel>("com.example",
1,
0,
"UePeopleModel");
and
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
?
qmlRegisterType :
"Sometimes a QObject-derived class may need to be registered with the QML type system but not as an instantiable type."
Use qmlRegisterType, if you want reuse a QObject-derived class with in one or more than one qml file with different property. QML is responsible for initialization of this register class.
See this for more help.
Defining QML Types from C++
setContextProperty :
Use setContextProperty, When you want to use a single global class to access to or from QML. Here You need create this class object before use setContextProperty().
Note: Since all expressions evaluated in QML are evaluated in a particular context, if the context is modified, all bindings in that context will be re-evaluated. Thus, context properties should be used with care outside of application initialization, as this may lead to decreased application performance.
See this for more help.
Embedding C++ Objects into QML
In the first one you are declaring a C++ type available for instantiation in QML, in the second you are declaring a global variable "uePeopleModel" of the same type.

Q_INVOKABLE method returning custom C++ type

I have a C++ method made Q_INVOKABLE. I can call this method from QML and it works when it returns basic types (like QString). But I can't with a custom type. How should I do this? Should I return a QVariant instead? Ideally, I would like to return a pointer to my custom type if possible.
EDIT
I do:
qmlRegisterType<MyType>("Mine", 1, 0, "MyType");
qmlEngine->rootContext()->setContextProperty("testObj", new MyType());
I can use testObj global object or create MyType QML component. But I cannot use it in some javascript code as a return type from a Q_INVOKABLE C++ method.
This is possible but you need to define your custom type
as an interface.
First of all in your main() function:
qmlRegisterInterface<MyType>("MyType");
Now you can proceed to create an object and return a pointer
in a Q_INVOKABLE:
MyType* example = new MyType(parent);
return example;
Note: it might be beneficial to pass the parent to your custom QObject to ensure that this object is deleted together with his parent (to avoid memory leaks).
Yes, QVariant is the way to go for your custom class in that construction. Make sure you register your class.
That being said, you may wish to consider using Q_PROPERTY instead, for your custom type and then you can access that even without a function call. If you need custom parameters to the method and you cannot rearrange the code, this is obviously not an option.
Note that the target of this answer are people with a similar problem, rather than the original asker.
The described method should work, at least in recent versions of Qt (I'm using Qt 5.12, but it should work in older versions too). Maybe it was a bug in one of the first QML releases.
Checklist: Verify you have done the following:
Registered your type qmlRegisterType<MyType>("Mine", 1, 0, "MyType"); (or use qmlRegisterUncreatableType)
Imported your custom types in qml: import Mine 1.0
Derived your class from QObject.
Added Q_OBJECT to your class definition.
When returning pointers from a Q_INVOKABLE method, please take object ownership into account.
I think Dimitri's answer only applies when your type is copyable (so it wouldn't work for QObject). My understanding is that when you have a type that is being manipulated by Qt, for example if it is being returned by an invokable, the type has to be registered as a metatype:
Non-copyable types like any QObject derived model cannot be metatypes
A pointer type is a different type, therefore it needs to register separately from the classes it points to
For pointer type Foo* you can register it with metatype system: qRegisterMetaType<Foo*>("Foo*");

How to automatically inject helper classes in each new module?

Developing a modular application, I want to inject some helper classes into each module. This should happen automated. Note that my helpers have state, so I can't just make them static and include them where needed.
I could store all helpers in a map with a string key and make it available to the abstract base class all modules inherit from.
std::unordered_map<std::string, void*> helpers;
RendererModule renderer = new RendererModule(helpers); // argument is passed to
// base class constructor
Then inside a module, I could access helpers like this.
std::string file = (FileHelper*)helpers["file"]->Read("C:/file.txt");
But instead, I would like to access the helpers like this.
std::string file = File->Read("C:/file.txt");
To do so, at the moment I separately define members for all helpers in the module base class, and set them for each specific module.
FileHelper file = new FileHelper(); // some helper instances are passed to
// multiple modules, while others are
// newly created for each one
RendererModule renderer = new RendererModule();
renderer->File = file;
Is there a way to automate this, so that I don't have to change to module code when adding a new helper to the application, while remaining with the second syntax? I an not that familiar with C macros, so I don't know if they are capable of that.
I think I see what your dilemma is, but I have no good solution for it. However, since there are no other answers, I will contribute my two cents.
I use the combination of a few strategies to help me with these kinds of problems:
If the helper instance is truly module-specific, I let the module itself create and manage it inside.
If I don't want the module to know about the creation or destruction of the helper(s), or if the lifetime of the helper instance is not tied to the module that is using it, or if I want to share a helper instance among several modules, I create it outside and pass the reference to the entry-point constructor of the module. Passing it to the constructor has the advantage of making the dependency explicit.
If the number of the helpers are high (say more than 2-3) I create an encompassing struct (or simple class) that just contains all the pointers and pass that struct into the constructor of the module or subsystem. For example:
struct Platform { // I sometimes call it "Environment", etc.
FileHelper * file;
LogHelper * log;
MemoryHelper * mem;
StatsHelper * stats;
};
Note: this is not a particularly nice or safe solution, but it's no worse than managing disparate pointers and it is straightforward.
All the above assumes that helpers have no dependency on modules (i.e. they are on a lower abstraction of dependency level and know nothing about modules.) If some helpers are closer to modules, that is, if you start to want to inject module-on-module dependencies into each other, the above strategies really break down.
In these cases (which obviously happen a lot) I have found that a centralized ModuleManager singleton (probably a global object) is the best. You explicitly register your modules into it, along with explicit order of initialization, and it constructs all the modules. The modules can ask this ModuleManager for a reference to other modules by name (kind of like a map of strings to module pointers,) but they do this once and store the pointers internally in any way they want for convenient and fast access.
However, to prevent messy lifetime and order-of-destruction issues, any time a module is constructed or destructed, the ModuleManager notifies all other modules via callbacks, so they have the chance to update their internal pointers to avoid dangling pointers and other problems.
That's it. By the way, you might want to investigate articles and implementations related to the "service locator" pattern.

Organization of the QT Code

I am writing an application of middle size. I will have many gui components and many classes. However, it is difficult for me to organize the code, to separate the logic, ... For example, let say that I press one button that creates an object of a class and perform a computation on that object. After exiting the slot function of the button, this local object is destroyed. What if I need it in another function later? Defining everything as a global variable in the header file is not a good thing for me. So I was thinking of a static class that contains somehow pointers to all the objects I will need later. Does anybody has a better idea?
How to manage objects inside an application is always a tricky
question. Qt goes down a very object-oriented route and uses reference
semantics implemented through pointer for nearly everything. To
prevent tedious manual memory management Qt organizes everything into
Object Trees. This
is augmented by Qt own
object model that adds
some dynamic capabilities.
If you want to go down that route, stick to everything Qt provides. It
is much more similar to Java than the usual C++ approach and might be
more comforting for beginners and maybe suits your application
domain. It tightly ties your code to Qt and will make it hard to
separate from it.
One other approach means to simply forgo all Qt stuff and work out the
core logic of your application. Develop it in pure C++ and than have a
thin layer that ties this logic into your Qt application through
signals and slots. In such an approach you would opt to use more
value-semantics.
For your concrete example of creating an algorithm and keeping it
around. The Qt approach:
class MyAlgo : public QObject {
Q_OBJECT
public:
MyAlgo(QObject* o) : QObject(o) { }
virtual compute();
};
// use it in a mainwindow slot
void MainWindow::executeAlgorithm(const QString& name) {
MyAlgo* algo = this->findChild<MyAlgo*>(name);
if(!algo) {
// not found, create
algo = new MyAlgo(this); // make mainwindow the parent of this algo
algo->setName(name); // QObject name property
}
algo->compute();
}