diff --git a/book/src/getting-started/1-qobjects-in-rust.md b/book/src/getting-started/1-qobjects-in-rust.md
index 15dc549ed..92e9a7e21 100644
--- a/book/src/getting-started/1-qobjects-in-rust.md
+++ b/book/src/getting-started/1-qobjects-in-rust.md
@@ -44,12 +44,11 @@ These concepts include:
- Enums
As with CXX, to use these features you mark a Rust module with an attribute macro ([`#[cxx_qt::bridge]`](../bridge/index.md)).
-
-Then you can use the afformentioned features with the help of extern blocks and macros to express them in a [Rust bridge](../bridge/index.md).
+Inside this bridge, you then describe the bi-directional interface between your C++/Qt and Rust code.
CXX-Qt will then expand this Rust bridge into two separate parts:
-- C++ files that define a QObject, enums etc to Qt.
-- The Rust code which provides the implementation of the features
+- C++ files that define QObjects, enums etc. and expose them to [Qts meta-object-system](https://doc.qt.io/qt-6/metaobjects.html).
+- The Rust code which provides the Rust implementation of the described structures, as well as interfaces to any C++/Qt constructs you declared.
@@ -57,20 +56,18 @@ CXX-Qt will then expand this Rust bridge into two separate parts:
-CXX-Qt also generates the code needed for interaction of the C++ QObject subclass and the `#[qobject]` marked struct using the [CXX library](https://cxx.rs/).
-For more details, see the [Bridge](../bridge/index.md) page.
+## Rust structs as QObjects
-The important take away here is the duality of any subclass generated by CXX-Qt.
-These classes are made up of the actual QObject subclass instance that C++ interacts with, as well as an instance of the Rust struct on the Rust side.
-When such a QObject is instantiated, it will always also construct an instance of the Rust struct as well.
-The lifetime of the Rust struct will be bound to that of the QObject.
-If the QObject is deleted, the Rust struct will be deleted as well.
-Typically this will be instantiated by QML and the lifetime will be directly associated with the corresponding QML item.
+Similar to CXX, CXX-Qt allows you to expose Rust structs as a new type to C++.
+However, CXX-Qt expands this feature to allow you to create a new QObject subclass that is backed by a Rust struct.
+In comparison to a normal opaque CXX class, the mapping between the QObject subclass and the Rust struct is **not 1:1**!
-The generated QObject subclass will then defer to the Rust struct for any behavior, which is then defined in Rust.
-For example, using the [`#[qinvokable]`](../bridge/extern_rustqt.md#invokables) attribute, we can define functions that will be exposed to C++, but will execute Rust code.
-Also, any fields in the Rust struct can be exposed to Qt as `Q_PROPERTY` fields by using the [`#[qproperty(T, NAME)]`](../bridge/extern_rustqt.md#properties) attribute.
-Therefore allowing you to assign them from QML as well.
+The QObject subclass it its own type in Rust, as well as in C++.
+When such a QObject is instantiated, it will always also construct an instance of the Rust struct.
+The QObject can then refer to the underlying Rust struct for property access.
+Any behavior of this QObject subclass will also be defined in Rust, e.g. using the [`#[qinvokable]`](../bridge/extern_rustqt.html#invokables) attribute.
+The Rust implementation also has access to the underlying Rust struct to modify any Rust data.
+In comparison to most CXX types, the outer QObject class and the inner Rust struct will remain two distinct types!
But enough theory for now, lets jump in and write [our first CXX-Qt module](./2-our-first-cxx-qt-module.md).
diff --git a/book/src/getting-started/2-our-first-cxx-qt-module.md b/book/src/getting-started/2-our-first-cxx-qt-module.md
index 26dc53ce4..e244117fa 100644
--- a/book/src/getting-started/2-our-first-cxx-qt-module.md
+++ b/book/src/getting-started/2-our-first-cxx-qt-module.md
@@ -16,14 +16,15 @@ tutorial
- rust
```
-As with all things Rust, we'll want to create a cargo project, run the following command inside the `tutorial` folder to initialise the Rust part of the project.
+As with all things Rust, we'll want to create a cargo project, run the following command inside the `tutorial` folder to initialize the Rust part of the project.
```bash
cargo init --lib rust
```
Note the `--lib` option here. For this example, we will create a static library in Rust and use CMake to
link this into a C++ executable. We'll discuss details of this later, when we [integrate our Rust project with CMake](./4-cmake-integration.md).
-As outlined in the previous section, to define a new QObject subclass, we'll create a Rust module within this library crate.
+As outlined in the previous section, to use CXX-Qt, we'll create a Rust module within this library crate.
+This Rust module will then serve as our interface between Qt and Rust.
First, in the `rust/src/lib.rs`, we tell Cargo about the module we're about to create:
```rust,ignore
@@ -31,14 +32,14 @@ First, in the `rust/src/lib.rs`, we tell Cargo about the module we're about to c
```
Now, we need to create a file `rust/src/cxxqt_object.rs` for that module.
-It will include our `#[cxx_qt::bridge]` that allows us to create our own qobjects in Rust:
+It will include our `#[cxx_qt::bridge]` that allows us to interact with Qt concepts.
+
+This is a lot to take in, so let's go one step at a time.
```rust,ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_cxx_qt_module}}
```
-This is a lot to take in, so let's go one step at a time.
-
## CXX-Qt bridge module
Starting with the module definition:
```rust,ignore
@@ -48,75 +49,110 @@ Starting with the module definition:
```
A `#[cxx_qt::bridge]` is the same as a `#[cxx::bridge]` and you can use all features of CXX in it.
-Additionally, a `#[cxx_qt::bridge]` gives you a few more features that allow you to create QObjects.
+Additionally, a `#[cxx_qt::bridge]` gives you a few more features that allow you to create QObjects from Rust or declare existing QObjects for access from Rust.
+
+## `extern "RustQt"`
+
+Like `extern "Rust"` and `extern "C++"` in CXX, CXX-Qt provides `extern "RustQt"` and `extern "C++Qt"`.
+
+These `extern` blocks instruct CXX-Qt to where the implementation of our interface lives.
+Anything that is marked as `extern "RustQt"` is implemented in Rust and will be exposed to C++.
+Conversely anything inside `extern "C++Qt"` is implemented in C++ and will be exposed to Rust.
## QObject struct
-To create a new QObject subclass, we can define a type alias within a `extern "RustQt"` block in our module and mark it with `#[qobject]`.
+First we will create a new QObject subclass.
+As we want to implement it in Rust, we need to place our interface inside `extern "RustQt"`.
+
+To create a new QObject subclass that will be defined in Rust, use a type-alias and mark it with `#[qobject]`.
+In our case the new class will be named `MyObject` and will be backed by a Rust struct named `MyObjectRust`.
```rust,ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_rustobj_struct_signature}}
```
-The Rust struct can be defined outside the module just like a normal Rust struct and can contain any kind of field, even Rust-only types.
+The Rust struct must be defined **outside** the bridge module and is therefore referred to using `super::`.
+This just needs to be a normal Rust struct and can contain any kind of field, even Rust-only types that are not compatible with CXX.
+
+Unless we want to use CXX-Qt's [Constructor feature](../traits/constructor.md) we just need to ensure that this struct implements Rusts `Default` trait
+In this case we just use `#[derive(Default)]` on the struct.
```rust,ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_rustobj_struct}}
```
-Optionally, add `qml_element` inside `#[qobject]` to tell the Rust build script to generate a QML_ELEMENT
-that will register the QObject with QML engine at startup. If you want the name of the QML type and the Rust type to be different,
-you can also add `qml_name = "OtherName"`. This takes the place of the
-[qt_add_qml_module CMake function](https://doc.qt.io/qt-6/qt-add-qml-module.html) (because that doesn't work with CXX-Qt's build system).
+Now the `#[qobject]` macro will take care of creating a new QObject subclass named `MyObject`.
+Every instance of that class will also include an instance of the `MyObjectRust` struct that the `MyObject` class will defer to for any data or behavior.
-Additionally, we need to either `impl Default` or `#[derive(Default)]` for our struct.
-```rust,ignore
-{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_rustobj_default}}
-```
+To automatically export this new class to QML, we mark it with the `#[qml_element]` attribute.
+This is the same as specifying [`QML_ELEMENT`](https://doc.qt.io/qt-6/qqmlengine.html#QML_ELEMENT) in C++.
+This takes the place of the [qt_add_qml_module CMake function](https://doc.qt.io/qt-6/qt-add-qml-module.html)
+(because that doesn't work with CXX-Qt's build system).
-The `#[qproperty]` attribute on the type alias will create properties to the fields matching the name and be exposed to the C++ side as a `Q_PROPERTY`.
+The `#[qproperty]` attribute will create a [`Q_PROPERTY`](https://doc.qt.io/qt-6/properties.html) for the given type and field name.
+CXX-Qt will then:
+1. Create the `Q_PROPERTY` on the QObject type.
+2. Create a `NOTIFY` signal for when the property changes.
+3. Generate getters and setters that use the underlying Rust fields and emit the NOTIFY signal on changes.
-That means the newly created QObject subclass will have two properties as members: `number` and `string`. For names that contain multiple words, like `my_number`, CXX-Qt will automatically rename the field from snake_case to camelCase to fit with C++/QML naming conventions (e.g. `myNumber`).
+In this case the newly created QObject subclass will have two properties: `number` and `string`.
+CXX-Qt expects a field for each property to exist in the underlying Rust struct.
+For names that contain multiple words, like `my_number`, CXX-Qt will automatically rename the field from snake_case to camelCase to fit with C++/QML naming conventions (e.g. `myNumber`).
### Types
-Do note though that any fields exposed as `#[qproperty]` must be types that CXX can translate to C++ types.
+Please note that any fields exposed as `#[qproperty]` must have types that CXX can translate to C++ types.
In our case that means:
-- `number: i32` -> `::std::int32_t number`
-- `string: QString` -> `QString string`
+- `#[qpoperty(i32, number)]` -> `Q_PROPERTY(::std::int32_t number ...)`
+- `#[qproperty(QString, string)` -> `Q_PROPERTY(QString string ...)`
For `i32`, CXX-Qt already knows how to translate it.
A `QString` however is unknown to CXX.
Luckily, the [`cxx_qt_lib`](https://docs.rs/cxx-qt-lib/latest/cxx_qt_lib/) crate already wraps many Qt types for us.
-We can just define them in the bridge like any other CXX type:
+We can just include them in the bridge like any other CXX type:
``` rust, ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_qstring_import}}
```
For more details on the available types, see the [Qt types page](../concepts/types.md).
-## Invokables
+-------
-CXX-Qt will then automatically generate a new QObject subclass for our `MyObjectRust` struct and expose it as an [`extern "C++"` opaque type](https://cxx.rs/extern-c++.html#opaque-c-types) to Rust.
-For any type alias `type T = super::S` marked with `#[qobject]`, CXX-Qt will expose the corresponding C++ QObject under `T`.
-In our case, this means we can refer to the C++ QObject for our `MyObjectRust` struct, as `MyObject`.
+CXX-Qt will then automatically generate a new QObject subclass called `MyObject` and expose it as an [`extern "C++"` opaque type](https://cxx.rs/extern-c++.html#opaque-c-types) back to Rust.
+In our case, this means we can refer to the C++ QObject as `qobject::MyObject`, as it is defined inside the `mod qobject`.
This type can be used like any other CXX opaque type.
-Additionally, CXX-Qt allows us to add functionality to this QObject by referring to the type as the self type of functions in an `extern "RustQt"` block in together with `#[qinvokable]`.
+
+## Invokables
+
+Additionally, CXX-Qt allows us to add functionality to this QObject by referring to the type as the self type of functions in an `extern "RustQt"` block.
```rust,ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_rustobj_invokable_signature}}
```
-And then implementing the invokables outside the bridge using `impl qobject::MyObject`.
+This works the same as exposing any other [member function with CXX](https://cxx.rs/extern-rust.html#methods) in an `extern "Rust"` block.
+Additionally CXX-Qt understands the `#[qinvokable]` attribute and marks the member function as [`Q_INVOKABLE`](https://doc.qt.io/qt-6/qtqml-cppintegration-exposecppattributes.html#exposing-methods-including-qt-slots).
+This means they can be called from QML.
+
+
+
+These functions then need to be implemented outside the bridge using `impl qobject::MyObject`.
```rust,ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_rustobj_invokable_impl}}
```
-> Note that by using `qobject` instead of `ffi` as the module name for the bridge,
-> referring to the C++ QObject outside the bridge becomes a natural `qobject::MyObject`
+This setup is a bit unusual, as the type `qobject::MyObject` is actually defined in C++.
+However, it is still possible to add member functions to it in Rust and then expose them back to C++.
+This is the usual workflow for QObjects in CXX-Qt.
+CXX-Qt will define the QObject class itself in C++, but defer to Rust for any behavior.
+
+> Note that we recommend calling the bridge module `qobject` instead of the CXX-typical `ffi`.
+> This way accessing the C++ QObject outside the bridge becomes a natural `qobject::MyObject`
> instead of `ffi::MyObject`.
+>
+> Feel free to choose any module name you like though.
-Also do not forget to use the relevant imports that are required for the invokable implementation.
+Also do not forget to import everything required for the invokable implementation.
```rust,ignore
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_use}}
@@ -132,12 +168,12 @@ In our case, we define two new functions:
Because we are implementing on the `qobject::MyObject` type instead of the `MyObject` type, `self` here is the C++ QObject that is generated from our `MyObject` struct.
As this type is a CXX Opaque type, we can't actually instantiate it.
-Qt/C++ takes care of this.
-However, we can still define Rust functions on this type.
-They will just be normal Rust functions, but will be executed on a C++ type.
-CXX-Qt will already generate getters and setters for all properties of your struct this way.
-If you additionally define these in the `extern "RustQt"` block of the bridge, they will also be callable from C++ and QML.
-In this case, the types of the arguments also need to convertable to C++, like with any `#[qproperty]`.
+Our Qt code will take care of this.
+Also, we can't move the QObject, which is why it is behind a Rust [`Pin`](https://doc.rust-lang.org/std/pin/struct.Pin.html).
+
+CXX-Qt will generate getters and setters for all properties of our struct.
+That's where the `number()` and `set_number()` functions used by `increment_number()` come from.
+For more details on what you can do with the QObject from Rust and what functions CXX-Qt will generate for you, take a look at the [QObject page](../concepts/generated_qobject.md).
And that's it. We've defined our first QObject subclass in Rust. That wasn't so hard, was it?
diff --git a/book/src/getting-started/3-qml-gui.md b/book/src/getting-started/3-qml-gui.md
index c90d0e3a3..59feab04e 100644
--- a/book/src/getting-started/3-qml-gui.md
+++ b/book/src/getting-started/3-qml-gui.md
@@ -17,6 +17,7 @@ So let's add a `main.qml` file in a `qml` folder:
```
If you're not familiar with QML, take a look at the [Qt QML intro](https://doc.qt.io/qt-6/qmlapplications.html).
+We of course also recommend our [QML Intro Training](https://www.kdab.com/software-services/on-site-training/qt-onsite/programming-qtqml-onsite-training/).
This code will create a pretty simple GUI that consists of two Labels and two Buttons.
The important part here is the use of the `MyObject` type.
@@ -30,25 +31,7 @@ As you can see here, CXX-Qt has converted the snake_case of the function names t
This way the `MyObject` doesn't seem at all out of place in QML.
It is again important to emphasize here that `MyObject` is just another QObject subclass and can be used just like any other `QObject` subclass.
-The only difference being that any invokable functions that are defined are defined in Rust, instead of C++.
+The only difference being that any invokable functions are defined in Rust, instead of C++.
For QML, this doesn't make a difference though.
-# Qt resources
-
-To include the `main.qml` file inside the application, use the [Qt resource system](https://doc.qt.io/qt-6/resources.html) by listing it in the `qml_files` part of our QML module in the `build.rs` file:
-
-
-
-```rust,ignore
-{{#include ../../../examples/qml_minimal/rust/build.rs:book_qml_module}}
-```
-
-In the `main.cpp` we then use the URL of the `main.qml` file inside the QML module.
-
-``` cpp, ignore
-{{#include ../../../examples/qml_minimal/cpp/main.cpp:book_qml_url}}
-```
-
Now that we have some application code, let's get this project [building and running](./4-cmake-integration.md).
diff --git a/book/src/getting-started/4-cmake-integration.md b/book/src/getting-started/4-cmake-integration.md
index 5637fd030..aa7babe71 100644
--- a/book/src/getting-started/4-cmake-integration.md
+++ b/book/src/getting-started/4-cmake-integration.md
@@ -36,7 +36,7 @@ That's the power of CXX-Qt.
## Cargo setup
Before we can get started on building Qt with CMake, we first need to make our Cargo build ready for it.
-If you've generated your project with the `cargo new --lib` or `cargo init --lib folder` command, your `Cargo.toml` likely looks something like this:
+If you've generated your project with the `cargo new --lib` or `cargo init --lib folder` command, your `Cargo.toml` should look something like this:
```toml,ignore
[package]
name = "qml-minimal"
diff --git a/book/src/getting-started/index.md b/book/src/getting-started/index.md
index e450e9a1d..144394b7d 100644
--- a/book/src/getting-started/index.md
+++ b/book/src/getting-started/index.md
@@ -13,7 +13,8 @@ In this guide we'll go through a minimal example that uses CXX-Qt to create your
### Prerequisites
This guide won't be able to explain everything to you, but it will try its best to make sure everyone can follow along.
-However, a few things you should make sure you're familiar with before attempting to follow this guide, as it may be confusing otherwise.
+However, there are a few things you should be familiar with before reading this guide.
+It may be confusing otherwise!
First of all, you should be familiar with Rust. There are many great resources for learning Rust, like [the book](https://doc.rust-lang.org/book/).
diff --git a/examples/qml_minimal/rust/src/cxxqt_object.rs b/examples/qml_minimal/rust/src/cxxqt_object.rs
index 9be9646e0..60d7ec8ab 100644
--- a/examples/qml_minimal/rust/src/cxxqt_object.rs
+++ b/examples/qml_minimal/rust/src/cxxqt_object.rs
@@ -23,6 +23,9 @@ pub mod qobject {
// ANCHOR: book_rustobj_struct_signature
unsafe extern "RustQt" {
+ // The QObject definition
+ // We tell CXX-Qt that we want a QObject class with the name MyObject
+ // based on the Rust struct MyObjectRust.
#[qobject]
#[qml_element]
#[qproperty(i32, number)]
@@ -33,6 +36,7 @@ pub mod qobject {
// ANCHOR: book_rustobj_invokable_signature
unsafe extern "RustQt" {
+ // Declare the invokable methods we want to expose on the QObject
#[qinvokable]
fn increment_number(self: Pin<&mut MyObject>);
@@ -49,28 +53,18 @@ use cxx_qt_lib::QString;
/// The Rust struct for the QObject
// ANCHOR: book_rustobj_struct
+#[derive(Default)]
pub struct MyObjectRust {
number: i32,
string: QString,
}
// ANCHOR_END: book_rustobj_struct
-// ANCHOR: book_rustobj_default
-impl Default for MyObjectRust {
- fn default() -> Self {
- Self {
- number: 0,
- string: QString::from(""),
- }
- }
-}
-// ANCHOR_END: book_rustobj_default
-
// ANCHOR: book_rustobj_invokable_impl
impl qobject::MyObject {
/// Increment the number Q_PROPERTY
pub fn increment_number(self: Pin<&mut Self>) {
- let previous = *self.as_ref().number();
+ let previous = *self.number();
self.set_number(previous + 1);
}