-
Hello! In a similar fashion to this post I made on CXX-Qt's discussions, I'm interested in knowing how Slint fairs with async Rust. I've been interested in cross-platform GUIs for a while, particularly with Rust and QtQuick/QML. I discovered Slint at the beginning of last year, but haven't really dived into it yet. However, I'm quite curious, since it's made by Qt folks, is clearly heavily inspired by the modern QtQuick/QML system and has first-party support for Rust. Async/await is becoming ever more prevalent, with many new API wrappers and the likes being published exclusively as async crates. One particular example I'm interested on is the great matrix-rust-sdk, which is now powering clients such as Element X iOS (Rust+SwiftUI), Element X Android (Rust+Jetpack Compose) and Fractal (Rust+GTK4). I'd like to play around with making a desktop client with Rust and either QtQuick/QML or Slint :) How does using an async library like the one mentioned above in a Slint UI look like? Is there first-party support? If not, are there plans for such a thing? On another somewhat related note, are there any major show stoppers in Slint in terms of feature parity with QML, specially with regards to accessibility and portability? Thank you! |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 17 replies
-
I have seen people use tokio with slint, but am no authority on how to do that. AFAICT you set aside one thread for the UI, pretty much like you would in Qt, too. Nothing Slint needs to support too much:-) I have not really used Qt in a while, so I do not feel qualified to do a comparison -- but here is the Slint side of the picture: Slint has support for accessibility, but this area could use some more work to make it truly great. In my experience that is the case with most accessibility systems out there though. The limiting factor for portability of Slint is the rust compiler. In my experience all the interesting things are supported there, but some people will miss their favorite CPU architectures. Slint can be made to work pretty much everywhere the rust compiler can generate code for, it does not even need the full rust standard library. Language portability of Slint is very good IMHO: We officially support Rust, C++ and JS as business logic languages and are currently adding python into the mix. A community member has used Slint from C#. We are of course always open for more languages:-) The Slint language itself has a very strict separation between business logic and UI. I like that a lot. Basically a designer can design to his hearts content and a developer can refactor the code as needed -- as long as the interface between UI and business logic stays untouched, they will not break each others work. It also will allow us to have great tooling (soon;-) and makes support for so many different languages possible. I am sure compared to Qt we do miss out on features. Most of that is by design: We happily delegate to rust infrastructure (e.g. docs, build tooling, etc.) and other people's crates (== rust libraries). Of course we also have features missing simply because nobody had the time to implement them yet. In my experience most bases are covered, as we tend to focus on those area the most people report issues in;-) And contributions are always welcome, too. I hope this helps at least a bit. |
Beta Was this translation helpful? Give feedback.
-
For async, Slint can run future in the UI thread with the slint::spawn_local function. You can also run other async executor (eg, tokio) on another thread. It is fairly easy to call back into the ui thread with slint::invoke_from_event_loop. |
Beta Was this translation helpful? Give feedback.
-
Just to add to above example, as it took a bit to wrap my mind around. runtime.clone().on_state_change.lock().await.subscribe({
let ui_handle = ui_handle.clone();
move |state| {
let ui_handle = ui_handle.clone();
slint::invoke_from_event_loop(move || {
let ui = ui_handle.clone().unwrap();
// do stuff with ui...
}).unwrap();
}
}).await; Here I queue up a lambda that will be invoked from a different thread to be run on main UI thread. This is more or less identical to how WPF dispatches calls from other threads on main ui thread (through a message queue). Make sure you are not sending ui handles to methods with Sync traits (as Slint is not multi-threaded). In short, there are no issues spawning threads from main UI thread, or having parallel threads make calls to slint ui. |
Beta Was this translation helpful? Give feedback.
-
Nice, thank you for the extra snippet!
For the project I'm working on, because of all the repetitiveness and
verbosity of this approach, I made some macros that greatly simplify
callbacks and so on. I'm still not 100% sold on them, but they're here:
https://git.sr.ht/~tmpod/eigen/tree/main/item/src/utils.rs
|
Beta Was this translation helpful? Give feedback.
-
Here is a working example updated from here. I would be interested to hear if this would be the proper "slint" way to do async. The UI:
The Main Rust:
AND id_map_data.rs
|
Beta Was this translation helpful? Give feedback.
For async, Slint can run future in the UI thread with the slint::spawn_local function.
With that function you can spawn future and call async function from a callback handler, for example.
You can also run other async executor (eg, tokio) on another thread. It is fairly easy to call back into the ui thread with slint::invoke_from_event_loop.