【rust/egui】(六)看看template的app.rs:TextEdit

这篇具有很好参考价值的文章主要介绍了【rust/egui】(六)看看template的app.rs:TextEdit。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

说在前面

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

TextEdit

  • 文本编辑框
    【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端

  • 其定义为:

    pub struct TextEdit<'t> {
        text: &'t mut dyn TextBuffer,
        hint_text: WidgetText,
        id: Option<Id>,
        id_source: Option<Id>,
        font_selection: FontSelection,
        text_color: Option<Color32>, // 文本颜色
        layouter: Option<&'t mut dyn FnMut(&Ui, &str, f32) -> Arc<Galley>>,
        password: bool, // 是否是密码
        frame: bool,
        margin: Vec2, 
        multiline: bool, // 是否支持多行文本
        interactive: bool, // 是否可编辑
        desired_width: Option<f32>, // 宽度
        desired_height_rows: usize, // 文本行数
        lock_focus: bool,
        cursor_at_end: bool, 
        min_size: Vec2, // 最小大小
        align: Align2, // 边距
        clip_text: bool, // 显示时是否进行裁剪
        char_limit: usize, // 文字上限
    }
    

    用起来可能是个简单的东西,但是实际上很是复杂,首先我们来看看它的外观以及用法

  • app.rs中,我们是通过以下方式添加的:

    ui.text_edit_singleline(label);
    

    它添加的是一个简单的单行输入框:

    pub fn singleline(text: &'t mut dyn TextBuffer) -> Self {
        Self {
            desired_height_rows: 1, // 文本行数
            multiline: false, // 是否多行,否
            clip_text: true, // 显示时是否裁剪文本,是
            ..Self::multiline(text)
        }
    }
    
  • 同样,我们可以通过ui.add()的方式来自定义属性

  • clip_text

    ui.add(egui::TextEdit::singleline(label).clip_text(false));
    

    效果如下,输入文本后,文本框宽度将随着输入文本扩展
    【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端

  • interactive

    ui.add(egui::TextEdit::singleline(label)
    	.clip_text(false)
    	.interactive(false));                
    

    效果如下,文本框将不可编辑,但是同样也不能选中(也就不能复制)
    【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端

  • 我们可以添加一个多行文本输入框看看:

    ui.add(egui::TextEdit::multiline(label));
    

    效果如下
    【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端
    由于我们使用的是同一个可变引用,所以在任意一个输入框输入文本时,两边会同时改变

  • 另外,我们也可以实现不可编辑但是可以选中的效果:

    ui.add(egui::TextEdit::multiline(&mut label.as_str()));
    

    【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端

    • 这里有个地方无法理解,&mut label.as_str()的类型是&mut &str,这是个啥?对&str的可变引用?&mut &str&mut str的区别是啥?
    • 使用&str倒是能理解,因为text: &'t mut dyn TextBuffer是限定了TextBuffer特征的,而egui只为String&str实现了该特征,并且一个可变,一个不可变,符合预期。
      impl TextBuffer for String {
          fn is_mutable(&self) -> bool {
              true
          }
          // ..
      }
      
      impl<'a> TextBuffer for &'a str {
          fn is_mutable(&self) -> bool {
              false
          }
      	// ..
      }
      
  • 输入框也支持对事件进行响应

    let response = ui.add(egui::TextEdit::singleline(&mut my_string));
    if response.changed() {
        // …
    }
    if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
        // …
    }
    
  • 进阶用法

    let output = egui::TextEdit::singleline(label).show(ui);
    if let Some(text_cursor_range) = output.cursor_range {
    	use egui::TextBuffer as _;
        let selected_chars = text_cursor_range.as_sorted_char_range();
        let selected_text = label.char_range(selected_chars);
        ui.label("Selected text: ");
        ui.monospace(selected_text);
    }
    

【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端文章来源地址https://www.toymoban.com/news/detail-679453.html

