Using Nt QML
How to declare objects in QML documents, bind their properties, and give QML your C++ types.
QML describes a tree of objects: their properties, the bindings that keep properties up to date, and what happens when signals arrive. Nt Qml reads QML documents and makes their objects with QQmlEngine and QQmlComponent, or with QQmlApplicationEngine for the main document of an application.
find_package(Nt6 REQUIRED)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE Nt::Qml)
A Document
import QtQml
QtObject {
id: root
property int hour: 6
property bool night: hour < 7 || hour > 21 // a binding: kept up to date
signal alarm(string reason)
onAlarm: (reason) => console.log("alarm:", reason)
function later() { hour += 1 }
property Timer clock: Timer { interval: 1000; repeat: true; running: true; onTriggered: root.later() }
Component.onCompleted: console.log("ready")
}
A document imports modules, then declares one root object. Objects have an id, properties (their type's, and the ones they declare with property), signals, functions, enumerations, and child objects, which go to the default property of their parent. Properties are set to values or bound to expressions; on handlers run when signals arrive.
Making the Objects
QQmlComponent reads a document and makes its objects:
QQmlEngine engine;
engine.rootContext()->setContextProperty("greeting", QStringLiteral("hello"));
QObject::connect(&engine, &QQmlEngine::quit, &app, &QCoreApplication::quit);
QQmlComponent component(&engine);
component.setData(document, QUrl(QStringLiteral("file:///home.qml")));
QObject *home = component.create();
if (!home) {
qWarning().noquote() << component.errorString();
return 1;
}
QQmlApplicationEngine loads the main document of an application, and quits it when the document calls Qt.quit():
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("greeting", QStringLiteral("hello"));
engine.load(QString::fromLocal8Bit(argv[1]));
if (engine.rootObjects().isEmpty())
return 1;
return app.exec();
Bindings
A property set to an expression is bound to it: the expression is evaluated again whenever a property it read changes. That can be a C++ property with a NOTIFY signal, a property declared in QML, or a context property. Assigning a value from a script replaces the binding; Qt.binding() makes a new one. A binding that changes what it depends on is reported as a binding loop.
Errors in bindings and handlers are warnings: QQmlEngine::warnings() reports them, with the file and line, and the application goes on.
C++ Types
qmlRegisterType() makes a QObject class a QML type of a module:
qmlRegisterType<Thermostat>("Home", 1, 0, "Thermostat");
Documents see its Q_PROPERTYs, signals, slots, Q_INVOKABLE methods and Q_ENUMs (as Thermostat.SomeValue). Q_CLASSINFO("DefaultProperty", "name") names the property that child objects go to; a QQmlListProperty property takes several. A class that inherits QQmlParserStatus is told when its component is complete. qmlRegisterSingletonType() and qmlRegisterSingletonInstance() make singletons, used by type name. qmlRegisterUncreatableType() makes a type that documents use but cannot make.
The QML_ELEMENT macros compile but do nothing, as Nt has no build step that reads them: register the types with these functions instead.
Types Written in QML
A file Badge.qml in the directory of a document is the type Badge there. import "dir" imports a directory of QML files, import Module a module from the import paths of the engine (QQmlEngine::addImportPath()), described by a qmldir file:
module Widgets
Panel 1.0 Panel.qml
singleton Style 1.0 Style.qml
component Name: Type { } declares an inline component, and Component { } a component that scripts make objects from with createObject(parent, properties).
The QtQml Module
QtObject, Timer, Connections and Component, and the Qt object: Qt.binding(), Qt.callLater(), Qt.quit(), Qt.exit(), Qt.point(), Qt.size(), Qt.rect(), Qt.formatDate(), Qt.formatTime(), Qt.formatDateTime(), Qt.createComponent(), Qt.createQmlObject(), Qt.resolvedUrl(), Qt.md5(), Qt.btoa(), Qt.atob(), Qt.platform.os and Qt.application. The JavaScript of documents is that of Using Nt Qml.
Not Yet Supported
Visual types (Qt Quick), attached properties other than Component.onCompleted and Component.onDestruction, Behavior and other "on" assignments, Binding, Loader, Repeater, models and views, JavaScript files imported by documents, required properties being checked, translations, and network URLs. Documents are interpreted, not compiled to C++.
The hello_qml example runs a document with a C++ type, a Timer and bindings.