【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.rhkb.cn/news/109037.html

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

相关文章

Grounded Language-Image Pre-training论文笔记

Title&#xff1a;Grounded Language-Image Pre-training Code 文章目录 1. 背景2. 方法&#xff08;1&#xff09;Unified Formulation传统目标检测grounding目标检测 &#xff08;2&#xff09;Language-Aware Deep Fusion&#xff08;3&#xff09;Pre-training with Scala…

【golang】派生数据类型---指针 标识符、关键字等

1、指针 对比C/C中的指针&#xff0c;go语言中的指针显得极为简洁&#xff0c;只是简单的获取某个空间的地址 或者 根据指针变量中的内容 获取对应存储空间的内容等操作。 具体示例如下&#xff1a; go中使用指针需要注意的点&#xff1a; 可以通过指针改变它所指向的内存空…

【CSS】轮播图案例开发 ( 基本设置 | 子绝父相 | 浏览器水平居中 | 圆角设置 | 绝对定位居中设置 )

代码示例 : <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Banner 轮播</title><style>/* 取消浏览器或者其它标签的默认的内外边距 */* {margin: 0;padding: 0;}/* 取消列表样式 主要是…

数据采集:selenium 获取某网站CDN 商家排名信息

写在前面 工作中遇到&#xff0c;简单整理理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整的&#xff0c;是人的逃避方式&#xff0c;是对大…

【内网穿透】搭建我的世界Java版服务器,公网远程联机

目录 前言 1. 搭建我的世界服务器 1.1 服务器安装java环境 1.2 配置服务端 2. 测试局域网联机 3. 公网远程联机 3.1 安装cpolar内网穿透 3.1.1 windows系统 3.1.2 linux系统&#xff08;支持一键自动安装脚本&#xff09; 3.2 创建隧道映射内网端口 3.3 测试公网远程…

【电源专题】18650圆柱电芯内部结构及器件

18650圆柱锂离子电池是一种直径为18mm、高度为65mm的锂离子电池,它最大的特点是拥有非常高的能量密度,它是比较成熟的锂离子电池,各方面系统质量稳定性较好,广泛适用于10千瓦时左右的电池容量场合,例如在、在手机、笔记本电脑等小型电器上。 常见的18650电池分为锂离子电池…

亚马逊云科技 re:Inforce 大会云安全合规与技术实践及 Security Jam 大赛,快来报名吧!...

‍‍ 2023年8月31日在北京 亚马逊云科技 re:Inforce 大会 首次登陆中国&#xff01; 我们期待您的莅临&#xff0c; 并与您一起迎接 AI 时代&#xff0c; 开启全面智能的安全旅程&#xff01; 在13:00-17:00的 培训与动手实验环节中 云安全合规与技术实践 及 Security Jam 大赛…

Python3 列表

Python3 列表 序列是 Python 中最基本的数据结构。 序列中的每个值都有对应的位置值&#xff0c;称之为索引&#xff0c;第一个索引是 0&#xff0c;第二个索引是 1&#xff0c;依此类推。 Python 有 6 个序列的内置类型&#xff0c;但最常见的是列表和元组。 列表都可以进…

韶音骨传导耳机值得入手吗,韶音骨传导耳机可以水洗吗

韶音家的代表作可以说是OpenRun Pro骨传导耳机&#xff0c;在发声单元位置上采用了开孔的处理&#xff0c;佩戴上耳的时候发声单元可以贴合耳道&#xff0c;在低频延伸性&#xff0c;但在中高频的时候整体会出现震感&#xff0c;纤细的耳挂在佩戴的时候是有着不错的舒适度的&am…

农村农产品信息展示网站的设计与实现(论文+源码)_kaic

摘 要 随着软件技术的迅速发展,农产品信息展示的平台越来越多,传统的农产品显示方法将被计算机图形技术取代。这种网站技术主要把农产品的描述、农产品价格、农产品图片等内容&#xff0c;通过计算机网络的开发技术&#xff0c;在互联网上进行展示&#xff0c;然后通过计算机网…

单片机TVS/ESD二极管防护

TVS 瞬态电压抑制二极管Transient Voltage Suppressor ESD 静电释放二极管 Electro-Static discharge 这两种本质上都是二极管。都是利用了二极管正向导通、反向截止的特性。二极管在反向截止截止条件下&#xff0c;如果电压继续增大&#xff0c;将会引发雪崩&#xff0c;使得…

ubuntu20.04安装gcc5.4 g++5.4

在进行ubuntu20.04的系统中安装gcc g5.4中&#xff0c;会出现安装问题 1、pip安装&#xff0c;失败 2、使用apt-get install 进行安装时&#xff0c;提示没有候选项&#xff1b; 原因&#xff1a;ubuntu20.04的系统下&#xff0c;系统默认安装的gcc9.0的版本&#xff0c;默认…

7.Oracle视图创建与使用

1、视图的创建与使用 在所有进行的SQL语句之中&#xff0c;查询是最复杂的操作&#xff0c;而且查询还和具体的开发要求有关&#xff0c;那么在开发过程之中&#xff0c;程序员完成的并不是是和数据库的所有内容&#xff0c;而更多的是应该考虑到程序的设计结构。可以没有一个项…

WordPress使用子主题插件 Child Theme Wizard,即使主题升级也能够保留以前主题样式

修改WordPress网站样式&#xff0c;主题升级会导致自己定义设置的网站样式丢失&#xff0c;还需要重新设置&#xff0c;很繁琐工作量大&#xff0c;发现在WordPress 中有Child Theme Wizard子主题插件&#xff0c;使用Child Theme Wizard子主题插件&#xff0c;即使主题升级&am…

HTML-常见标签、HTML5新特性

HTML 软件架构 1.C/S架构 (1) C/S架构即Client/Server&#xff08;客户机/服务器&#xff09;结构。 (2) C/S 架构特点 ​ C/S结构在技术上很成熟&#xff0c;它的主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。但是该结构的程序是…

8年测试经验之谈 —— 接口自动化测试requests

1.什么是requests&#xff1f; requests是一个Python第三方库&#xff0c;处理URL资源特别方便 2.安装requests pip3 install requests 如果遇到Permission denied安装失败&#xff0c;请加上sudo重试 3.使用requests 3.1get请求方法 3.1.1基本的get请求 import reques…

如何使用CSS实现一个3D旋转效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 3D效果实现⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域…

python下载bilibili视频,下载合集,下载选集

一. 内容简介 bilibili视频下载&#xff0c;下载合集&#xff0c;下载选集 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3代码 链接&#xff1a;https://pan.baidu.com/s/1tO8xSmaqqoTxHI9P_UkDBw?pwd1234 提取码&#xff1a;1234 三.主要流程 3.1 …

C语言-内存分布(STM32内存分析)

C/C内存分布 一、内存组成二、静态区域文本段 &#xff08;Text / 只读区域 RO&#xff09;已初始化读写数据段&#xff08;RW data -- Initialized Data Segment&#xff09;未初始化数据段&#xff08;BSS -- Block Started by Symbol&#xff09; 三、动态区域堆&#xff08…

【C++】list类的模拟实现

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录 前言一、list类的模拟实现1.1 list的…