[Rust] GUI: egui

egui๋Š” Rust์˜ ์ฃผ์š” GUI ํ™˜๊ฒฝ ์ค‘ ํ•˜๋‚˜๋‹ค.

๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ€๋ฒผ์šด ํ˜•ํƒœ๋ฅผ ์ง€ํ–ฅํ•˜๋ฉฐ, ์•ฑUI์™€ ์›นUI๋ฅผ ๋™์‹œ์— ์ œ๊ณตํ•œ๋‹ค.
์ด ํฌ์ŠคํŠธ์—์„œ๋Š” ์•ฑ๋งŒ ๋‹ค๋ฃฌ๋‹ค.

์ด ๋…€์„์€ ๋”ฑํžˆ ๋น ๋ฅด๊ฑฐ๋‚˜ ๊ฐ•๋ ฅํ•œ ๊ตฌ์กฐ๋ฅผ ์ง€ํ–ฅํ•˜๊ณ  ๋งŒ๋“ค์–ด์ง€์ง€๋Š” ์•Š์•˜๋‹ค. ๋ Œ๋”๋ง์— ๋Œ€ํ•ด์„œ๋„ ๋ณ„๋‹ค๋ฅธ ์ตœ์ ํ™”๋ฅผ ํ•˜์ง€๋Š” ์•Š๊ณ  ๋งŒ๋“  ๊ฒƒ ๊ฐ™๋”๋ผ. ๋ญ”๊ฐ€ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ์ƒํ˜ธ์ž‘์šฉ์ด ๋ฐœ์ƒํ•˜๋ฉด ํ•ญ์ƒ ์ „์ฒด ๋ ˆ์ด์•„์›ƒ์„ ๋ Œ๋”๋งํ•œ๋‹ค.




์„ค์น˜

์ฃผ์š” ์ข…์†์„ฑ์€ eframe์ด๋ผ๋Š” ๋…€์„์ด๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

[dependencies]
eframe = { version = "0.26.2", features = [
    "default",
    "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
    "auto-color",
    "humantime",
] }



Hello World ์˜ˆ์ œ

์•„๋ž˜๋Š” ์ „์ฒด ์ฝ”๋“œ๋‹ค.

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release

use eframe::egui;

fn main() -> Result<(), eframe::Error> {
    env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

    let options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
        ..Default::default()
    };

    // Our application state:
    let mut name = "Arthur".to_owned();
    let mut age = 42;

    eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("My egui Application");
            ui.horizontal(|ui| {
                let name_label = ui.label("Your name: ");
                ui.text_edit_singleline(&mut name)
                    .labelled_by(name_label.id);
            });
            ui.add(egui::Slider::new(&mut age, 0..=120).text("age"));
            if ui.button("Increment").clicked() {
                age += 1;
            }
            ui.label(format!("Hello '{name}', age {age}"));
        });
    })
}

๋ถ™์—ฌ๋„ฃ์–ด์„œ ์šฐ์„  ์‹คํ–‰ํ•ด๋ณด์ž.


๊ทธ๋Ÿผ ์ด๋ ‡๊ฒŒ ์•ฑ์ด ๋œฐ ๊ฒƒ์ด๋‹ค.




๊ตฌ์กฐ ๋ถ„์„

๋ง‰ ๊ทธ๋ ‡๊ฒŒ ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•˜์ง„ ์•Š๋‹ค.

์šฐ์„  ๊ธฐ๋ณธ ์ฐฝ ํฌ๊ธฐ๋ถ€ํ„ฐ ์ •์˜ํ•œ๋‹ค.


๊ทธ๋ฆฌ๊ณ  run_simple_native๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์•ฑ์„ ๋„์šด๋‹ค. ์—ฌ๊ธฐ์—์„œ๋Š” ์•„๊นŒ ์ •์˜ํ•œ ์˜ต์…˜๊ณผ Panel ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์„œ ์ฐฝ ์ •๋ณด๋ฅผ ์ •์˜ํ•œ๋‹ค.

