Integrating C++ code with QML
Overview
The Qt Quick Ultralite applications use C++ code for business logic, interfacing with hardware, and working with other software modules. The C++ part of the application interacts with the QML presentation layer. Therefore the C++ classes as well as their functions, properties, and signals are exposed to QML code.
Interface headers
An application can contain interface headers that describe the components that shall be exposed to QML. These are normal C++ header files that are registered in CMake with the qul_register_types()
macro.
When you register a header with the macro, it has two effects on the build:
- the
qmlinterfaceextractor
tool will be run on the header, creating one or more QML interface files - the generated files will be fed to
qmltocpp
when translating the project's QML code
The steps enable QML code to make use of the C++ interfaces.
Exporting C++ APIs
Components
Class and struct declarations are the building blocks for exposing C++ functionality to QML. Each exported C++ class declaration defines a QML component of the same name.
The following example demonstrates how to use components:
#include <qul/qtobject.h> #include <qul/property.h> #include <qul/signal.h> struct BigState : public Qul::Items::QtObject { Qul::Property<int> bigness; int feed(int amount); Qul::Signal<void()> gotFood; };
Item { BigState { id: bigState bigness: 61 onGotFood: bigness = 99 } Component.onCompleted: bigState.feed(3) }
In order to be picked up by qmlinterfaceextractor, the declared class
- must at least indirectly inherit from Qul::Items::QtObject
- must be default constructible
Some base classes have special meaning. For more detailed information, see Singletons and Models
Singletons
If the class derives directly from Qul::Items::Singleton<Itself>, it is marked with pragma singleton and an instance is available globally.
The following example demonstrates how to use Singletons:
struct MyApi : public Qul::Items::Singleton<MyApi> { void start(); };
Item { Component.onCompleted: MyApi.start() }
Models
The class can directly derive from from Qul::Model<T> to export a list model. See the Qul::Model documentation for details.
Functions
All public non-overloaded member functions in an exported class declaration are available in QML. The function's parameter types and return type are mapped to their QML counterparts.
The following example demonstrates how to use functions:
struct DirLookup : public Qul::Items::QtObject { Qul::Property<const char *> basePath; int lookup(const char *path); }; struct Simulator : public Qul::Items::Singleton<Simulator> { void run(DirLookup *lookup); };
Item { DirLookup { id: look basePath: "/objects" } Component.onCompleted: Simulator.run(look) }
Properties
Public fields in exported class declarations become component properties if the field has the type Qul::Property<T>. Here T describes the property's C++ type and is mapped to a corresponding QML type.
The properties defined in this way behave like built-in properties. In particular they can be assigned bindings in QML and can be used as a data source in other bindings.
The following example demonstrates how to use properties:
struct MyData : public Qul::Items::QtObject { Qul::Property<int> val; void update(int x) { // can get and set property values from C++ val.setValue(x); } };
Item { Item { // can bind QML property to exported property x: mydata_x.val color: "red" width: 50 height: 50 } MyData { id: mydata_x val: 100 } MyData { id: mydata_width // can bind exported property val: parent.width } Component.onCompleted: { mydata_x.update(200); console.log(mydata_width.val); } }
Grouped properties
Properties can be grouped together as follows:
struct MyObject : public Qul::Items::QtObject { struct Grouped { Qul::Property<int> val1; Qul::Property<int> val2; }; Grouped group; };
Item { MyObject { group.val1: 42 group.val2: 43 } }
The grouping happens by placing the properties inside a struct or class S and then having a field of type S inside the exported class. The type S must not itself be derived from Qul::Items::QtObject. Only its public fields of type Qul::Property are exposed as properties within the group. Groups are only for properties and can not have signals, enums or functions.
Signals
Public fields of type Qul::Signal<Fn>
are translated to signals on the QML component.
The template argument Fn
must be a function type that describes the signal's parameter types. As usual, these types are mapped to the matching QML types. Similarly, the parameter names used in Fn
becomes a QML signal's parameter names.
The following code demonstrates how use signals:
struct MyItem : public Qul::Items::QtObject { Qul::Signal<void(int sigValue)> triggered; void callTriggered() { triggered(42); } };
Item { MyItem { id: myitem onTriggered: console.log(sigValue); } Component.onCompleted: myitem.callTriggered() }
Enums
Public enum declarations in an exported class declaration are translated to QML enums.
The following code demonstrates how use public enums:
struct MyStates : public Qul::Items::Singleton<MyStates> { enum State { On, Off, Broken }; };
Item { property MyStates.State state: MyStates.On }
C++ to QML type mapping
C++ type | QML type |
---|---|
bool | bool |
integral (char, short, int, long, ...) | int |
floating point (float, double) | real |
T* where T derives from QtObject | matching component type |
enum in exported class | matching enum type |