For example, an empty QObject-based class defined in C++. It's created from QML. Then C++ adds some properties to it via setProperty. But they aren't becoming accessible by QML.
Other example: use setContextObject and then start adding properties to that C++ object. No effect on QML.
How to make it work?
update
I see two options: private API (MetaObject builder) and code generation for QML items at runtime.
I think you're looking for QQmlPropertyMap. It allows you to add properties dynamically. It's usually better to predefine values through qt models in C++ though, and there aren't many good use cases for using QQmlPropertyMap.
There actually several ways to do this, this article has a great explanations.
Related
Before April 2019, it was possible for a Lua script to reflect the methods and properties of a LuaBridge class using string keys __parent, __class, __propget, and __propset. This was an incredibly useful tool for creating test scripts and development tools to maintain a large class framework exported into Lua.
From looking through the release notes of LuaBridge, it seems the string keys were removed for security reasons. But I find myself placing more priority on the ability to reflect classes from scripts than on whether scripts can muck around in the object model. Especially in dev mode.
The LuaBridge Reference Manual implies there is a way for a C/C++ program to expose the metatables, but I haven't been able to figure out how to do it. I am quite new to interfacing between C and Lua (or LuaBridge), so I'm not surprised that I am perplexed. If anyone could share an example of how to do this, I would appreciate it.
Since no one seems to have a good suggestion, I realized I could roll my own reflection of the names of properties, methods, and constants. For my purposes I don't really need to execute or access them.
So rather than muck around inside LuaBridge I added __class, __propget, and __propset static properties to every class in my framework. These return a table implemented with std::map which LuaBridge supports. The tables simple have the names as keys and a dummy value.
One caveat I discovered is that you have to add static properties to derived classes when creating the derived class with deriveClass. If you try to add them later (using beginClass), LuaBridge throws an assert.
I am working on custom lightweight UI library for my C++ project and I have question about implementing control's behavior.
Currently I have system that create instances of controls from provided files, so graphical representation, text, dimensions and other parameters are defined in external file. Regarding buttons and other interactive controls: I have base button class and for each button I am creating derived class with its own implementation of behavior related methods(onClick() etc.) see pseudo snippet:
class Button
{
public:
Button();
virtual void onClick();
};
class newButton : public Button
{
void onClick()
{}//specific implementation
};
I am looking for way to describe behavior externally(scripting language possibly) and inserting it to specific instance of base button on compile, so I won't need to create subclasses of button, and buttons/components could be completely described in external file. Any toughts or recommendations will be appreciated.
Thanks
Well I think you got another XY problem: Using run-time object polymorphism is not able to solve your wish. Although it enables C++ code to not care which specific implementation one uses, and can accept new unknown solutions at run time, these new solution still have to be compiled with an C++ compiler, and be compliant with the base class definition and C++ implementation (your compiler like gcc or MSVC) specific details of runtime polymorphism.
Since I assume you don't want that, which also makes sense and is a pattern getting popular in the C++ world (see QML or Javascript/C++ hybrids), you have some options.
Either you implement all basic behaviour building blocks in C++ (where you can of course use runtime polymorphism or even compile time polymorphism), which you then simply combine according to your UI description language at run time. To parse your so called DSL i.e. UI description language, you can use libraries like boost spirit.
How ever if you really to script the UI logic and not simply describe it, you would have to design and implement a whole programming language, which is also compatible to your C++ implementations runtime object polymorphism. Which I would find a very big and long task.
But don't dispair, that are ready solution like Javescript/C++ in the form of react native and electron using native node modules, or QML/Qt, or lua, a scripting language, specifically designed to be used in other programming languages.
I would like to develop relatively simple dialog-based GUIs for Raspberry PI 2 (Linux/Raspbian) that is why would like to study Qt beginning with the basic/core features. RTFM, I know. So I read one of them, and to be honest understood very little.
The biggest question in my head: Why would it have been worth reading in the first place? What is the purpose of the Qt properties? What are they good for?
How do they work internally and from the point of view of writing the code.
What is the memory and performance cost? Is it necessary to use them? If not, is it worth using them considering my use case?
Properties are used to read/write values in objects through a standard generic interface. Needed for interfacing with script engines (QtScript or QtQml), the widget designer, remote object interfaces (QtDBus, QtRemoteObjects, QtWebChannel).
Most properties get implemented through normal getter/setter functions which are then tied to a property name and registered with the property system using the Q_PROPERTY macro. Alternatively the property name can be bound to a member variable. Read/write access with the generic property() and setProperty() API is the rerouted either to calls to the registered getter/setter or to the registered member variable.
The property information is stored as a QMetaProperty in the class' staticMetaObject, access through the property API will incur a lookup based on the property name.
Your use case doesn't seem to require usage of properties.
Another use case, as mentioned by Kuba in the comment, is to attach data to QObject based objects without modifying them.
These kind of properties, so called "dynamic properties", are handled slightly differently. Instead of getter/setter functions or a member variable, they are stored in a generic internal storage, currently a QVector<QVariant>
The DYNAMIC FACTORY pattern describes how to create a factory that
allows the creation of unanticipated products derived from the same
abstraction by storing the information about their concrete type in
external metadata
from : http://www.wirfs-brock.com/PDFs/TheDynamicFactoryPattern.pdf
The PDF says:
Configurability
. We can change the behavior of an application by just changing its configuration
information. This can be done without the need to change any source code (just change the descriptive information about the type in the metadata repository) or to restart the application (if caching is not used – if caching is used the cache will need to be flushed).
It is not possible to introduce new types to a running C++ program without modifying source code. At the very least, you'd need to write a shared library containing a factory to generate instances of the new type: but doing so is expressly rules out by the PDF:
Extensibility / Evolvability
. New product types should be easily
added without requiring neither a
new factory class nor modifying
any existing one.
This is not practical in C++.
Still, the functionality can be achieved by using metadata to guide some code writing function, then invoking the compiler (whether as a subprocess or a library) to create a shared library. This is pretty much what the languages mentioned in the PDF are doing when they use reflection and metadata to ask the virtual machine to create new class instances: it's just more normal in those language environments to need bits of the compiler/interpreter hanging around in memory, so it doesn't seem such a big step.
Yes...
Look at the Factories classes in the Qtilities Qt library.
#TonyD regarding
We can change the behavior of an application by just changing its configuration information.
It is 100% possible if you interpret the sentence in another way. What I read and understand is you change a configuration file (xml in the doc) that gets loaded to change the behaviour of the application. So perhaps your application has 2 loggers, one to file and one to a GUI. So the config file can be edited to choose one or both to be used. Thus no change of the application but the behaviour is changed. The requirement is that anything that you can configure in the file is available in the code, so to say log using network will not work since it is not implemented.
New product types should be easily added without requiring neither a new factory class nor modifying any existing one.
Yes that sounds a bit impossible. I will accept the ability to add ones without having to change the original application. Thus one should be able to add using plugins or another method and leave the application/factory/existing classes in tact and unchanged.
All of the above is supported by the example provided. Although Qtilities is a Qt library, the factories are not Qt specific.
I've often come across APIs that allow users to get and set various parameters that control a module's operation. I now find myself contemplating writing yet another properties API but don't want to reinvent the wheel.
The following is typical basic client code:
setInt("bitrate", 1000);
setEnum("mode", MODE_FAST);
setStr("output file", "music.mp3");
Frequently there are dozens of parameters that can be set and such property sets are often under continuous development.
Some APIs are smarter than others, more advanced features being:
Hierarchical grouping of properties
Enumeration of properties
Numeric parameters with enforced minima and maxima
Default parameter values
Settings that are enabled, disabled or read only
Dynamic parameters - settings that appear, disappear, have min/max set, become enabled, disabled or read only depending on other parameters' state.
Properties accessed via UUID key rather than textual name
Beyond the C-style accessors in the sample code above, I've come across frameworks that can:
Read/write properties to file (e.g. XML)
Read/write settings to Windows Registry
Interface with system properties APIs like IPersistPropertyBag
Have default dumb GUI implementations, e.g. tree-view or list
Have GUI extensions appropriate to minima/maxima/enabled state reducing repetition in GUI code.
I would love to find a well-designed public library that provides a framework for all of the above but so far have drawn a blank. I'm aware of Boost.PropertyTree but it's only really a skeleton. Are there other portable properties API frameworks that I should be aware of?
One of the key elements of the Qt property system is actually a very solid implementation of a variant type class QVariant that enables you to get rid of the typed setInt, setString ... calls.
If you get a hold of a similar well behaved class e.g. possibly Boost::Variant or something similar a property system is fairly easy to implement using a map of string as the backing part.
One of the conveniences of the qt property system is that you can override setter and getter functions without the user having to know about them. E.g. given your generic property setter being setProperty(name, value). The implementor can in the class declaration denote that the property "speed" has its own setter setSpeed(float value) so that when a user of your class invokes the generic version of setProperty("speed", 100), the system will call setSpeed(100) on your instance.
If you don't need features like that you can probably implement your own property system. Gamasutra has a piece on implementing reflection in C++ that might help you too.
If you don't mind having a dependency on Qt Core, then Qt has a fairly well designed property system. This means though that you will be relying on Qt's MOC.