พื้นฐาน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน UI แบบโหมดทันที
- วิดเจ็ตและการจัดวาง
- จัดการสถานะแอป
- จัดแพ็กเกจแอปเดสก์ท็อป