0Pricing
Learn Rust Coding · บทเรียน

พื้นฐาน UI แบบโหมดทันที

ทำความเข้าใจวิธีที่ egui เรนเดอร์

พื้นฐาน UI แบบโหมดทันที เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

ความหมายของโหมดทันที

egui เป็นไลบรารี GUI แบบ immediate-mode ต่างจากชุดเครื่องมือแบบคงอยู่ (GTK, Qt) ที่คุณสร้างแผนผังวิดเจ็ตถาวร egui จะสร้าง UI ทั้งหมดใหม่ตั้งแต่ต้นในทุกเฟรม

โค้ดของคุณทำงานจากบนลงล่างในแต่ละเฟรม และปล่อยวิดเจ็ตออกมาเป็นการเรียกฟังก์ชัน ไม่มีกราฟโหนดที่จัดเก็บไว้ UI เป็นเพียงผลข้างเคียงจากการเรียกใช้ closure ของคุณ

ลูปการอัปเดต

แอป egui จะนำ eframe::App ไปใช้งาน โดยเรียกเมธอด update หนึ่งครั้งต่อเฟรม ซึ่งโดยทั่วไปคือ 60 ครั้งต่อวินาที

ภายใน update คุณจะอธิบายว่า UI ควรมีหน้าตาเป็นอย่างไร ในขณะนี้ โดยอ้างอิงจากสถานะปัจจุบัน egui จะไม่คำนวณส่วนต่าง แต่ปล่อยทุกอย่างออกมาใหม่ทั้งหมด

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _f: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.label("Hello, egui!");
        });
    }
}

Context และ Ui

ชนิดหลักสองชนิดปรากฏอยู่ทั่วไป egui::Context คือแฮนเดิลที่ใช้ร่วมกันและโคลนได้โดยมีต้นทุนต่ำสำหรับสถานะ UI ทั้งหมดของเฟรม

Ui คือพื้นที่ที่คุณเพิ่มวิดเจ็ตเข้าไป แผงและหน้าต่างจะส่ง &mut Ui ให้คุณภายใน closure จากนั้นคุณเรียกเมธอดอย่าง ui.label หรือ ui.button กับค่านี้

egui::CentralPanel::default().show(ctx, |ui| {
    ui.heading("Dashboard");
    ui.separator();
    ui.label("Widgets go here.");
});

วิดเจ็ตคืนการตอบสนอง

เนื่องจาก UI ถูกสร้างใหม่ในทุกเฟรม คุณจึงลงทะเบียนฟังก์ชันเรียกกลับแบบชุดเครื่องมือคงอยู่ไม่ได้ แต่การเรียกวิดเจ็ตทุกครั้งจะคืนค่า Response ทันที

คุณตรวจสอบ Response ได้ในเฟรมเดียวกัน เช่น .clicked(), .hovered(), .changed() วิธีนี้ทำให้การจัดการเหตุการณ์อยู่ในบรรทัดเดียวกับการจัดวาง

if ui.button("Save").clicked() {
    self.save();
}
let resp = ui.text_edit_singleline(&mut self.name);
if resp.changed() {
    self.dirty = true;
}

สถานะอยู่ที่คุณ

egui จัดเก็บข้อมูลของแอปพลิเคชันไว้น้อยมาก ค่าของวิดเจ็ตจะอยู่ใน self ของโครงสร้าง App และคุณส่งการอ้างอิงแบบแก้ไขได้เข้าไปในวิดเจ็ต

ช่องข้อความรับ &mut String ส่วนช่องทำเครื่องหมายรับ &mut bool egui เขียนค่ากลับผ่านการอ้างอิง ดังนั้นโครงสร้างของคุณจึงเป็นแหล่งข้อมูลจริงเพียงแหล่งเดียว

struct MyApp {
    name: String,
    enabled: bool,
}

// inside update:
ui.text_edit_singleline(&mut self.name);
ui.checkbox(&mut self.enabled, "Enabled");

การตั้งค่า eframe

eframe เป็นเฟรมเวิร์กอย่างเป็นทางการสำหรับโฮสต์ egui บนเดสก์ท็อปและเว็บ โดยจัดการหน้าต่างเนทีฟ พื้นผิว GPU และลูปเหตุการณ์

คุณเริ่มทำงานด้วย eframe::run_native โดยส่งชื่อหน้าต่าง ตัวเลือกเนทีฟ และ closure ที่สร้าง App ของคุณ

fn main() -> eframe::Result<()> {
    let opts = eframe::NativeOptions::default();
    eframe::run_native(
        "My App",
        opts,
        Box::new(|_cc| Ok(Box::new(MyApp::default()))),
    )
}

การวาดใหม่ที่ขับเคลื่อนด้วยอินพุต

โดยค่าเริ่มต้น egui จะวาดใหม่เมื่อมีบางสิ่งเกิดขึ้นเท่านั้น เช่น การเลื่อนเมาส์ การกดปุ่ม หรือคำขอที่ระบุอย่างชัดเจน วิธีนี้ช่วยประหยัด CPU เมื่อแอปไม่ได้ทำงาน

สำหรับภาพเคลื่อนไหวหรือข้อมูลแบบสด ให้เรียก ctx.request_repaint() เพื่อกำหนดเวลาเฟรมถัดไป หรือใช้ request_repaint_after พร้อมระยะเวลาเพื่ออัปเดตตามเวลาที่กำหนด