变量绑定过程

  • 初次接触update函数以及输入框,对于label变量是怎样和文本输入框的内容绑定在一起还是很感兴趣的,看了一些源码后有一些猜想,这里记录下
  • 首先,text是特征对象TextBuffer的可变引用,而特征TextBuffer则有一些关键的方法,例如insert_text()
    impl TextBuffer for String {
        fn is_mutable(&self) -> bool {
            true
        }
    
        fn as_str(&self) -> &str {
            self.as_ref()
        }
    
        fn insert_text(&mut self, text: &str, char_index: usize) -> usize {
            // Get the byte index from the character index
            let byte_idx = self.byte_index_from_char_index(char_index);
    
            // Then insert the string
            self.insert_str(byte_idx, text);
    
            text.chars().count()
        }
    
        fn delete_char_range(&mut self, char_range: Range<usize>) {
            assert!(char_range.start <= char_range.end);
    
            // Get both byte indices
            let byte_start = self.byte_index_from_char_index(char_range.start);
            let byte_end = self.byte_index_from_char_index(char_range.end);
    
            // Then drain all characters within this range
            self.drain(byte_start..byte_end);
        }
    
        fn clear(&mut self) {
            self.clear();
        }
    
        fn replace(&mut self, text: &str) {
            *self = text.to_owned();
        }
    
        fn take(&mut self) -> String {
            std::mem::take(self)
        }
    }
    
    通过这些方法可以对变量值进行修改,而后就是调用这些方法的过程是怎样的?
  • 查找insert_text()方法的引用,可以找到一个events()函数:
    /// Check for (keyboard) events to edit the cursor and/or text.
    /// 监听文本框中光标/文本对应的(键盘)事件
    fn events()
    
  • 也就是说,在我们使用键盘输入字符时,会触发对应的事件,从而调用到对应的insert_text()方法,从而改变对应的变量值。
  • 但是,这其中又有另外一个问题:在前面的文章中有提到,update函数也是触发了对应的事件后才会被调用的 ,而我们的变量label是在update函数开始才进行的绑定,那么,这个输入文本 到 对应变量值改变的具体过程(顺序)是怎样的呢?
  • 首先说猜想 (后面证明该猜想是错误的)
    • 应用启动,update会首次调用一次,这个时候,我们的变量label通过层层转移,最终显示到文本框中。
    • 这个时候输入字符,eframe监听到事件,将事件通知egui进行分发
    • events()函数触发,修改对应的值
    • egui调用update函数,更新ui
  • 上面的猜想中,主要的点在于,变量值在update函数前就被更新了,所以我们可以添加日志进行验证:
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
            let Self { label, value } = self;
    
            log::error!("{}", label);
    		// ...
            log::error!("update end {}", label);
        }
    
    日志输出为:
    [2023-08-27T09:42:45Z ERROR demo_app::app] o0olele
    [2023-08-27T09:42:45Z ERROR demo_app::app] update end o0olele
    [2023-08-27T09:42:45Z ERROR demo_app::app] o0olele
    [2023-08-27T09:42:45Z ERROR demo_app::app] update end o0olele1
    
    可以看到,在输入字符的那一次update中,变量值在函数开始时并没有发生变化,也就是说刚刚的猜想是错的🤡
  • 那是怎么回事呢?
    【rust/egui】(六)看看template的app.rs:TextEdit,Rust,rust,开发语言,后端
  • 让我们回过头来看看events()的引用,居然是在show()函数中被调用的,而show()是在update中调用的
  • 所以实际的过程应该是:
    • 应用启动,update会首次调用一次,这个时候,我们的变量label通过层层转移,最终显示到文本框中。
    • 这个时候输入字符,eframe监听到事件,将事件通知egui进行分发并调用update函数
    • label变量再次进行绑定
    • 之后,在TextEdit对应的show()方法中,检测到对应的事件,进而修改对应的变量值
    • 更新ui

参考

  • Rust: the weird but safe string
  • TextEdit

