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

说在前面

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

TextEdit

  • 文本编辑框
    在这里插入图片描述

  • 其定义为:

    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));
    

    效果如下,输入文本后,文本框宽度将随着输入文本扩展
    在这里插入图片描述

  • interactive

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

    效果如下,文本框将不可编辑,但是同样也不能选中(也就不能复制)
    在这里插入图片描述

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

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

    效果如下
    在这里插入图片描述
    由于我们使用的是同一个可变引用,所以在任意一个输入框输入文本时,两边会同时改变

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

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

    在这里插入图片描述

    • 这里有个地方无法理解,&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);
    }
    

在这里插入图片描述

变量绑定过程

  • 初次接触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 indexlet byte_idx = self.byte_index_from_char_index(char_index);// Then insert the stringself.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 indiceslet 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 rangeself.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中,变量值在函数开始时并没有发生变化,也就是说刚刚的猜想是错的🤡
  • 那是怎么回事呢?
    在这里插入图片描述
  • 让我们回过头来看看events()的引用,居然是在show()函数中被调用的,而show()是在update中调用的
  • 所以实际的过程应该是:
    • 应用启动,update会首次调用一次,这个时候,我们的变量label通过层层转移,最终显示到文本框中。
    • 这个时候输入字符,eframe监听到事件,将事件通知egui进行分发并调用update函数
    • label变量再次进行绑定
    • 之后,在TextEdit对应的show()方法中,检测到对应的事件,进而修改对应的变量值
    • 更新ui

参考

  • Rust: the weird but safe string
  • TextEdit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/87828.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

干货!证书超实用小Tips

1.CSA 是加拿大标准协会(Canadian Standards Association)的简称&#xff0c;它成立于1919年&#xff0c;是加拿大首家专为制定工业标准的非盈利性机构。在北美市场上销售的电子、电器等产品都需要取得安全方面的认证。 2.EAC认证 是海关联盟国家的认证。海关联盟是由俄罗斯…

【java】【springboot】【idea】springboot项目pom.xml 灰色下划线

解决方案&#xff1a; 这里我们找到了原因&#xff0c;就是因为选择了Ignored Files导致pom.xml文件被设置在maven忽略文件清单中&#xff0c;所以我们将打勾的选项取消&#xff0c;点击Apply,然后点击OK

Flutter问题记录 - Unable to find bundled Java version

新版本的Android Studio真的移除了JRE&#xff0c;jre目录找不到&#xff0c;怪不得报错了&#xff0c;不过多了一个jbr目录&#xff0c;找了个以前的Android Studio版本对比 搜了一下jbr&#xff08;JetBrains Runtime&#xff09;&#xff0c;原来IDEA老早就开始用了&#xf…

视频汇聚/视频云存储/视频监控管理平台EasyCVR安全检查的相关问题及解决方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Python使用 YOLO_NAS_S 模型进行目标检测并保存预测到的主体图片

一、前言&#xff1a; 使用 YOLO_NAS_S 模型进行目标检测&#xff0c;并保存预测到的主体图片 安装包&#xff1a; pip install super_gradients pip install omegaconf pip install hydra-core pip install boto3 pip install stringcase pip install typing-extensions pi…

自动化PLC工程师能否转到c#上位机开发?

成功从自动化PLC工程师转向C#上位机开发的经历可能因人而异&#xff0c;以下是一些分享的思路和建议&#xff1a;扩展编程技能&#xff1a;学习C#语言和相关的开发工具和框架&#xff0c;掌握语言的基础知识和常用的编程技巧。可以通过在线教程、培训课程、书籍等途径进行学习&…

python使用 flask+vue 制作前后端分离图书信息管理系统

目录标题 前言制作前后端分离图书信息管理系统的思路&#xff1a;素材代码效果展示 后端部分接口部分前端部分尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 哈喽兄弟们&#xff0c;今天咱们来用Python实现一个前后端分离的图书信息管理系统。 制作前后端分离图书信…

RabbitMQ的镜像队列

镜像队列 如果 RabbitMQ 集群中只有一个 Broker 节点&#xff0c;那么该节点的失效将导致整体服务的临时性不可用&#xff0c;并且也可能会导致消息的丢失。可以将所有消息都设置为持久化&#xff0c;并且对应队列的durable 属性也设置为 true &#xff0c;但是这样仍然无法…

《自动驾驶与机器人中的SLAM技术》之GNSS相关基础知识总结

简介 本篇基于对《自动驾驶与机器人中的SLAM技术》中的GNSS定位相关基础知识进行总结用于备忘 知识点整理 GNSS(全球卫星导航系统)定位原理 GNSS 通过测量自身与地球周围各卫星的距离来确定自身的位置 , 而与卫星的距离主要是通过测量时间间隔来确定的 GNSS与GPS的关系 GPS(…

工厂方法模式的概述和使用

目录 一、工厂方法模式概述1. 定义2. 使用动机 二、工厂方法模式结构1. 模式结构2. 时序图 三、工厂方法模式的使用实例四、工厂方法模式的优缺点五、工厂方法模式在Java中应用 原文链接 一、工厂方法模式概述 1. 定义 工厂方法模式(Factory Method Pattern)又称为工厂模式&…

七层、四层和五层网络模型区别和联系

七层、四层和五层网络模型区别和联系 概述OSI网络7层模型&#xff08;概念型框架&#xff09;概述图片分析 四层模型概述常用协议OSI与TCP/IP四层的区别 五层模型概述三种网络模型对比 总结 概述 网络模型-七层模型&#xff08;OSI模型&#xff09;、五层协议体系结构和TCP/IP…

双基证券:预计未来还会有更多政策来吸引增量资金

双基证券表明&#xff0c;8月27日&#xff0c;活泼资本商场五大方针出台&#xff1a;证券买卖印花税折半征收&#xff1b;阶段性收紧IPO节奏&#xff1b;上市房企再融资不受破发、破净和亏损限制&#xff1b;规范控股股东与实践操控人减持行为&#xff1b;融资保证金最低份额由…