Crate qmetaobject

source ·
Expand description

This crate implements binding to the Qt API which allow to use QML from a rust application.

Example:

use cstr::cstr;
use qmetaobject::prelude::*;

// The `QObject` custom derive macro allows to expose a class to Qt and QML
#[derive(QObject,Default)]
struct Greeter {
    // Specify the base class with the qt_base_class macro
    base: qt_base_class!(trait QObject),
    // Declare `name` as a property usable from Qt
    name: qt_property!(QString; NOTIFY name_changed),
    // Declare a signal
    name_changed: qt_signal!(),
    // And even a slot
    compute_greetings: qt_method!(fn compute_greetings(&self, verb: String) -> QString {
        format!("{} {}", verb, self.name.to_string()).into()
    })
}

fn main() {
    // Register the `Greeter` struct to QML
    qml_register_type::<Greeter>(cstr!("Greeter"), 1, 0, cstr!("Greeter"));
    // Create a QML engine from rust
    let mut engine = QmlEngine::new();
    // (Here the QML code is inline, but one can also load from a file)
    engine.load_data(r#"
        import QtQuick 2.6
        import QtQuick.Window 2.0
        // Import our Rust classes
        import Greeter 1.0

        Window {
            visible: true
            // Instantiate the rust struct
            Greeter {
                id: greeter;
                // Set a property
                name: "World"
            }
            Text {
                anchors.centerIn: parent
                // Call a method
                text: greeter.compute_greetings("hello")
            }
        }
    "#.into());
    engine.exec();
}

Basic types

The re-exported crate qttypes contains binding to the most usefull basic types such as QString, QVariant, …

You can also simply use rust type String, but using QString might avoid unecessary conversions in some case.

Meta type

In order to be able to use a type in a signal or method parameter, or as a property type, the type need to implement the QMetaType trait. All the method are provided so you can just implement the QMetaType like this:

use qmetaobject::QMetaType;

#[derive(Default, Clone)]
struct MyPoint(u32, u32);

impl QMetaType for MyPoint {};

With that it is also possible to put the type in a QVariant

Object pinning

Once an object that derives from QObject is exposed to C++, it needs to be pinned, and cannot be moved in memory. Also, since the Qt code can be re-entrant, the object must be placed in a RefCell. The QObjectPinned object is used to enforce the pinning.

If you want to keep pointer to reference, you can use QPointer.

Threading

The QML engine only runs in a single thread. And probably all the QObjects needs to be living in the Qt thread. But you can use the queued_callback function to create callback that can be called from any thread and are going to run in the Qt thread.

This can be done like so:

use qmetaobject::prelude::*;

#[derive(QObject, Default)]
struct MyAsyncObject {
    base: qt_base_class!(trait QObject),
    result: qt_property!(QString; NOTIFY result_changed),
    result_changed: qt_signal!(),
    recompute_result: qt_method!(fn recompute_result(&self, name: String) {
        let qptr = QPointer::from(&*self);
        let set_value = qmetaobject::queued_callback(move |val: QString| {
            qptr.as_pinned().map(|this| {
                this.borrow_mut().result = val;
                this.borrow().result_changed();
            });
        });
        std::thread::spawn(move || {
            // do stuff asynchronously ...
            let r = QString::from("Hello ".to_owned() + &name);
            set_value(r);
        }).join();
    })
}

Re-exports

Modules

Macros

  • Embed files and made them available to the Qt resource system.
  • This macro must be used once as a type in a struct that derives from QObject. It is anotate from which QObject like trait it is supposed to derive. the field which it annotate will be an internal property holding a pointer to the actual C++ object
  • This macro can be used to declare a method which will become a meta method.
  • Equivalent to the Q_PLUGIN_METADATA macro.
  • This macro can be used as a type of a field and can then turn this field in a Qt property. The first parameter is the type of this property. Then we can have the meta keywords similar to these found in Q_PROPERTY.
  • Declares a signal

Structs

Enums

Constants

  • Refer to the documentation of Qt::UserRole

Traits

  • Trait that is implemented by the QEnum custom derive macro
  • Trait that is implemented by the QGadget custom derive macro
  • Trait that is implemented by the QObject custom derive macro

Functions

Type Aliases