【rust/egui】(四)看看template的app.rs:update以及组件TopBottomPanel&Button

说在前面

  • rust新手,egui没啥找到啥教程,这里自己记录下学习过程
  • 环境:windows11 22H2
  • rust版本:rustc 1.71.1
  • egui版本:0.22.0
  • eframe版本:0.22.0
  • 上一篇:这里

update

  • update实际上还是eframe::App的特征,并非egui的内容。其官方注解如下:
    fn update(&mut self, ctx: &Context, frame: &mut Frame)
    Called each time the UI needs repainting, 
    which may be many times per second.
    
    update函数会在需要重绘ui(或者其他)的时候被调用,一秒可能会调用多次
    (稍微看了下源代码,可能是事件驱动调用?)
  • 我们可以在该函数里加个日志看看调用情况:
    [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
    
    可以看到,当我们不进行任何操作(鼠标、键盘均不输入)时,是没有任何输出的,当按住任意一个按键后,日志开始疯狂输出,这也印证了事件驱动的猜想。
  • 其他内容本文暂未深入

TopBottomPanel

  • 接下来正式开始接触egui的内容,首先是:

    #[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(),其实现如下:

    pub fn top(id: impl Into<Id>) -> Self {
        Self::new(TopBottomSide::Top, id)
    }
    // id需要是全局唯一的, e.g. Id::new("my_top_panel").
    

    参数id:需要实现Into<Id>特征,并且需要全局唯一,那我要是不唯一怎么办,比如把下面的SidePanel也改成一样的:

    egui::SidePanel::left("top_panel")
    

    运行后出现报错 (错误提示还挺全) 在这里插入图片描述

  • 在函数实现中,实际上还是调用的new方法,传入位置的枚举TopBottomSide::Top

  • 当然我们也可以调用bottom()方法,对应枚举TopBottomSide::Bottom
    在这里插入图片描述

  • new方法的实现如下:

    pub fn new(side: TopBottomSide, id: impl Into<Id>) -> Self {
        Self {
            side,
            id: id.into(), // 调用into方法,转为Id类型
            frame: None,
            resizable: false, // 下面是一些控制参数
            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>
    

    参数add_contentsFnOnce闭包,仅执行一次,在我们的应用中,闭包中添加了一个简单的菜单栏:

    // 添加菜单栏
    egui::menu::bar(ui, |ui| {
        ui.menu_button("File", |ui| {
        	if ui.button("Quit").clicked() {
            	_frame.close();
            }
        });
    });
    
  • 注意:上面说的执行一次,是说此次update调用中执行一次

  • 我们继续深入下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>,
    }
    

    其实是可以修改一些样式的,比如高度:

    egui::TopBottomPanel::top("top_panel").min_height(100.0).show(...
    

    在这里插入图片描述

menu::bar

  • TopBottomPanel中,我们使用bar()函数添加了一个菜单栏,其函数定义如下:
    pub fn bar<R>(
        ui: &mut Ui,
        add_contents: impl FnOnce(&mut Ui) -> R
    ) -> InnerResponse<R>
    
    同样使用FnOnce闭包来添加一些额外的元素
  • 菜单栏组件在TopBottomPanel::top中的展示效果最好,当然也可以放在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会盖住菜单(File):
    在这里插入图片描述

menu::menu_button

  • bar()的回调中,我们添加了一个下拉按钮
    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
  • 同时也使用了FnOnce闭包添加了一个按钮:
    ui.menu_button("File", |ui| {
    	if ui.button("Quit").clicked() {
            _frame.close();
        }
    });
    
  • 其实我们还可以在menu_button中添加一个子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中会怎样呢?
    在这里插入图片描述
    其实也是可以的,只是效果不是很好,对比一下(上图是放在panel中,下图是放在bar中的效果):
    在这里插入图片描述

Ui::button

  • 上面我们已经接触到了文本按钮,其定义如下:
    pub fn button(&mut self, text: impl Into<WidgetText>) -> Response
    
  • 实际上是一个简单的封装函数:
    Button::new(text).ui(self)
    
  • 通常的用法是:
    if ui.button("Click me").clicked() {}
    
  • 现在我们进一步看看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>,
    }
    
  • 是有一些参数可以设置的,那我们怎样添加一个不一样的按钮呢?
    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元素是否被点击、拖拽,进而做出对应的处理;例如点击事件:
    pub fn clicked(&self) -> bool {
        self.clicked[PointerButton::Primary as usize]
    }
    
    其大致流程是:鼠标点击事件被eframe捕获,由egui计算与整个ui的交互结果,例如哪些元素被点击到了,点击结果存储到Response.clicked数组中,我们只需访问即可。
    clicked存储了五种点击事件
    pub enum PointerButton {
        /// The primary mouse button is usually the left one.
        /// 通常是鼠标左键
        Primary = 0,
    
        /// The secondary mouse button is usually the right one,
        /// and most often used for context menus or other optional things.
        /// 通常是鼠标右键
        Secondary = 1,
    
        /// The tertiary mouse button is usually the middle mouse button (e.g. clicking the scroll wheel).
        /// 通常是鼠标中键
        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

  • 调用该函数会通知eframe关闭应用,调用后应用不会立即关闭,而是在该帧结束的时候关闭
  • 同时,如果crate::run_native后面还有代码的话,也会继续执行:
    let ret = eframe::run_native(
        "demo app",
        native_options,
        Box::new(|cc| Box::new(demo_app::TemplateApp::new(cc))),
    );
    
    log::error!("end");
    
    ret
    

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这是一个 Rust 语言的 API 文档,介绍了 Tauri 库版本 1.3.0 中的 `WindowBuilder` 结构体。`WindowBuilder` 结构体是用于创建 Tauri 应用程序窗口的构建器。以下是该文档的翻译: # `WindowBuilder` 用于创建 Tauri 应用程序窗口的构建器。 ## 结构体成员 ### `width` 窗口的宽度。默认值为 `800`。 ### `height` 窗口的高度。默认值为 `600`。 ### `title` 窗口的标题。默认值为 `Tauri Application`。 ### `resizable` 窗口是否可以调整大小。默认为 `true`。 ### `fullscreen` 窗口是否全屏。默认为 `false`。 ### `fullscreenable` 窗口是否可以全屏。默认为 `true`。 ### `decorations` 窗口是否有装饰。默认为 `true`。 ### `transparent` 窗口是否透明。默认为 `false`。 ### `always_on_top` 窗口是否总在最上层。默认为 `false`。 ### `icon` 窗口的图标。默认为 `None`。 ### `min_width` 窗口的最小宽度。默认为 `None`。 ### `min_height` 窗口的最小高度。默认为 `None`。 ### `max_width` 窗口的最大宽度。默认为 `None`。 ### `max_height` 窗口的最大高度。默认为 `None`。 ### `inner_border` 窗口是否有内边框。默认为 `true`。 ### `platform_specific` 在某些平台上启用特定于平台的外观和行为。默认为 `true`。 ## 方法 ### `new() -> WindowBuilder` 创建新的 `WindowBuilder` 实例。 ### `build(&self) -> Result<Window, String>` 使用该构建器创建并返回一个新的 `Window` 实例。如果构建器的参数不正确,则返回一个 `Err`。 ### `with_title<S: Into<String>>(mut self, title: S) -> Self` 设置窗口标题。 ### `with_width(mut self, width: f64) -> Self` 设置窗口的宽度。 ### `with_height(mut self, height: f64) -> Self` 设置窗口的高度。 ### `with_resizable(mut self, resizable: bool) -> Self` 设置窗口是否可以调整大小。 ### `with_fullscreen(mut self, fullscreen: bool) -> Self` 设置窗口是否全屏。 ### `with_fullscreenable(mut self, fullscreenable: bool) -> Self` 设置窗口是否可以全屏。 ### `with_decorations(mut self, decorations: bool) -> Self` 设置窗口是否有装饰。 ### `with_transparent(mut self, transparent: bool) -> Self` 设置窗口是否透明。 ### `with_always_on_top(mut self, always_on_top: bool) -> Self` 设置窗口是否总在最上层。 ### `with_icon(mut self, icon: Icon) -> Self` 设置窗口的图标。 ### `with_min_width(mut self, min_width: f64) -> Self` 设置窗口的最小宽度。 ### `with_min_height(mut self, min_height: f64) -> Self` 设置窗口的最小高度。 ### `with_max_width(mut self, max_width: f64) -> Self` 设置窗口的最大宽度。 ### `with_max_height(mut self, max_height: f64) -> Self` 设置窗口的最大高度。 ### `with_inner_border(mut self, inner_border: bool) -> Self` 设置窗口是否有内边框。 ### `with_platform_specific(mut self, platform_specific: bool) -> Self` 设置是否在某些平台上启用特定于平台的外观和行为。 ## 示例 ```rust use tauri::WindowBuilder; let builder = WindowBuilder::new() .with_title("My App") .with_width(800.0) .with_height(600.0); let window = builder.build().unwrap(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值