egui๋Š” ๋ Œ๋”๋ง ์ตœ์ ํ™”๊ฐ€ ์กฐ๊ธˆ ๋ชจ์ž๋ผ๋‹ค๊ณ  ํ–ˆ์—ˆ๋‹ค.

์ด ์ฝ”๋“œ๋ฅผ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‚˜ User ์ƒํ˜ธ์ž‘์šฉ์ด ์žˆ์„๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ๊ทธ๋ฆฐ๋‹ค.
๊ทธ๋ž˜์„œ ๊ทธ๊ฑธ ์—ผ๋‘์— ๋‘๊ณ  ์ž˜ ์งœ์ค˜์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ๋ฉด ์•ˆ๋œ๋‹ค.

์•„๋ฌดํŠผ ์ €๊ธฐ์„œ ๋ ˆ์ด์•„์›ƒ ์š”์†Œ๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์Œ“์•„์˜ฌ๋ฆฌ๋Š” ํ˜•ํƒœ๋‹ค. ์ •์˜ํ•œ ์ˆœ์„œ๋Œ€๋กœ ์œ„-์•„๋ž˜๋กœ ๋ฐฐ์น˜๋œ๋‹ค.

  1. heading์œผ๋กœ ํ—ค๋” ์˜์—ญ์„ ๋‘๊ณ ,
  2. horizonatal๋กœ ๊ฐ€๋กœ ์˜์—ญ์„ ๋‘๊ณ  ๋ผ๋ฒจ๊ณผ ํ…์ŠคํŠธ ์ž…๋ ฅ์ฐฝ์„ ๋งŒ๋“ค์—ˆ๋‹ค.
  3. ์˜†์œผ๋กœ ์›€์ง์—ฌ์„œ ๊ฐ’์„ ์กฐ์ ˆํ•˜๋Š” ์Šฌ๋ผ์ด๋”๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด age ๋ณ€์ˆ˜๊ฐ’์ด ์ˆ˜์ •๋˜๊ฒŒ ํ•œ๋‹ค.
  4. button์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ทธ๊ฒŒ ๋ˆŒ๋ ธ์„๋•Œ๋งˆ๋‹ค age ๊ฐ’์„ 1 ๋Š˜๋ฆฌ๊ฒŒ ํ•œ๋‹ค.
  5. ํ…์ŠคํŠธ label์„ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•œ๋‹ค.

๋‹ค๋ฅธ gui ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์— ๋น„ํ•˜๋ฉด ๊ตฌ์กฐ๊ฐ€ ๊ฝค ์ด์งˆ์ ์ธ ๋ฉด๋„ ์žˆ๋‹ค. ํŠนํžˆ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง์ด ์ฝœ๋ฐฑ์„ ํ†ตํ•ด ๊ตฌ์„ฑ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด ํŠน์ดํ•˜๋‹ค. ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์„ ์ค„์ด๊ธฐ ์œ„ํ•จ์ด๋ผ๋‚˜.

์•„๋ฌดํŠผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง๋„ ํ”„๋ ˆ์ž„ ํ•œ๋ฒˆ ๋Œ๋•Œ๋งˆ๋‹ค ์กฐ๊ฑด๋ฌธ์„ ๋‹ค๋Š” ์‹์œผ๋กœ ๊ตฌ์„ฑ์ด ๋œ๋‹ค. ์ €๊ธฐ ๋ฒ„ํŠผ ํ•ธ๋“ค๋ง ์ฒ˜๋Ÿผ ๋ง์ด๋‹ค.
๋ผ์ดํ”„ํƒ€์ž„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ผ์ด ์ ์œผ๋‹ˆ ์“ฐ๊ธฐ ์‰ฌ์šด ๋ถ€๋ถ„์€ ํ™•์‹คํžˆ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.


์ฐธ์กฐ
https://github.com/emilk/egui