Hamze GHALEBI
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Rust egui: A Step-by-Step Tutorial (Easy Reading Format) Hello there! Welcome to GUI (Graphical User Interface) development with Rust and the `egui` library. I'm Gemini, your guide. Think of me as a friendly teacher who's helped many beginners like you get started with Rust. We'll take it slow and steady. Don't worry if things seem new – we'll break them down. Let's begin! ## I. Introduction to egui: Your Friendly GUI Toolkit **What's a GUI?** It's the visual part of an app – buttons, text boxes, sliders – things you click and interact with. **What's `egui`?** `egui` is a Rust library specifically made for building these GUIs. **Why use `egui`?** * **Simple & Fast:** It's designed to be easy to learn and quick to run [1, 2]. * **Portable:** Write your code once, run it on desktops (Windows, Mac, Linux) *and* in web browsers! [1, 3] This uses a technology called WebAssembly (WASM). * **Immediate Mode:** This is `egui`'s special way of working. Let's explore it. ### Immediate Mode vs. Retained Mode (The `egui` Way) Think of **Retained Mode** (common in other GUI toolkits) like building with LEGOs. You create objects (button, text box), and the library *remembers* them [1]. `egui` uses **Immediate Mode**. Imagine a whiteboard: 1. Every fraction of a second (a "frame"), `egui` asks your code: "What should the UI look like *right now*?" 2. Your code describes the *entire* UI based on the current situation (your app's data). 3. `egui` draws it. 4. `egui` then *forgets* the drawing, ready for the next frame [1, 2]. **Key Differences:** | Feature | Immediate Mode (`egui`) | Retained Mode (Other GUIs) | | :------------------ | :-------------------------------------- | :-------------------------------------- | | **UI Definition** | Redrawn fresh **every frame** [1]. | UI objects **created & kept** in memory. | | **State** | **Your app code** holds UI data [1, 2]. | GUI library often holds UI data. | | **Interactions** | Logic is **in your drawing code** [1]. | Separate "event handlers" attached. | | **Simplicity** | Often **simpler** to start with [1, 2]. | Can handle complex layouts easily. | **Why Immediate Mode is often simpler:** Your code directly controls what's shown based on your application's data *right now*. There's less complexity in syncing separate UI state [2]. ## II. Essential Rust Fundamentals for egui You don't need to be a Rust expert, but knowing these basic concepts will help you understand `egui` code [3]. * **Functions (`fn`):** Blocks of code that do specific tasks. You'll put your UI logic in functions. * **Mutability (`mut`):** Allows variables to be changed. GUIs change constantly, so you'll see `mut` a lot, especially with `&mut` (mutable borrow) [3]. * **Structs (`struct`):** Let you create your own data types by grouping related variables. You'll use a struct to hold your application's state (data) [1]. * **Enums (`enum`):** Define a type that can have one of a few specific values (variants). Great for multiple-choice options [3]. * **Closures (`|args| { ... }`):** Mini, unnamed functions defined on the spot. `egui` uses them heavily for layout and defining UI sections [3]. * **Ownership & Borrowing (`&`, `&mut`):** Rust's safety feature! `&mut` lets `egui` safely *modify* your app's state without taking ownership [3]. * **Traits:** Define shared behaviour (like interfaces). You'll implement the `eframe::App` trait for your main app struct [3]. * **Modules & Crates (`use`, `::`):** How Rust organizes code and uses external libraries (`egui`, `eframe`). `use` brings items into scope; `::` separates parts of a path (like `eframe::egui`). Don't worry if these seem abstract now. You'll see them in action soon! ## III. Setting Up a New Rust Project with eframe Let's create our first project! We'll use `eframe`, which helps `egui` run as a standalone app [1]. **Steps:** 1. **Open Terminal:** Go to your command prompt or terminal. 2. **Navigate:** Go to the directory where you keep your code projects. 3. **Create Project:** Run `cargo new egui_demo` ```bash cargo new egui_demo ``` 4. **Enter Directory:** Run `cd egui_demo` ```bash cd egui_demo ``` 5. **Add `eframe` Dependency:** * Open the `Cargo.toml` file in the `egui_demo` folder. * Find the `[dependencies]` section. * Add this line: ```toml [dependencies] eframe = "0.25" # Using version from example [1]. Check crates.io for latest! ``` 6. **Write Basic Code:** * Open the file `src/main.rs`. * **Delete everything** inside it. * Paste this starting code [1]: ```Rust // Import necessary stuff from the eframe crate use eframe::egui; // Main entry point of the program fn main() -> Result<(), eframe::Error> { // Default window settings let options = eframe::NativeOptions::default(); // Start the egui application! eframe::run_native( "egui Demo", // Window title options, // Window settings // This creates our app state. Don't worry too much about Box::new for now. Box::new(|_cc| Box::new(MyApp::default())), ) } // This struct holds our application's data (state) // `#[derive(Default)]` makes it easy to create a starting instance #[derive(Default)] struct MyApp { label: String, // For a text input field value: f32, // For a slider // We will add more fields here later! } // Implement the eframe::App trait for MyApp, telling eframe how to run it impl eframe::App for MyApp { // The `update` method is called every frame to draw the UI // `&mut self` allows this method to modify MyApp's fields fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { // Show a central panel where we'll put our UI egui::CentralPanel::default().show(ctx, |ui| { // `ui` is our tool to add widgets // Add a heading ui.heading("My egui Application"); // Arrange items horizontally ui.horizontal(|ui| { ui.label("Write something: "); // Text input linked to `self.label` // `&mut self.label` lets the widget change the `label` field ui.text_edit_singleline(&mut self.label); }); // Add a slider linked to `self.value` ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0).text("value")); // Add a button if ui.button("Increment").clicked() { // If clicked, increase `self.value` self.value += 1.0; } // Display the current state in a label ui.label(format!("Hello '{}', value: {}", self.label, self.value)); }); } } ``` 7. **Run the App:** * Go back to your terminal (still in the `egui_demo` folder). * Run `cargo run` ```bash cargo run ``` * Cargo will build and run your code. A window should appear! [1] You did it! You ran your first `egui` app. ## IV. Basic Structure of an egui Application (Enhanced Explanation) Let's break down that starting code: 1. **`main` Function:** * Starts the program. * Sets up `eframe` options. * Calls `eframe::run_native(...)`. * Tells `eframe` how to create your application's initial state (`Box::new(|_cc| Box::new(MyApp::default()))`). * **Syntax Note:** `Box::new()` puts data on the "heap" (a memory area). `eframe` uses it here for flexibility. You don't need to fully grasp `Box` yet. Just know this line creates your `MyApp` struct. * **Syntax Note:** `MyApp::default()` uses the `Default` trait (often auto-generated by `#[derive(Default)]`) to create a `MyApp` with starting values (empty `String`, `0.0` `f32`). 2. **The State Struct (`struct MyApp`)** * Holds *all* the data your UI needs. * `label: String` holds text for the input box. * `value: f32` holds the number for the slider. 3. **The `eframe::App` Trait Implementation (`impl eframe::App for MyApp`)** * This block tells `eframe` that `MyApp` knows how to be an application. * It requires the `update` method. 4. **The `update` Method (`fn update(&mut self, ...)`):** * **The heart of `egui`!** Called every frame (many times per second). * **`&mut self`:** Gets *mutable access* to your `MyApp` instance. This is crucial! It means `update` can *change* the data (like `self.value += 1.0`). * **`ctx: &egui::Context`:** Provides access to `egui`'s context (input, style, etc.). * **`|ui| { ... }`:** A closure! An inline function where you define the UI for *this frame*. `egui` gives you the `ui` object to use inside it. * **`ui.heading(...)`, `ui.horizontal(...)`, etc.:** Methods called on the `ui` object add widgets (visual elements) to the screen. * **`&mut self.label`, `&mut self.value`:** Passing mutable borrows (`&mut`) links the widget directly to your state field. When the user interacts, the widget modifies your `MyApp` field. **Key Idea:** The `update` function runs, reads the current state from `self`, draws the UI based on that state, checks for interactions, potentially modifies `self` based on interactions, and then finishes until the next frame. ## V. Adding Basic UI Widgets (Enhanced Explanation) Widgets are the building blocks (buttons, labels, etc.). You add them using the `ui` object inside closures. Let's enhance `MyApp` to hold more state for new widgets: ```Rust // --- Add Enums (Specific choice types) --- #[derive(Debug, PartialEq, Clone, Copy)] // Allow printing, comparing, copying enum ColorChoice { Red, Green, Blue } #[derive(PartialEq, Debug, Clone, Copy)] // Allow comparing, printing, copying enum AppMode { View, Edit, Settings } // --- Update MyApp Struct (holds ALL application state) --- struct MyApp { label: String, value: f32, show_extra_info: bool, // For a checkbox (true/false) selected_color: ColorChoice, // For radio buttons counter: i32, // Another piece of state current_mode: AppMode, // To control which view is shown } // --- Manually Implement `Default` (starting values) --- // We do this manually because ColorChoice/AppMode don't have automatic defaults. impl Default for MyApp { fn default() -> Self { // `Self` means `MyApp` here Self { label: "Initial Text".to_string(), // Create a String value: 5.0, show_extra_info: false, // Checkbox starts unchecked selected_color: ColorChoice::Red, // Default radio choice counter: 0, current_mode: AppMode::View, // Start in View mode } } } ``` **Syntax Explained:** * **`enum`:** Defines a type with specific variants (e.g., `ColorChoice` can *only* be `Red`, `Green`, or `Blue`). * **`#[derive(...)]`:** Asks Rust to auto-generate common trait implementations (`Debug` for printing, `PartialEq` for `==`, `Clone`/`Copy` for duplicating). * **`impl Default for MyApp`:** Provides a standard way (`MyApp::default()`) to create a starting instance. * **`Self { ... }`:** Syntax to create an instance of the struct (`MyApp`) within its own `impl` block. * **`.to_string()`:** Converts a basic string literal (`"..."`) into an owned `String`. Now, let's see how to add Checkboxes and Radio Buttons in the `update` method (we'll integrate this into a fuller example later): ```Rust // Inside the `update` method, within a panel's `.show(ctx, |ui| { ... })` block: // --- Checkbox --- // Links directly to the `show_extra_info` boolean field in `MyApp`. // Clicking the box toggles `self.show_extra_info`. ui.checkbox(&mut self.show_extra_info, "Show Advanced Options"); // You can then use this state to show/hide other things: if self.show_extra_info { ui.label("Showing advanced info because the box is checked!"); // ... add more widgets here ... } // --- Radio Buttons --- ui.label("Choose a Color:"); // Arrange them horizontally ui.horizontal(|ui| { // Each button represents one variant of the `ColorChoice` enum. // They are linked to the SAME state field: `self.selected_color`. // Clicking a button updates `self.selected_color` to *that button's* value. ui.radio_value(&mut self.selected_color, ColorChoice::Red, "Red"); ui.radio_value(&mut self.selected_color, ColorChoice::Green, "Green"); ui.radio_value(&mut self.selected_color, ColorChoice::Blue, "Blue"); }); // Display the currently selected choice ui.label(format!("Selected: {:?}", self.selected_color)); // `{:?}` uses Debug format ``` **Key Idea:** Widgets like `checkbox` and `radio_value` use `&mut self.field_name` to directly read *and write* to your application's state struct (`MyApp`). ## VI. Handling User Interactions (Enhanced Explanation) How does your app *react*? You check widget states during the `update` call [1, 4]. Most interactive widgets (like `button`, `slider`, `checkbox`) return a `Response` struct. This `Response` tells you what happened *in that specific frame*. * **Button Clicks (`.clicked()`):** ```Rust // Store the response in a variable let save_button_response = ui.button("Save"); // Check if it was clicked THIS frame if save_button_response.clicked() { println!("Save clicked!"); // Update state or call a function here... self.label = "Saved!".to_string(); } ``` * **Mouse Hover (`.hovered()`):** ```Rust if save_button_response.hovered() { // Show a helpful tooltip when the mouse is over the button save_button_response.on_hover_text("Click here to save your data"); } ``` * **Right-Clicks (`.secondary_clicked()`):** ```Rust if save_button_response.secondary_clicked() { println!("Right-click detected!"); // Maybe show a context menu here... } ``` * **Value Changes (`.changed()`):** Useful for sliders, text edits, etc. ```Rust let slider_response = ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0)); // `changed()` is true in the frame the value *finished* changing (e.g., mouse release) if slider_response.changed() { println!("Slider value is now: {}", self.value); // Trigger saving the new value, perhaps? } ``` * **Dragging (`.dragged()`):** ```Rust if slider_response.dragged() { // Maybe show temporary feedback while dragging // ui.label("Dragging slider..."); } ``` **Key Idea:** You don't wait for events. In each `update`, you *ask* the widgets (via their `Response`) if an interaction just happened, and react immediately by changing state or drawing something different. ## VII. Organizing UI Layout (Enhanced Explanation) Arranging widgets makes your UI usable. `egui` offers simple tools [3]: * **Basic Layouts (`horizontal`, `vertical`):** * `ui.horizontal(|ui| { ... });` - Widgets side-by-side [5]. * `ui.vertical(|ui| { ... });` - Widgets top-to-bottom [5]. * You can **nest** these (e.g., vertical list of horizontal rows). * **Panels (`TopBottomPanel`, `SidePanel`, `CentralPanel`):** * Divide your window into fixed areas (top/bottom/left/right) or the main central area [1]. * Define panels *before* `CentralPanel` in `update`. * **Grouping (`ui.group`, `ui.collapsing`):** * `ui.group(|ui| { ... });` - Draws a box around items [5]. * `ui.collapsing("Header", |ui| { ... });` - Clickable header to show/hide content [3]. * **Alignment (`ui.vertical_centered`, `Layout::right_to_left`):** * Helpers to center items or change layout direction. * **Grids (`egui::Grid`):** * Perfect for forms! Aligns items in columns. * Use `ui.end_row()` after adding widgets for each row. * **Menus (`egui::menu::bar`, `ui.menu_button`):** * Helpers for creating menu bars, usually in a `TopBottomPanel`. Let's see a combined layout (using the full `MyApp` struct from Section V): ```Rust // This replaces the `impl eframe::App for MyApp` block entirely impl eframe::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { // --- Top Panel: Menu Bar --- egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| { egui::menu::bar(ui, |ui| { // Use the menu bar layout helper // File Menu ui.menu_button("File", |ui| { // Creates "File" button with dropdown if ui.button("Reset Counter").clicked() { self.counter = 0; } if ui.button("Quit").clicked() { // Send command to close the window ctx.send_viewport_cmd(egui::ViewportCommand::Close); } }); // End File Menu dropdown // Mode Menu ui.menu_button("Mode", |ui| { // Creates "Mode" button with dropdown // Use radio buttons to change mode, close menu on click if ui.radio_value(&mut self.current_mode, AppMode::View, "View").clicked() { ui.close_menu(); } if ui.radio_value(&mut self.current_mode, AppMode::Edit, "Edit").clicked() { ui.close_menu(); } if ui.radio_value(&mut self.current_mode, AppMode::Settings, "Settings").clicked() { ui.close_menu(); } }); // End Mode Menu dropdown // Display state on the right side of the menu bar ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { ui.label(format!("Counter: {}", self.counter)); // Show counter value }); // End right-aligned section }); // End menu bar }); // End Top Panel // --- Left Panel: Info / Tools --- egui::SidePanel::left("info_panel") .default_width(150.0) // Set a default width .show(ctx, |ui| { ui.heading("Info Panel"); ui.separator(); // Visual dividing line ui.label(format!("Selected: {:?}", self.selected_color)); ui.separator(); if ui.button("Reset Label Text").clicked() { self.label = String::default(); // Reset to empty string } ui.separator(); // Add some spacing at the bottom ui.allocate_space(ui.available_size()); }); // End Side Panel // --- Central Panel: Main Content (Changes based on Mode) --- egui::CentralPanel::default().show(ctx, |ui| { ui.heading(format!("Current Mode: {:?}", self.current_mode)); ui.separator(); // Use `match` to show different UI based on `self.current_mode` match self.current_mode { // --- VIEW MODE UI --- AppMode::View => { ui.heading("VIEW DATA"); // Use a group to visually contain the data ui.group(|ui|{ ui.label(format!("Label: {}", self.label)); ui.label(format!("Value: {:.1}", self.value)); // Format float to 1 decimal place }); // End group // Show more details only if the checkbox in settings is ticked if self.show_extra_info { // Use a collapsing header for optional info ui.collapsing("Show More Details", |ui| { ui.label(format!("Counter: {}", self.counter)); ui.label(format!("Color Choice: {:?}", self.selected_color)); }); } else { ui.label("(Enable 'Show Advanced Info' in Settings)"); } } // End View Mode Arm // --- EDIT MODE UI --- AppMode::Edit => { ui.heading("EDIT DATA"); // Use a Grid for aligned form elements egui::Grid::new("edit_grid") .num_columns(2) // Define 2 columns .spacing([20.0, 8.0]) // Horizonal & vertical spacing .striped(true) // Alternating row backgrounds .show(ui, |ui| { // Add content row by row ui.label("Edit Label:"); // Column 1, Row 1 ui.text_edit_singleline(&mut self.label); // Column 2, Row 1 ui.end_row(); // MUST call end_row() to finish the row ui.label("Adjust Value:"); // Column 1, Row 2 ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0)); // Column 2, Row 2 ui.end_row(); ui.label("Counter:"); // Column 1, Row 3 ui.horizontal(|ui|{ // Nested horizontal layout in Col 2, Row 3 if ui.button("+").clicked() { self.counter += 1; } ui.label(format!("{}", self.counter)).highlight(); // Highlight the number if ui.button("-").clicked() { self.counter -= 1; } }); ui.end_row(); }); // End Grid } // End Edit Mode Arm // --- SETTINGS MODE UI --- AppMode::Settings => { ui.heading("SETTINGS"); // Use a Group for visual structure ui.group(|ui|{ ui.checkbox(&mut self.show_extra_info, "Show Advanced Info in View"); ui.separator(); // Line separator within the group ui.label("Color Scheme:"); ui.horizontal(|ui| { // Radio buttons side-by-side ui.radio_value(&mut self.selected_color, ColorChoice::Red, "Red"); ui.radio_value(&mut self.selected_color, ColorChoice::Green, "Green"); ui.radio_value(&mut self.selected_color, ColorChoice::Blue, "Blue"); }); // End horizontal layout }); // End group ui.separator(); // Separator between group and button // Add a button to reset ALL state back to defaults if ui.button("Reset All State").clicked() { *self = MyApp::default(); // Replace current state with default values // Optional: Stay in settings mode after reset // self.current_mode = AppMode::Settings; } } // End Settings Mode Arm } // End match self.current_mode }); // End CentralPanel } // End update fn } // End impl eframe::App ``` **Key Layout Ideas:** * Use Panels for overall structure (Menu, Side, Central). * Use `horizontal`/`vertical` for basic flow inside panels/groups. * Use `Grid` for forms needing aligned columns. * Use `group`/`collapsing` to organize related items visually. * Nest layouts as needed! ## VIII. State Management (Enhanced Explanation) This is super important for `egui`! * **Your `struct MyApp` is King:** It holds all the data (`label`, `value`, `counter`, `current_mode`, etc.) [1, 2]. This is the **single source of truth**. * **`update` Reads State:** Each frame, `ui.label(format!("{}", self.counter))` reads the *current* `self.counter` value to display it [1, 4]. * **Interactions Write State:** `if ui.button("+").clicked() { self.counter += 1; }` *directly changes* `self.counter` when the button is clicked [4]. `ui.text_edit_singleline(&mut self.label)` *directly changes* `self.label` as you type. * **UI Updates Automatically:** Because `update` runs every frame and always reads the *latest* state from `self`, the UI instantly reflects any changes made in the previous frame [4]. **Example: Changing Modes** 1. `self.current_mode` holds the state (`View`, `Edit`, or `Settings`). 2. The `match self.current_mode { ... }` block reads this state. 3. Based on the state, *different UI code runs*, showing the View, Edit, or Settings widgets. 4. Clicking a mode radio button (`ui.radio_value(&mut self.current_mode, ...`) *directly changes* the `self.current_mode` field. 5. On the *very next frame*, the `match` expression reads the *new* mode and instantly shows the corresponding UI. **Resetting State:** The `*self = MyApp::default();` line is a simple way to reset everything. * `MyApp::default()` creates a *brand new* struct instance with default values. * `*self = ...` assigns this new instance over the memory of the old `self`, effectively replacing it. **Slow Tasks (Reminder):** Don't do slow things (like file downloads) directly in `update`! Use threads and communicate back using channels or shared state, checking for results without blocking `update` [2]. ## IX. Advanced Features Once you master the basics, `egui` offers more [3]: * **Custom Panels:** Design your own panel types [1, 3]. * **Game Engine Integration:** Use `egui` inside games (e.g., with `bevy_egui`) [1, 3]. * **Dynamic UI:** Use `if`, `match`, and loops (`for item in &self.items { ... }`) to build UI based on data. * **More Widgets:** Explore `egui_extras` (tables, images) and other community crates [1]. * **Custom Widgets:** Build your own reusable UI elements. * **Context Menus:** Add right-click menus easily (`response.context_menu(...)`). * **Drag and Drop:** Handle file drops or item dragging. * **Debugging Tools:** * `ctx.set_debug_on_hover(true);` - Hover to see widget bounds/IDs [1]. * `egui::Window::new("Debug").show(ctx, |ui| { ctx.inspection_ui(ui); });` - Show detailed debug info window. ## X. Best Practices Tips for good `egui` code [1]: 1. **Keep Logic Out of `update`:** Put complex calculations in separate functions. Let `update` *call* those functions based on interactions, but keep `update` itself focused on drawing and simple state changes [1]. 2. **Organize State:** Keep your `MyApp` struct tidy. For very complex apps, group related state into smaller structs within `MyApp`. 3. **Use Debug Tools:** They save *a lot* of time when layouts or interactions misbehave [1]. 4. **Think Readability:** Structure your `update` function clearly. Use comments. Break down very complex UI sections into helper functions if needed. 5. **Accessibility:** Use clear labels. Check if `eframe` or your integration supports accessibility features like AccessKit [2]. ## XI. Further Learning & Resources Ready for more? Check these out [2, 5, 1, 3]: * **Official Docs:** [docs.rs/egui](https://docs.rs/egui) [5] * **Web Demo & Examples:** [www.egui.rs](https://www.egui.rs/) [2] * **GitHub Repo:** [github.com/emilk/egui](https://github.com/emilk/egui) (Source code, discussions, more examples!) [2] * **`eframe` Template:** [github.com/emilk/eframe_template](https://github.com/emilk/eframe_template) (Quick start project) [5] * **Game Dev:** `bevy_egui` [github.com/mvlabat/bevy_egui](https://github.com/mvlabat/bevy_egui) [3] * **Community:** GitHub Discussions, Discord servers. * **Extra Widgets:** `egui_extras` [crates.io/crates/egui_extras](https://crates.io/crates/egui_extras) [1] * **"Awesome egui" Lists:** Search for curated lists of helpful `egui` crates. ## XII. Conclusion `egui` makes GUI development in Rust surprisingly simple and fun! Its immediate mode approach often leads to cleaner code by keeping state management straightforward [1, 2]. Plus, it runs everywhere (desktop and web) [1, 3]. You've learned the essentials: setup, the `update` loop, state handling (`MyApp`), adding widgets, responding to clicks/hovers, organizing layouts, and even switching UI views based on state. The best way forward? **Build things!** Start simple, modify the examples, try adding features. `egui` gives fast feedback, making experimentation easy. Enjoy creating interactive Rust applications! Happy coding! ---

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully