qobject_impl

Attribute Macro qobject_impl 

Source
#[qobject_impl]
Expand description

Annotate an impl block to make its struct accessible from QML.

The macro implements a range of traits that are enable bridging from Rust to QML. The mechanism is based on the implementation of various traits with some code generated at macro expandsion time. You should not implement these traits yourself. As a user, you should only interact with:

This macro makes it possible to declare the following items within the impl block:

  • signals with the qsignal attribute macro
  • invokable functions with the qslot attribute macro
  • struct properties with the qproperty macro

Further, it allows the struct to implement traits to fulfill specific QML purposes. These are called Base traits. The available base traits are:

  • QListModel to make a struct accessible by QML ListView, QML Repeater, or similar.
  • QTableModel to make a struct accessible by QML TableView.

Only one of those traits can be implemented at the same time.

§Usage

The qobject_impl macro must be applied to a impl block of the target struct. Only a single impl block can be annotated with this macro and all applications of qsignal, qslot and qproperty have to be limited to this block.

In order to communicate with QML, the macro creates briding objects that are attached to the respective structs. Therefore, objects created with qobject_impl should be created with default_with_attached_qobject or expanded with attach_qobject. This is not necessary if the struct is instantiated in QML.

The macro creates, when register is called a QML module with name matching your Cargo package name. So for a Cargo.toml with

[package]
 name = "hello_world"

[dependencies]
qtbridge

the QML file has to contain

import hello_world

§Requirements

A struct annotated with qobject_impl must implement the Default trait. The static function register has to be called at the start of the main function to make this struct instantiable from QML. The macro implements Drop to call detach_qobject, cleaning up the QML parts of the object. You can implement Drop yourself when using the NoDrop option (see below). In that case, detach_qobject has to be called manually.

§Parameters

Parameters to adjust the macro behaviour are passed as comma-separated keywords or keyword-value pairs.

Base = BaseTrait

Set the ‘base’ trait. Requires that the specified trait is implemented for the corresponding struct.

NoQmlElement

Do not implement QmlRegister. QmlRegister registers the struct in the QML type system, allowing you to instantiate this type in QML. The NoQmlElement option can be useful to turn off instantiatability within QML or to provide a manual implementation of this trait with better control over naming and versioning.

Singleton

Implement QmlRegister as a singleton. A singleton is accessed from QML as a single shared instance of the type, using the type name as identifier. This is useful for application-wide data, global settings, or service objects.

NoDrop

Do not implement Drop in the macro. This option has to be set when a custom Drop implementation is required. The function attach_qobject has to be called manually to avoid memory leaks.

LinkMe

This option calls register at application without any additional code. The crate Linkme is used for this purpose and needs to be added to Cargo.toml.

§Example

use qtbridge::{QApp, qobject_impl};

#[derive(Default)]
pub struct Counter {
   value: i32,
}

#[qobject_impl(Singleton)]
impl Counter {
    qproperty!("value", Member = value, Notify = "valueChanged");

    #[qsignal]
    fn value_changed(&self);

    #[qslot]
    fn change_value(&mut self, inc: bool) {
        self.value = match inc {
            true => self.value.saturating_add(1),
            false => self.value.saturating_sub(1),
        };
        self.value_changed();
    }
}

const QML_CODE: &str =
r#"
    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    import qtbridge // must match your cargo package name

    ApplicationWindow {
        visible: true
        title: qsTr("Counter QML app")
        RowLayout {
            anchors.centerIn: parent
            Button {
                text: "-"
                onClicked: Counter.changeValue(false)
            }
            Button {
                text: "+"
                onClicked: Counter.changeValue(true)
            }
        }
    }
"#;

fn main() {
    QApp::new()
        .register::<Counter>()
        .load_qml(QML_CODE.as_bytes())
        .run();
}