Finding a Rust GUI that is easy to use

I've been looking for a Rust GUI crate to use with my project and so far have come up dry. My criteria are as follows:

  1. The documentation for the crate must be well-written and easy for a relative novice like myself to follow/decipher. Especially important to me is that it include many examples (examples that don't rely on an assert!() call to show that it works) that show how to use the functions and methods contained in the crate.

  2. It should be simple to use. I say that in a relative sense, since the idea of "simple" very much depends on the expertise of the user. While I have been progressing in my knowledge of Rust, as I said, I'm still a relative novice so that has to be factored into how one would consider a Rust GUI crate to be "simple" to use.

  3. It would be nice if it was written in native Rust rather than being a wrapper around a library written in some other language. That desire is not graven in stone, it's just that I've found that the crates that are based on code from some other language have poor Rust documentation that is difficult to follow.

    Anyway, I'm hoping this post will spark some good discussion on that topic, and, through that discussion, I will be able to settle on a good GUI crate to use in my project.

    Thanks for your help.

1 Like

If you're into immediate mode GUIs, then have a look at egui.

There's many examples in the repo, but where it really shines is the web demo: you can get the code of every fancy thing you see there!

1 Like

If you are interested in or are already working with the Elm Architecture or just prefer more event driven development, my personal favourite is iced. It's Rust native, can be compiled for native and web platforms and is very well documented and tooled. If you can't find a widget you're looking for in iced::widget, chances are you'll be able to find it in iced_aw.

I like it for it's effective use of the builder pattern in it's API design as well as the way it defines the size of widgets (see Length). Theming is little hard to get to grips with at first, but once you have you get the advantage of consistent design across your entire app, which help to get rid of UI boilerplate.

2 Likes

Thanks for replying, @ScratchCat458. I took a look at iced a while back and kept seeing references to The Elm Architecture. I haven't seen a good explanation of it, though. Could you expand on that a little? Maybe share how it works well for you? Thanks.

1 Like

@rikyborg,
I really appreciate it that you got back to me on this. Thank you. I did take a look at egui a couple of weeks ago, Like you, I thought the web demo was excellent and would be useful if I decided to incorporate egui into my project. However, I came away feeling that it was rather complicated to use, so didn't spend a lot of time checking the crate out. Of course, that means I'm likely not getting a clear picture of how egui works or its ease of use. Since I'm not the most skilled Rust programmer, simplicity and documentation are very important. Could you, please, expand on how egui works for you and how easy a less-than-proficient coder like me is going to find it to work with? Thanks!

1 Like

The Elm Architecture is very reminiscent of functional patterns. It is broken up into the model, the view and update mechanism. The model is your state, in Iced this would be the struct (or enum) that you are implementing Application or Component on. The view is the UI shown to the user, which can access the model/state for rendering purposes, but only immutably. This is shown in the function signature of the view method:

fn view(&self) -> Element<'_, Self::Message, Renderer<Self::Theme>>;

To update data, elements of the UI are allowed to send Messages on events, which is usually an enum. The update method is allowed to make changes to application state and in the case of Iced, send futures to run which can produce another Message on completing, allowing more expensive operations to run the background. After an Update occurs, the View is re-rendered with the new state of the application. Iced provides another construct for localising logic to specific parts of your UI. Components manage their own state and can handle internal updates through Events, but can still produce Messages to connect with the wider application.

One of the advantages of this design architecture is that you can make events you don't care about unrepresentable through the power of the type system. Gone is the mental modelling of bidirectional data binding and other components being able to modify state in a way that you don't intend. The pattern of messages makes it really easy to see how data flows across your application and components allow you to prevent the problem of everything becoming a ball of fiery mutable state.

For me as a developer, Iced and the Elm Architecture give me something I value highly from Rust as language but in my UI workflow. Control. As someone who values modelling my application state in great detail, the advantage of being able extend this to the flow and modification of data is very appealing. But even the little things about its API design are really well thought out. Traits are used to model the visual style of components in their different states (pressed, hovered, focuses) and having an application-wide style system (see iced::theme) is very helpful for consistency in my interfaces. Length is a very useful abstraction that allows fixed and fractional sizes to seamlessly interact in design.

I'd say the best way to see if this suits your personal design principles is to look at some of the examples and try writing an application yourself. Who knows, you might fall in love with a new design pattern. :wink:

5 Likes

I guess I should have started with the disclaimer that I'm far from an experienced GUI programmer! I actually have an instinctive distaste for feel very uncomfortable with GUI programming, it's something I find hard and time consuming, and I'm never satisfied with the results I get. I feel much more at ease in low-level and embedded domains.

That said, I have done some amount of GUI programming in the past with Python using wxPython (bindings for wxWidgets). The feeling I got there was that I was always hacking my way around, and the app was slowly growing into a mess of interdependent state, callbacks, cyclic references, ... It was in general hard to understand what was going on.

Which is why nowadays I really like the concept of immediate mode GUIs (like egui): the entire UI is redrawn from scratch every frame, which means it doesn't contain any state, nor callbacks and references to other parts of your code. I find this architecture much simpler to reason about. The egui author has a much better explanation of why immediate mode can be a good choice.

That was the case for me too. It was not immediate to understand how to set up the project at first, but then the actual coding was rather smooth.

One important thing I had forgotten to mention in my previous post, is that to get started with egui you actually need a framework. I now remember that most of my troubles with getting started were because I didn't understand that. The good default choice is eframe, see also what is the difference between egui and eframe.

For the setup, the eframe template repo could help.

For a general understanding, I just found this video tutorial (linked from the eframe README) that should help. It starts with a (short) general discussion of different GUI frameworks in Rust, then goes on implementing an app using egui and eframe. I only skimmed through it, but seems useful!

Sorry I can't be more helpful, as I said above I'm really not "a GUI guy", but I try to give it a go every now and then.


As an aside, for retained mode GUIs (not immediate mode), I heard great things about iced too, just like @ScratchCat458 suggested. I haven't tried it myself though.

1 Like

We've had some good discussion about iced and egui and I'm in the process of digging into those two Rust GUI's to see if I can make them work for me. A while back I looked at GTK as a possible GUI I could use. Is there a GTK user out there who might be willing to share his/her thoughts about how well GTK might work for me? Thanks.

Ok, so it's time I got more organized at checking these GUI crates out. So, here's my list of to-do's to guide me. If I can accomplish these tasks without too much trouble, the crate in question may very well be the one for me.

/*
    -- Open a window.
        -- Add a number input widget. 
        -- Add a checkbox widget. 
        -- Add a radio checkbox widget. 
        -- Add a text input box. 

    -- Is there an existing piece of code I can use/modify 
        to eventually add an editor to my project? 

*/     

First on my list is Iced.

I can provide some piece of code for your to-do list, powered by the crate tk and crate tcl..

use tcl::*;
use tk::cmd::*;
use tk::*;

fn main() -> TkResult<()> {
    let tk = make_tk!()?;
    let root = tk.root();

    // -- Add a text input box. 
    let text_box = root.add_text(())?
        .pack( -side("bottom") )?;

    // -- Add a number input widget. 
    let check_digit = tclfn!( tk, args: "%S",
        fn check_digit( key: String ) -> TclResult<bool> {
            Ok( match key.as_str() {
                "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" => true,
                _ => false,
            })
        }
    );
    let entry = root.add_entry( -validate("key") -validatecommand(check_digit) )?
        .pack( -side("left") -fill("x") -expand(1) )?;

    // -- Add a checkbox widget. 
    let check = root.add_checkbutton(())?
        .pack( -side("left") )?;

    // -- Add a radio checkbox widget. 
    let radio = root.add_radiobutton(())?
        .pack( -side("left") )?;

    Ok( main_loop() )
}

I think it's an easy-to-use GUI library and this is the tutorial.

Bad news: it's a wrapper of the Tk library written in C.

Good news: it's quite easy for those who have some experience of the standard GUI library of Python/Ruby.

2 Likes

+1 for Iced. However I wouldn't say it's "very well documented", I think the documentation leaves much to be desired. But this somewhat alleviates by the number of examples in the repo.

I tried GTK-rs. I had to create a variable for each widget. It rapidely became a real memory management hell. Especially when I had to generate dynamically a list of items, with the possibility to edit, add, remove and reorder them.

Tk looks really interesting. That tutorial looks really well done and could be a game-changer when it comes to adding a GUI to my project. I just added it to my queue of GUI crates to check out. Yes, I'd prefer something written in native Rust, but it's the documentation that is most important. Thanks, oooutlk!

I am the author of crate tk. Just feel free to ask questions in this forum or on github if something is not mentioned in that tutorial. And I need some responses from crate users to improve it. :slightly_smiling_face:

I did just want to jump in as someone that's spent a long time with various GUI approaches: GUI is hard and everything sucks :wink:. You shouldn't feel bad for being confused and wandering why everything is either too confusing or is demoware that immediately fails with a real project: that just means you haven't been beaten down yet!

But really, it just is a both functionally and essentially difficult problem to solve: Rust might be a pretty bad fit for the loose bag of objects that most UI code turns into; but your options elsewhere aren't actually all that much better in my experience.

A lot of people talk about how GUI widgets are a natural fit for OOP: they clearly haven't used view source on any OOP widgets; it's copy-pasta code and special cases all day. If you want to do anything that isn't provided by your toolkit you best go shopping.

React got really successful in web as a way to map your application state to the DOM (that is, web widgets) - but it's just about impossible to compose your state without global application knowledge even with all the ecosystem built around it. Now signal based libraries like solid are getting good press: but it's still a mess to e.g. create a UI that edits properties on an object. Rust has approaches that emulate both of these, which also emulate the issues to some extent.

This is not to say these approaches are bad, necessarily; just that it's best to think of these as anything that works well with GUIs only does so because someone spent a lot of effort making that one thing work well. It doesn't mean that the thing you're doing is going to work well.

Incidentally, my litmus test for GUI libraries is how easy is it to implement a tab control "from scratch"; it's shockingly difficult to do well in pretty much anything popular.

5 Likes

As the author of Kas, I tried to find a slightly different approach marrying an elm-like design with stateful widgets. The result is... fairly efficient, somewhat more complex than Iced, and hits far too many not-yet-implemented/stable RFCs (we now have stable GATs but not yet dyn-safe GATs; RPITIT should enable a few simplifications (not yet done)).

Be aware:

  • The last release is horribly outdated; tutorials too; hopefully I'll get that sorted this month
  • There are essentially two ways of implementing UI (components), and there is a fairly big gap in the approaches:
    • Custom stateful widgets are powerful and can directly refer to children but are complex and Rust does not provide great support for constructing single-instance (anonymous) trait objects or inferring the type of fields. (This is the only option in prior Kas releases.)
    • Declarative, constructing a tree of widgets which may react to events and updates of input data (vaguely like Druid / Xilem but read-only). For the most part this is easier to use, but a little less flexible.

This seems like a good place to reference Igor Loskutov's article 50 Shades of Rust, or emerging Rust GUIs in a WASM world, featured the May 3 edition of This Week in Rust.

I have been experimenting with the Dioxus project with mixed results. I agree with Simon:

1 Like

Another good GUI option is tauri is similar to Electron solution but in Rust ecosystem allow use HTML, CSS frameworks like React or Rust like Yew etc.

I found that article very interesting. I thought I had found most of the Rust GUI versions out there, but Mr. Loskutov's article listed a whole herd's worth of GUI's that were brand new to me. Thanks for the info! :>) :cow: :cowboy_hat_face:

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.