ui.label(format!("Tick: {}", self.counter));
self.counter += 1;
ctx.request_repaint(); // keep animating

ไม่มีรหัสประจำวิดเจ็ตที่เก็บคงอยู่ (เกือบทั้งหมด)

egui สร้างเอกลักษณ์ของวิดเจ็ตจากลำดับการเรียกและตำแหน่ง โดยสร้าง Id ให้อัตโนมัติ สิ่งนี้สำคัญกับสิ่งต่าง ๆ เช่นส่วนหัวที่ยุบได้ ซึ่งต้องใช้หน่วยความจำที่คงเดิมระหว่างเฟรม

เมื่อวิดเจ็ตสองรายการอาจมีเอกลักษณ์ซ้ำกัน เช่น ปุ่มที่มีป้ายกำกับเดียวกันในลูป ให้ครอบด้วย ui.push_id(i, |ui| ...) เพื่อแยกความแตกต่าง

for (i, item) in self.items.iter().enumerate() {
    ui.push_id(i, |ui| {
        if ui.button(&item.label).clicked() {
            println!("clicked {}", i);
        }
    });
}

ข้อแลกเปลี่ยนของโหมดทันที

โหมดทันทีทำให้โค้ดส่วนติดต่อผู้ใช้ขับเคลื่อนด้วยข้อมูลได้โดยตรง: if ใช้แสดงหรือซ่อนส่วนหนึ่ง และ for ใช้แสดงรายการ ไม่จำเป็นต้องเพิ่มหรือลบโหนดด้วยตนเอง และไม่มีความไม่สอดคล้องระหว่างโมเดลกับมุมมอง

ข้อเสียคือส่วนติดต่อผู้ใช้ทั้งหมดจะทำงานซ้ำในทุกเฟรม ดังนั้นควรให้งานในแต่ละเฟรมมีค่าใช้จ่ายต่ำ และหลีกเลี่ยงการคำนวณหนักภายใน update

if self.logged_in {
    ui.label(format!("Welcome, {}", self.user));
} else {
    ui.label("Please sign in.");
}

แอปสมบูรณ์แบบขั้นต่ำ

เมื่อนำทุกอย่างมารวมกัน: โครงสร้างหนึ่งเก็บสถานะ update วาดสถานะนั้น และ main เรียกใช้หน้าต่าง นี่คือโครงร่างทั้งหมดของโปรแกรมเดสก์ท็อป egui ทุกโปรแกรม

ส่วนอื่น ๆ ไม่ว่าจะเป็นการจัดวาง ธีม หรือการจัดแพ็กเกจ ล้วนต่อยอดจากลูปนี้

#[derive(Default)]
struct App { count: i32 }

impl eframe::App for App {
    fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            if ui.button("+1").clicked() { self.count += 1; }
            ui.label(format!("Count: {}", self.count));
        });
    }
}

เหตุใด Rust จึงเหมาะกับ egui

การออกแบบของ egui ใช้ประโยชน์จากจุดแข็งของ Rust การยืม &mut self เข้าไปในการเรียก update เพียงครั้งเดียวทำให้ตัวตรวจสอบการยืมรับประกันว่าจะไม่มีการแข่งกันเข้าถึงข้อมูลระหว่างวิดเจ็ตกับโมเดลของคุณ

ไม่มี callback ที่จับสถานะแก้ไขร่วมกัน ไม่มีกราฟ Rc<RefCell> ที่ถูกบังคับใช้โดยโครงสร้างต้นไม้แบบเก็บคงอยู่ มีเพียงการเป็นเจ้าของตามปกติและการส่งผ่านแบบแก้ไขได้หนึ่งครั้งต่อเฟรม

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจของคุณเกี่ยวกับโหมดทันที

สรุป

egui เป็นแบบโหมดทันที: ส่วนติดต่อผู้ใช้ทั้งหมดจะถูกสร้างใหม่ในแต่ละเฟรมภายใน eframe::App::update วิดเจ็ตคือการเรียกฟังก์ชันที่คืนค่า Response ให้คุณตรวจสอบได้ทันที

ข้อมูลของคุณอยู่ใน self และถูกส่งผ่านการอ้างอิงแบบแก้ไขได้ ดังนั้นตัวตรวจสอบการยืมจึงช่วยให้โมเดลกับมุมมองสอดคล้องกัน eframe::run_native เป็นผู้โฮสต์หน้าต่างและลูปเหตุการณ์ ต่อไปเราจะสำรวจชุดวิดเจ็ตและระบบการจัดวาง

คำถามที่พบบ่อย

บทเรียน “พื้นฐาน UI แบบโหมดทันที” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “พื้นฐาน UI แบบโหมดทันที” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “พื้นฐาน UI แบบโหมดทันที”

ทำความเข้าใจวิธีที่ egui เรนเดอร์ คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “พื้นฐาน UI แบบโหมดทันที” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม

ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน UI แบบโหมดทันที
  2. วิดเจ็ตและการจัดวาง
  3. จัดการสถานะแอป
  4. จัดแพ็กเกจแอปเดสก์ท็อป
← กลับไปที่ Learn Rust Coding