【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.mzph.cn/news/55677.shtml

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

相关文章

Flink CDC数据同步

背景 随着信息化程度的不断提高&#xff0c;企业内部系统的数量和复杂度不断增加&#xff0c;因此&#xff0c;数据库系统的同步问题已成为越来越重要的问题。 缓存失效 在缓存中缓存的条目(entry)在源头被更改或者被删除的时候立即让缓存中的条目失效。如果缓存在一个独立的…

微信小程序canvas type=2d生成海报保存到相册、文字换行溢出显示...、文字删除线、分享面板

一、简介 做个简单的生成二维码海报分享&#xff0c;我做的时候也找简单的方法看能不能实现页面直接截图那种生成图片&#xff0c;原生小程序不支持&#xff0c;不多介绍下面有全部代码有注释、参数自行替换运行看看&#xff0c;还有需要优化的地方&#xff0c;有问题可以咨询…

squid服务器

目录 squid初识 安装squid代理 常用命令 主要配置文件 正向代理 环境配置 linux服务器设置 windows客户端设置 反向代理 环境配置 在web服务器配置服务 linux服务器配置 squid初识 含义&#xff1a;squid cache是一个流行的自由软件&#xff08;GNU通用公共许可证…

低代码与低代码平台的概念解析

随着数字化转型和软件需求的不断增长&#xff0c;传统的手写代码开发方式已经无法满足迅速推出应用程序的需求。为了加快软件开发的速度并降低技术门槛&#xff0c;低代码开发模式应运而生。本文将介绍低代码的概念&#xff0c;探讨什么是低代码什么是低代码平台&#xff1f; 一…

poi带表头多sheet导出

导出工具类 package com.hieasy.comm.core.excel;import com.hieasy.comm.core.excel.fragment.ExcelFragment; import com.hieasy.comm.core.utils.mine.MineDateUtil; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.*; import org.apache.po…

Git基本操作(Idea版)

第一次发布项目&#xff08;本地->远程&#xff09; 方式一 通过push的方式推送本地库到远程库&#xff08;远程已创建好仓库&#xff09; 这种方式需要提前创建好仓库。 右键点击项目&#xff0c;可以将当前分支的内容 push 到 GitHub 的远程仓库中。 注意&#xff1a…

CSDN编程题-每日一练(2023-08-27)

CSDN编程题-每日一练&#xff08;2023-08-27&#xff09; 一、题目名称&#xff1a;异或和二、题目名称&#xff1a;生命进化书三、题目名称&#xff1a;熊孩子拜访 一、题目名称&#xff1a;异或和 时间限制&#xff1a;1000ms内存限制&#xff1a;256M 题目描述&#xff1a; …

R包开发-2.1:在RStudio中使用Rcpp制作R-Package(更新于2023.8.23)

目录 0-前言 1-在RStudio中创建R包项目 2-创建R包 2.1通过R函数创建新包 2.2在RStudio通过菜单来创建一个新包 2.3关于R包创建的说明 3-添加R自定义函数 4-添加C函数 0-前言 目标&#xff1a;在RStudio中创建一个R包&#xff0c;这个R包中包含C函数&#xff0c;接口是Rc…

如何使用HTML5新增的标签来构建语义化的页面结构?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ <header>&#xff1a;⭐ <nav>&#xff1a;⭐ <main>&#xff1a;⭐ <section>&#xff1a;⭐ <article>&#xff1a;⭐ <aside>&#xff1a;⭐ <footer>&#xff1a;⭐ <figure> 和 &l…

登录校验-Filter-详解

目录 执行流程 拦截路径 过滤器链 小结 执行流程 过滤器Filter拦截到请求之后&#xff0c;首先执行方放行之前的逻辑&#xff0c;然后执行放行操作&#xff08;doFilter&#xff09;&#xff0c;然后会访问对应的Web资源&#xff08;对应的Controller类&#xff09;&#…

【图像分类】基于卷积神经网络和主动学习的高光谱图像分类(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Web应用登录验证的几种方式

一、SessionCookie登录 传统的sessioncookie登录是一种有状态 的登录 1、传统的sessioncookie 流程 浏览器登录发送账号和密码&#xff0c;服务端查找数据库验证用户验证成功后&#xff0c;服务端把用户状态&#xff08;登录状态&#xff0c;角色&#xff0c;权限等信息&…

【python】jupyter notebook导出pdf和pdf不显示中文问题

文章目录 写在前面1. 使用jupyter notebook导出pdf1.1 安装Pandoc1.2 安装MiKTex1.3 示例导出pdf 2. 中文显示问题2.1 显示中文问题示例2.2 解决办法1&#xff1a;修改tex2.3 解决办法2&#xff1a;修改内置文件 写在前面 使用jupyter notebook导出pdf时&#xff0c;出现了一些…

31、springboot 配置HTTP服务端口及如何通过WebServer实例动态获取项目中的HTTP端口

配置HTTP服务端口及如何通过WebServer实例动态获取项目中的HTTP端口 ★ 设置HTTP服务端口&#xff1a; - server.port或者SERVER_PORT环境变量——总结来说&#xff0c;其实就是要配置server.port外部配置属性。▲ 同样遵守如下优先级&#xff1a; 这些都是外部配置源&#x…

Win 11 电脑的 Win + E 快捷键失效

报的错误信息如下&#xff1a; 该文件没有与之关联的应用来执行该操作。请安装应用&#xff0c;若已经安装应用&#xff0c;请在”默认应用设置"页面中创建关联。 报错原因&#xff1a;系统注册表被改写了导致的出错 解决办法&#xff1a; 1、首先&#xff0c;按键盘上…

python编程环境使用技巧2-python环境迁移

Python环境迁移步骤 将Python环境从一个计算机迁移到另一个计算机可以按照以下步骤进行&#xff1a; 1-备份环境&#xff1a; 在源计算机上&#xff0c;使用pip工具备份当前Python环境的包列表到一个文本文件。在命令行终端中执行以下命令&#xff1a; pip freeze > requi…

【韩顺平 零基础30天学会Java】数组、排序和查找(2days)

数组、排序、查找和多维数组 数组可以存放多个同一类型的数据。数组也是一种数据类 型&#xff0c;是引用数据类型。 定义一个数组 double[] hens {3,5,1,3.4,2,50} 遍历数组得到数组所有元素的和 hens[下标]&#xff0c;下标是从0开始编号的。 可以通过数组名.lenght得到数组…

【数据库】使用ShardingSphere+Mybatis-Plus实现读写分离

书接上回&#xff1a;数据库调优方案中数据库主从复制&#xff0c;如何实现读写分离 ShardingSphere 实现读写分离的方式是通过配置数据源的方式&#xff0c;使得应用程序可以在执行读操作和写操作时分别访问不同的数据库实例。这样可以将读取操作分发到多个从库&#xff08;从…

详细手机代理IP配置

嗨&#xff0c;亲爱的朋友们&#xff01;作为一家代理产品供应商&#xff0c;我知道有很多小伙伴在使用手机进行网络爬虫和数据采集时&#xff0c;常常会遇到一些IP限制的问题。别担心&#xff01;今天我要给大家分享一下手机IP代理的设置方法&#xff0c;让你们轻松应对这些限…

vue2 路由入门

一、单页应用程序介绍 1.概念 单页应用程序&#xff1a;SPA【Single Page Application】是指所有的功能都在一个html页面上实现 2.具体示例 单页应用网站&#xff1a; 网易云音乐 https://music.163.com/ 多页应用网站&#xff1a;京东 https://jd.com/ 3.单页应用 VS 多页…