Qt/QML qmlRegisterType vs. setContextProperty (difference) - c++

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.

Related

How to access non-static Qt Ui function from a static member function of a different class?

So me and my friends are developing Connect4 in C++. At first we elaborated the logic behind the game in a Visual Studio Console Application. We came up with 3 classes, "Logic", "GameUi" (That name is probably not suitable) and "Gui". (I should mention that all members off these classes are static members - so no instances)
Once the logic worked it was my job to tranfer it to Qt. And here's the problem:
So basically once the player has done an input (aka. The Player has chosen a column in which he wants to throw the slice (?) in) the Logic class processes this input and updates the vector in which we store the field. After this Logic calls the GamUi class, which should then call a function in the Gui class (Note that the Gui class is now the Qt class). The Problem with that is that I can't call a non-static function in the Qt class to change the Ui from a static function from a different class.
At first I thought about making the Ui public, which is according to the internet not a good programming exercise.
Thank you very much in advance
Ps: Please don't judge me for my non-native-speaker-english and my not very good c++ skills.
Assuming GUI is a singleton, you might code a static GUI::instance() method that returns a pointer to itself. Call it from anywhere and you have your pointer. Better yet, [inherit from QObject and] use signals and slots.

Interacting Window Components from Member Object

As Qt programs happen to live within their MainWindow class, I am having troubles altering the design components via a member class, that, because of inter-inclusion of headers leading to compilation errors.
MainWindow class holding a EventManager member object needs to have its design components modified in a method of EventManager without having multi-inclusion issue, that considering that MainWindow needs to include EventManager to be able to hold it within its class as member.
What would be the best (programmatically speaking) method to achieve this goal ?

Accessing QML plug-in code as C++ object

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.

Qtilities: Custom property types for the property browsers?

I'm writing a program that requires the user to be very flexible in manipulating data on a given object. I figured I would use a property browser of some kind; Qtilities' ObjectDynamicPropertyBrowser caught my eye.
However, I need to be able to add my own data types. The documentation is not clear on how to do so.
How can I allow my own data types to be represented in Qtilities' property browser widgets?
Also, more about my needs:
The data types are not part of Qt, nor are they even Q_OBJECTs.
Qt-specific modifications to the relevant classes are not an option.
Declaring the relevant classes via Q_DECLARE_METATYPE is okay.
In particular, I need to represent vector and matrix types (and possibly more later).
The browser you refer to depends on the QObject property system. So, unless your classes are QObjects, it won't work - but don't despair, Qt 5.5 to the rescue (read on). The browser seems to use a QTreeView and provides an adapter model that exposes the QObject property system. So, it leverages Qt's type and delegate system.
In Qt 5.5, there is a general purpose property system, known as gadgets, that can be used on any class, as long as there is a QMetaObject describing that class. By adding the Q_GADGET macro to a class deriving from the subject class, and describing the properties using Q_PROPERTY macro, you can leverage moc and the gadget system to access your unmodified types' properties.
The only reason you'd do that is to require minimal changes to the ObjectPropertyBrowser system. You don't want the ObjectDynamicPropertyBrowser, since it works on dynamic properties, and your objects don't have any. They have static properties, given through Q_PROPERTY macros and code generated by moc.
So, you'll proceed as you would for implementing your own type support for QVariant and views in general. You also need Qt 5.5, since you need gadget support for it to work. A solution for Qt 5.4 and below requires a different approach and might be less cumbersome to implement in another way.
See this answer for a reference on using gadget property system for object serialization, it's fundamentally what the property browser would do, sans the serialization proper of course.
There are three steps. First, you need to address simple custom types that don't have a structure, but represent a single value (such as a date, or time, or geographic position, etc.), or a collection of simple values (such as a matrix).
Ensure that QVariant can carry the simple types. Add the Q_DECLARE_METATYPE macro right after the type's definition in an interface (header file).
Implement delegates for the types. For types with table structure, such as a matrix, you can leverage QTableView and provide an adaptor model that exposes the type's contents as a table model.
Secondly, you get to your complex types that have internal structure:
Create a wrapper class that derives from the complex type, declares all properties using Q_PROPERTY, and has the Q_GADGET macro (not Q_OBJECT since they are not QObjects). Such class should not have any members of its own. Its only methods should be optional property accessors. The Q_GADGET macro adds the static (class) member staticMetaObject.
The underlying type can be static_cast to the wrapper class if needed, but that's normally not necessary.
At this point, any class that you wrote a wrapper for is accessible to the QMetaProperty system directly, without casting! You'd use the wrapper's staticMetaObject for its static metaobject, but the QMetaProperty readOnGadget and writeOnGadget will take the pointers to the base class directly.
Thirdly, since ObjectPropertyBrowser most likely doesn't implement the support for gadgets in Qt 5.5, as that's quite new, you'll have to modify it to provide such support. The changes will be minimal and have to do with using QMetaProperty::readOnGadget and QMetaProperty::writeOnGadget instead of QMetaProperty::read and QMetaProperty::write. See the serialization answer for comparison between the two.

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*");