到了这里,关于【rust/egui】(六)看看template的app.rs:TextEdit的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【rust/egui】(二)看看template的main函数:日志输出以及eframe run_native

    rust新手,egui没啥找到啥教程,这里自己记录下学习过程 环境:windows11 22H2 rust版本:rustc 1.71.1 egui版本:0.22.0 eframe版本:0.22.0 上一篇:这里 首先让我们看看 main.rs 中有些什么 在 eframe 中使用的日志库为 log 以及 env_logger ,其日志等级有5个: 我们可以在main函数中添加测试一

    2024年02月13日
    浏览(31)
  • 【rust/egui】(一)从编译运行template开始

    rust新手,egui没啥找到啥教程,这里自己记录下学习过程 环境:windows11 22H2 rust版本:rustc 1.71.1 egui版本:0.22.0 eframe版本:0.22.0 rust windows安装参考:这里 本文默认读者已安装相关环境(git、vscode等) egui github demo online 关于 immediate mode wikipedia microsoft learn 先 clone 下这个项目(也可

    2024年02月13日
    浏览(27)
  • RUST egui部署到github

    接上文,当用trunk serve编译部署后,工程目录下就会有一个dist目录,这个目录就是用来部署用的。 :) 创建一个github repo,这个repo的名称有固定格式要求,就是你自己的用户名+github.io,比如我的用户名是crazyskady,那么这个repo就叫crazyskady.github.io 部署就简单了,先把自己的

    2024年03月21日
    浏览(37)
  • [Rust GUI]eframe(egui框架)代码示例

    你可以使用egui的其他绑定,例如:egui-miniquad,bevy_egui,egui_sdl2_gl 等。 egui库相当于核心库,需要借助eframe框架写界面。 eframe使用egui_glow渲染,而egui_glow需要opengl2.0+。 1、访问微软官网下载生成工具 2、勾选这个 3、对比勾选细节 4、点击安装 5、安装完成 6、关闭 Visual Studio

    2024年02月08日
    浏览(35)
  • Rust图形界面:从零开始创建eGUi项目

    egui系列:初步 首先,用cargo创建一个新项目,并添加eframe 尽管默认创建的项目只实现了输出Hello world功能,但添加了eframe库,所以下载需要一点时间。 创建成功后,直接把下面的代码写入main.rs文件中,这些代码来自egui的hello_world示例。 然后运行cargo run,结果如下所示 在e

    2024年02月01日
    浏览(47)
  • 【Rust日报】2023-02-14 Rust GUI 框架对比: Tauri vs Iced vs egui

    Rust GUI 框架对比: Tauri vs Iced vs egui Tauri:使用系统的 webview 来渲染 HTML/JS 的前端。你可以选择任何前端框架。后台是用Rust编写的,可以通过内置的方法与前台通信。 Iced: 受 Elm 启发的(响应式)GUI库。在桌面上使用 wgpu 进行渲染;实验性的web后端创建DOM进行渲染。所有代码

    2024年02月02日
    浏览(27)
  • 微软开源 windows-drivers-rs, 用 Rust 开发 Windows 驱动程序

    Microsoft Azure 首席技术官兼著名 Windows 软件开发人员 Mark Russinovich 在社交平台上宣布, 启动了一个名为 windows-drivers-rs 的新开源项目。 该项目可帮助开发人员使用 Rust 开发 Windows 驱动程序, 旨在支持 WDM (Windows Driver Model) 和 WDF (Windows Driver Framework) 驱动程序开发模型。 当前版本的

    2024年02月08日
    浏览(32)
  • 微软开源 windows-drivers-rs,用 Rust 开发 Windows 驱动程序

    导读 Microsoft Azure 首席技术官兼著名 Windows 软件开发人员 Mark Russinovich 在社交平台上宣布,启动了一个名为 windows-drivers-rs 的新开源项目。 该项目可帮助开发人员使用 Rust 开发 Windows 驱动程序,旨在支持 WDM (Windows Driver Model) 和 WDF (Windows Driver Framework) 驱动程序开发模型。 当前

    2024年02月08日
    浏览(36)
  • 【rust/egui】(十)使用painter绘制一些图形—connections

    rust新手,egui没啥找到啥教程,这里自己记录下学习过程 环境:windows11 22H2 rust版本:rustc 1.71.1 egui版本:0.22.0 eframe版本:0.22.0 上一篇:这里 在上一节我们使用 painter 绘制了一个可以拖拽的小方块,现在我们来用 painter 将两个小方块连接起来,类似这种: 首先我们需要在我们

    2024年02月09日
    浏览(29)
  • 【rust/egui】(八)使用panels给你的应用划分功能区块

    rust新手,egui没啥找到啥教程,这里自己记录下学习过程 环境:windows11 22H2 rust版本:rustc 1.71.1 egui版本:0.22.0 eframe版本:0.22.0 上一篇:这里 panel 是ui上的一块区域,比如我们打开CSDN的markdown编辑器,它大致上可以划分成四(五)块 (当然实际实现上这四块区域可能不是并列的

    2024年02月09日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包