Skip to main content
Logo Triophore

Beyond the Terminal: Building Iced GUIs with Rust

Rust’s popularity has exploded in recent years, and for good reason. It offers memory safety, blazing-fast performance, and a modern development experience. While often associated with systems programming and command-line tools, Rust is increasingly finding its place in the realm of graphical user interface (GUI) development. One shining example of this is Iced, a cross-platform GUI library that embraces the Elm architecture.

Why Iced?

Iced distinguishes itself with its elegant approach to GUI development:

Elm Architecture: Iced’s core is inspired by the Elm architecture, promoting a unidirectional data flow that makes your application logic clear, robust, and easy to reason about. Native Performance: Leveraging Rust’s inherent speed, Iced applications are performant and responsive. Cross-Platform Compatibility: Write your code once and deploy it seamlessly on Windows, macOS, and Linux. Type Safety: Benefit from Rust’s strong type system to catch errors at compile time and build more reliable applications. Modern Design: Create visually appealing and user-friendly interfaces with Iced’s flexible styling options.

Getting Started

Let’s dive into a basic example to give you a taste of Iced:


use iced::{button, Element, Sandbox, Settings, Text};

pub fn main() -> iced::Result {
    Counter::run(Settings::default())
}

struct Counter {
    value: i32,
    increment_button: button::State,
    decrement_button: button::State,
}

#[derive(Debug, Clone, Copy)]
enum Message {
    IncrementPressed,
    DecrementPressed,
}

impl Sandbox for Counter {
    type Message = Message;

    fn new() -> Self {
        Counter {
            value: 0,
            increment_button: button::State::new(),
            decrement_button: button::State::new(),
        }
    }

    fn title(&self) -> String {
        String::from("Counter - Iced")
    }

    fn update(&mut self, message: Message) {
        match message {
            Message::IncrementPressed => {
                self.value += 1;
            }
            Message::DecrementPressed => {
                self.value -= 1;
            }
        }
    }

    fn view(&mut self) -> Element<'static, Message> {
        let increment = button::Button::new(&mut self.increment_button, Text::new("+"))
            .on_press(Message::IncrementPressed);
        let decrement = button::Button::new(&mut self.decrement_button, Text::new("-"))
            .on_press(Message::DecrementPressed);

        Text::new(self.value.to_string())
            .size(50)
            .into()
    }
}

In this example, we create a simple counter application with two buttons to increment and decrement a value. The update function handles messages triggered by user interactions, and the view function describes the UI layout.

Beyond the Basics

Iced provides a rich set of widgets and layout options for building complex and interactive interfaces. You can create text inputs, sliders, progress bars, and more. Additionally, Iced allows you to customize the look and feel of your application with themes and styles.

When to Choose Iced

Iced is a great choice for a variety of GUI applications, especially when:

You prioritize clean and maintainable code. You need cross-platform compatibility. You value native performance. You prefer a declarative style of UI development.

Resources

Iced Crate: https://crates.io/crates/iced Iced Repository: https://github.com/iced-rs/iced

Conclusion

Iced empowers Rust developers to create beautiful, performant, and reliable GUI applications. With its focus on simplicity and type safety, Iced is an excellent option for both beginners and experienced developers looking to explore the world of GUI development with Rust.