Skip to content

Commit

Permalink
Add "Basics" tutorial
Browse files Browse the repository at this point in the history
This is the code developed during the second tutorial video:
https://www.youtube.com/watch?v=fdikaBcTgSM

It goes slightly beyond the minimal example, so add it as it's own
project.
It should also serve as a reference for backwards-compatibility.
  • Loading branch information
LeonMatthesKDAB committed Jan 23, 2025
1 parent 6c94838 commit d5b0c98
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `QDateTime::from_string` to parse `QDateTime` from a `QString`.
- Support for further types: `QUuid`
- New example: Basic greeter app

### Fixed

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"examples/demo_threading/rust",
"examples/qml_features/rust",
"examples/qml_minimal/rust",
"examples/qml_basics",

"tests/basic_cxx_only/rust",
"tests/basic_cxx_qt/rust",
Expand Down
20 changes: 20 additions & 0 deletions examples/qml_basics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
# SPDX-FileContributor: Leon Matthes <[email protected]>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

[package]
name = "cxx-qt-basics"
version = "0.1.0"
edition = "2021"
authors = [
"Leon Matthes <[email protected]>"
]

[dependencies]
cxx.workspace = true
cxx-qt.workspace = true
cxx-qt-lib = { workspace = true, features = [ "full" ] }

[build-dependencies]
cxx-qt-build = { workspace = true, features= [ "link_qt_object_files" ] }
17 changes: 17 additions & 0 deletions examples/qml_basics/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Leon Matthes <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//
use cxx_qt_build::{CxxQtBuilder, QmlModule};
fn main() {
CxxQtBuilder::new()
.qml_module(QmlModule {
uri: "com.kdab.tutorial",
qml_files: &["qml/main.qml"],
rust_files: &["src/main.rs"],
..Default::default()
})
.qt_module("Network")
.build();
}
55 changes: 55 additions & 0 deletions examples/qml_basics/qml/main.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Leon Matthes <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.12

import com.kdab.tutorial 1.0

ApplicationWindow {
width: 640
height: 480
visible: true

Greeter {
id: greeter
}

RowLayout {
anchors.fill: parent

Label { text: qsTr("Greeting") }
ComboBox {
textRole: "name"
valueRole: "value"
onActivated: greeter.greeting = currentValue

model: [{ name: qsTr("Hello World!"), value: Greeter.Hello },
{ name: qsTr("Bye!"), value: Greeter.Bye }]

Component.onCompleted: currentIndex = indexOfValue(greeter.greeting)
}

Label { text: qsTr("Language") }
ComboBox {
textRole: "name"
valueRole: "value"
onActivated: greeter.language = currentValue

model: [{ name: qsTr("English"), value: Greeter.English },
{ name: qsTr("French"), value: Greeter.French },
{ name: qsTr("German"), value: Greeter.German }]

Component.onCompleted: currentIndex = indexOfValue(greeter.language)
}

Button {
text: qsTr("Greet")
onClicked: console.warn(greeter.greet())
}
}
}
90 changes: 90 additions & 0 deletions examples/qml_basics/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Leon Matthes <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cxx_qt::bridge]
mod qobject {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString;
}

#[qenum(Greeter)]
pub enum Language {
English,
German,
French,
}

#[qenum(Greeter)]
pub enum Greeting {
Hello,
Bye,
}

unsafe extern "RustQt" {
#[qobject]
#[qml_element]
#[qproperty(Greeting, greeting)]
#[qproperty(Language, language)]
type Greeter = super::GreeterRust;

#[qinvokable]
fn greet(self: &Greeter) -> QString;
}
}

use qobject::*;

impl Greeting {
fn translate(&self, language: Language) -> String {
match (self, language) {
(&Greeting::Hello, Language::English) => "Hello, World!",
(&Greeting::Hello, Language::German) => "Hallo, Welt!",
(&Greeting::Hello, Language::French) => "Bonjour, le monde!",
(&Greeting::Bye, Language::English) => "Bye!",
(&Greeting::Bye, Language::German) => "Auf Wiedersehen!",
(&Greeting::Bye, Language::French) => "Au revoir!",
_ => "🤯",
}
.to_string()
}
}

pub struct GreeterRust {
greeting: Greeting,
language: Language,
}

impl Default for GreeterRust {
fn default() -> Self {
Self {
greeting: Greeting::Hello,
language: Language::English,
}
}
}

use cxx_qt_lib::QString;

impl qobject::Greeter {
fn greet(&self) -> QString {
QString::from(self.greeting.translate(self.language))
}
}

fn main() {
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};

let mut app = QGuiApplication::new();
let mut engine = QQmlApplicationEngine::new();

if let Some(engine) = engine.as_mut() {
engine.load(&QUrl::from("qrc:/qt/qml/com/kdab/tutorial/qml/main.qml"));
}

if let Some(app) = app.as_mut() {
app.exec();
}
}

0 comments on commit d5b0c98

Please sign in to comment.