說(shuō)在前面
- rust新手,egui沒(méi)啥找到啥教程,這里自己記錄下學(xué)習(xí)過(guò)程
- 環(huán)境:windows11 22H2
- rust版本:rustc 1.71.1
- egui版本:0.22.0
- eframe版本:0.22.0
- 上一篇:這里
update
-
update
實(shí)際上還是eframe::App
的特征,并非egui
的內(nèi)容。其官方注解如下:fn update(&mut self, ctx: &Context, frame: &mut Frame) Called each time the UI needs repainting, which may be many times per second.
update
函數(shù)會(huì)在需要重繪ui(或者其他)的時(shí)候被調(diào)用,一秒可能會(huì)調(diào)用多次(稍微看了下源代碼,可能是事件驅(qū)動(dòng)調(diào)用?) - 我們可以在該函數(shù)里加個(gè)日志看看調(diào)用情況:
可以看到,當(dāng)我們不進(jìn)行任何操作(鼠標(biāo)、鍵盤(pán)均不輸入)時(shí),是沒(méi)有任何輸出的,當(dāng)按住任意一個(gè)按鍵后,日志開(kāi)始瘋狂輸出,這也印證了事件驅(qū)動(dòng)的猜想。[2023-08-20T07:44:02Z ERROR demo_app::app] update [2023-08-20T07:44:02Z ERROR demo_app::app] update [2023-08-20T07:44:02Z ERROR demo_app::app] update [2023-08-20T07:44:02Z ERROR demo_app::app] update [2023-08-20T07:44:02Z ERROR demo_app::app] update [2023-08-20T07:44:07Z ERROR demo_app::app] update [2023-08-20T07:44:07Z ERROR demo_app::app] update
- 其他內(nèi)容本文暫未深入
TopBottomPanel
-
接下來(lái)正式開(kāi)始接觸egui的內(nèi)容,首先是:
#[cfg(not(target_arch = "wasm32"))] // 非wasm才有 egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { // 頂部的panel通常用于菜單欄 egui::menu::bar(ui, |ui| { ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { _frame.close(); } }); }); });
-
看看這里面是些什么,首先是
top()
,其實(shí)現(xiàn)如下:pub fn top(id: impl Into<Id>) -> Self { Self::new(TopBottomSide::Top, id) } // id需要是全局唯一的, e.g. Id::new("my_top_panel").
參數(shù)
id
:需要實(shí)現(xiàn)Into<Id>
特征,并且需要全局唯一,那我要是不唯一怎么辦,比如把下面的SidePanel
也改成一樣的:egui::SidePanel::left("top_panel")
運(yùn)行后出現(xiàn)報(bào)錯(cuò)
(錯(cuò)誤提示還挺全) -
在函數(shù)實(shí)現(xiàn)中,實(shí)際上還是調(diào)用的
new
方法,傳入位置的枚舉TopBottomSide::Top
-
當(dāng)然我們也可以調(diào)用
bottom()
方法,對(duì)應(yīng)枚舉TopBottomSide::Bottom
-
new
方法的實(shí)現(xiàn)如下:pub fn new(side: TopBottomSide, id: impl Into<Id>) -> Self { Self { side, id: id.into(), // 調(diào)用into方法,轉(zhuǎn)為Id類(lèi)型 frame: None, resizable: false, // 下面是一些控制參數(shù) show_separator_line: true, default_height: None, height_range: 20.0..=f32::INFINITY, } }
-
緊跟
top()
的是show()
方法:pub fn show<R>( self, ctx: &Context, add_contents: impl FnOnce(&mut Ui) -> R ) -> InnerResponse<R>
參數(shù)
add_contents
:FnOnce
閉包,僅執(zhí)行一次,在我們的應(yīng)用中,閉包中添加了一個(gè)簡(jiǎn)單的菜單欄:// 添加菜單欄 egui::menu::bar(ui, |ui| { ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { _frame.close(); } }); });
-
注意:上面說(shuō)的執(zhí)行一次,是說(shuō)此次
update
調(diào)用中執(zhí)行一次 -
我們繼續(xù)深入下
TopBottomPanel
的定義:pub struct TopBottomPanel { side: TopBottomSide, id: Id, frame: Option<Frame>, resizable: bool, show_separator_line: bool, default_height: Option<f32>, height_range: RangeInclusive<f32>, }
其實(shí)是可以修改一些樣式的,比如高度:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-668002.html
egui::TopBottomPanel::top("top_panel").min_height(100.0).show(...
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-668002.html
menu::bar
- 在
TopBottomPanel
中,我們使用bar()
函數(shù)添加了一個(gè)菜單欄,其函數(shù)定義如下:
同樣使用pub fn bar<R>( ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R ) -> InnerResponse<R>
FnOnce
閉包來(lái)添加一些額外的元素 - 菜單欄組件在
TopBottomPanel::top
中的展示效果最好,當(dāng)然也可以放在Window
中。The menu bar goes well in a TopBottomPanel::top, but can also be placed in a Window. In the latter case you may want to wrap it in Frame.
放到bottom會(huì)蓋住菜單(File):
menu::menu_button
- 在
bar()
的回調(diào)中,我們添加了一個(gè)下拉按鈕
似乎pub fn menu_button<R>( ui: &mut Ui, title: impl Into<WidgetText>, add_contents: impl FnOnce(&mut Ui) -> R ) -> InnerResponse<Option<R>> Construct a top level menu in a menu bar.
menu_button
最好包在menu bar
中 - 同時(shí)也使用了
FnOnce
閉包添加了一個(gè)按鈕:ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { _frame.close(); } });
- 其實(shí)我們還可以在
menu_button
中添加一個(gè)子menu_button
:
效果如圖ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { _frame.close(); } ui.menu_button("QuitMenu", |ui| { if ui.button("Quit").clicked() { _frame.close(); } }); });
- 如果
menu_button
直接放在panel
中會(huì)怎樣呢?
其實(shí)也是可以的,只是效果不是很好,對(duì)比一下(上圖是放在panel
中,下圖是放在bar
中的效果):
Ui::button
- 上面我們已經(jīng)接觸到了文本按鈕,其定義如下:
pub fn button(&mut self, text: impl Into<WidgetText>) -> Response
- 實(shí)際上是一個(gè)簡(jiǎn)單的封裝函數(shù):
Button::new(text).ui(self)
- 通常的用法是:
if ui.button("Click me").clicked() { … }
- 現(xiàn)在我們進(jìn)一步看看
Button
的定義:pub struct Button { text: WidgetText, shortcut_text: WidgetText, wrap: Option<bool>, /// None means default for interact fill: Option<Color32>, stroke: Option<Stroke>, sense: Sense, small: bool, frame: Option<bool>, min_size: Vec2, rounding: Option<Rounding>, image: Option<widgets::Image>, }
- 是有一些參數(shù)可以設(shè)置的,那我們?cè)鯓犹砑右粋€(gè)不一樣的按鈕呢?
if ui .add(egui::Button::new("q") // .fill(Color32::GOLD) .min_size(egui::Vec2 { x: 20.0, y: 100.0 })) .clicked() { _frame.close(); }
-
ui.button()
、ui.add()
返回的都是Response
,它可以讓我們知道ui元素是否被點(diǎn)擊、拖拽,進(jìn)而做出對(duì)應(yīng)的處理;例如點(diǎn)擊事件:
其大致流程是:鼠標(biāo)點(diǎn)擊事件被pub fn clicked(&self) -> bool { self.clicked[PointerButton::Primary as usize] }
eframe
捕獲,由egui
計(jì)算與整個(gè)ui的交互結(jié)果,例如哪些元素被點(diǎn)擊到了,點(diǎn)擊結(jié)果存儲(chǔ)到Response.clicked
數(shù)組中,我們只需訪問(wèn)即可。
clicked存儲(chǔ)了五種點(diǎn)擊事件pub enum PointerButton { /// The primary mouse button is usually the left one. /// 通常是鼠標(biāo)左鍵 Primary = 0, /// The secondary mouse button is usually the right one, /// and most often used for context menus or other optional things. /// 通常是鼠標(biāo)右鍵 Secondary = 1, /// The tertiary mouse button is usually the middle mouse button (e.g. clicking the scroll wheel). /// 通常是鼠標(biāo)中鍵 Middle = 2, /// The first extra mouse button on some mice. In web typically corresponds to the Browser back button. Extra1 = 3, /// The second extra mouse button on some mice. In web typically corresponds to the Browser forward button. Extra2 = 4, }
eframe::Frame::close
- 調(diào)用該函數(shù)會(huì)通知eframe關(guān)閉應(yīng)用,調(diào)用后應(yīng)用不會(huì)立即關(guān)閉,而是在該幀結(jié)束的時(shí)候關(guān)閉
- 同時(shí),如果
crate::run_native
后面還有代碼的話,也會(huì)繼續(xù)執(zhí)行:let ret = eframe::run_native( "demo app", native_options, Box::new(|cc| Box::new(demo_app::TemplateApp::new(cc))), ); log::error!("end"); ret
參考
- Button
- menu_button
- bar
- TopBottomPanel
- update
到了這里,關(guān)于【rust/egui】(四)看看template的app.rs:update以及組件TopBottomPanel&Button的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!