<Rust>egui部件学习:如何在窗口及部件显示中文字符?

前言
本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析,主要讲解egui的源代码、部件属性、如何应用。

环境配置
系统:windows
平台:visual studio code
语言:rust
库:egui、eframe

概述
本文是本专栏的第一篇博文,主要讲述如何使用egui库来显示一个窗口以及如何在窗口显示中文字符。

egui是基于rust的一个GUI库,可以创建窗口并添加部件、布局,其github地址:
https://github.com/emilk/egui

事实上,类似于iced,egui都提供了示例程序,本专栏的博文都是建立在官方示例程序以及源代码的基础上,进行的实例讲解。
即,本专栏的文章并非只是简单的翻译egui的官方示例与文档,而是针对于官方代码进行的实际使用,会在官方的代码上进行修改,包括解决一些问题。

部件属性

在使用egui前,需要添加其依赖:

egui="0.28.1"
eframe="0.28.1"

将上面的库添加到你的项目的toml文件中,然后编译一下。

然后我们来看一个简单的示例,我们以官方提供的例子中的第一个confirm_exit例子来进行说明。这个例子很简单,就是生成一个窗口,并且在关闭窗口时弹出一个提示窗口,选择yes关闭,选择no,不关闭。

官方代码如下:

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release   
#![allow(rustdoc::missing_crate_level_docs)] // it's an exampleuse eframe::egui;fn main() -> eframe::Result {env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).let options = eframe::NativeOptions {viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),..Default::default()};eframe::run_native("Confirm exit",options,Box::new(|_cc| Ok(Box::<MyApp>::default())),)
}#[derive(Default)]
struct MyApp {show_confirmation_dialog: bool,allowed_to_close: bool,
}impl eframe::App for MyApp {fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {egui::CentralPanel::default().show(ctx, |ui| {ui.heading("Try to close the window");});if ctx.input(|i| i.viewport().close_requested()) {if self.allowed_to_close {// do nothing - we will close} else {ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);self.show_confirmation_dialog = true;}}if self.show_confirmation_dialog {egui::Window::new("Do you want to quit?").collapsible(false).resizable(false).show(ctx, |ui| {ui.horizontal(|ui| {if ui.button("No").clicked() {self.show_confirmation_dialog = false;self.allowed_to_close = false;}if ui.button("Yes").clicked() {self.show_confirmation_dialog = false;self.allowed_to_close = true;ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);}});});}}
}

运行之后显示如下:
在这里插入图片描述
点击关闭按钮,弹出提示窗口:
在这里插入图片描述
点击yes按钮,直接关闭,点击no按钮,提示窗口消失,窗口不关闭。

本文暂且不关注窗口如何显示以及如何添加部件,这将在以后的文章中说明。

现在,我们来修改上面的代码,将上面代码中涉及的text文本的内容都修改为中文,再来看看效果。

修改后的代码:

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release    
#![allow(rustdoc::missing_crate_level_docs)] // it's an exampleuse eframe::egui;fn main() -> eframe::Result {env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).let options = eframe::NativeOptions {viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),..Default::default()};eframe::run_native("egui测试窗口",options,Box::new(|_cc| Ok(Box::<MyApp>::default())),)
}#[derive(Default)]
struct MyApp {show_confirmation_dialog: bool,allowed_to_close: bool,
}impl eframe::App for MyApp {fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {egui::CentralPanel::default().show(ctx, |ui| {ui.heading("尝试关闭窗口");});if ctx.input(|i| i.viewport().close_requested()) {if self.allowed_to_close {// do nothing - we will close} else {ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);self.show_confirmation_dialog = true;}}if self.show_confirmation_dialog {egui::Window::new("你想要关闭吗?").collapsible(false).resizable(false).show(ctx, |ui| {ui.horizontal(|ui| {if ui.button("否").clicked() {self.show_confirmation_dialog = false;self.allowed_to_close = false;}if ui.button("是").clicked() {self.show_confirmation_dialog = false;self.allowed_to_close = true;ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);}});});}}
}

再来运行看下:
在这里插入图片描述
点击关闭按钮:
在这里插入图片描述
可以看到,无论是窗口直接显示的文本还是按钮的文本,都显示乱码,这是因为egui自带的字体不支持中文导致的。

所以,和iced库一样,我们只要想办法将字体替换为自定义的字体(支持中文字符)即可。

支持中文字符的字体有很多,可以去网上自行下载,一般来说,最常用的应该是simsun.ttf,当然,也可以去egui作者提供的一个字体网站下载字体:
https://github.com/notofonts/noto-cjk/tree/main/Sans#downloading-noto-sans-cjk

下面我们来看下,如何替换字体,这里依然参考官方提供的示例custom_font。这里就不贴具体代码了,自定义字体的方法,是在efram的一个属性AppCreator中:

/// This is how your app is created.    
///
/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc.
pub type AppCreator = Box<dyn FnOnce(&CreationContext<'_>) -> Result<Box<dyn App>, DynError>>;

其实就是设置CreationContext,其下的ctx:

 /// You can use this to customize the look of egui, e.g to call [`egui::Context::set_fonts`],/// [`egui::Context::set_visuals`] etc.pub egui_ctx: egui::Context,

context实现了set_fonts函数:

  /// Tell `egui` which fonts to use.       ////// The default `egui` fonts only support latin and cyrillic alphabets,/// but you can call this to install additional fonts that support e.g. korean characters.////// The new fonts will become active at the start of the next frame.pub fn set_fonts(&self, font_definitions: FontDefinitions) {crate::profile_function!();let pixels_per_point = self.pixels_per_point();let mut update_fonts = true;self.read(|ctx| {if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) {// NOTE: this comparison is expensive since it checks TTF data for equalityif current_fonts.lock().fonts.definitions() == &font_definitions {update_fonts = false; // no need to update}}});if update_fonts {self.memory_mut(|mem| mem.new_font_definitions = Some(font_definitions));}}

而set_fonts的参数是FontDefinitions,我们设置其font_data即可。

pub struct FontDefinitions {       /// List of font names and their definitions.////// `epaint` has built-in-default for these, but you can override them if you like.pub font_data: BTreeMap<String, FontData>,/// Which fonts (names) to use for each [`FontFamily`].////// The list should be a list of keys into [`Self::font_data`]./// When looking for a character glyph `epaint` will start with/// the first font and then move to the second, and so on./// So the first font is the primary, and then comes a list of fallbacks in order of priority.pub families: BTreeMap<FontFamily, Vec<String>>,
}

font_data实现了from_static函数:

 pub fn from_static(font: &'static [u8]) -> Self {   Self {font: std::borrow::Cow::Borrowed(font),index: 0,tweak: Default::default(),}}

我们为from_static传入自定义字体的字节数组即可,可以适应include_byets来获取数组:

const ICON_BYTES:&[u8]=include_bytes!("../font/simsun.ttf");

如上,我们下载simsun.ttf字体文件,放到项目文件夹中,然后获取其静态字节数组。

 // Start with the default fonts (we will be adding to them rather than replacing them). let mut fonts = egui::FontDefinitions::default();// Install my own font (maybe supporting non-latin characters).// .ttf and .otf files supported.fonts.font_data.insert("my_font".to_owned(),egui::FontData::from_static(ICON_BYTES,),);

这是官方提供的示例代码,我们只是修改其中的字体的内容。
使用自定义字体后,我们再来运行一下程序看看:
在这里插入图片描述
点击关闭按钮后:
在这里插入图片描述

好了,以上就是使用egui显示窗口时,如何显示中文的解决办法,基本上是基于官方给的示例。
本文并没有修改太多,因为主要是说明如何显示中文的问题。对于一些初学者来说,可能即使看官方示例和说明,也不知道如何解决这个问题,如果我这边的解释能帮助你,那就不枉了。

后续的文章里,中文字符显示的函数将会被独立出来,单独作为一个mod,然后在main中调用,这样也方便管理。

完整代码:
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release     
#![allow(rustdoc::missing_crate_level_docs)] // it's an exampleuse eframe::egui;const MY_FONTS_BYTES:&[u8]=include_bytes!("../font/simsun.ttf");fn main() -> eframe::Result {env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).let options = eframe::NativeOptions {viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),..Default::default()};eframe::run_native("egui测试窗口",options,//Box::new(|_cc| Ok(Box::<MyApp>::default())),Box::new(|cc| Ok(Box::new(MyApp::new(cc)))),)
}///
/// 设置自定义字体
/// 
fn setup_custom_fonts(ctx: &egui::Context) {// Start with the default fonts (we will be adding to them rather than replacing them).let mut fonts = egui::FontDefinitions::default();// Install my own font (maybe supporting non-latin characters).// .ttf and .otf files supported.fonts.font_data.insert("my_font".to_owned(),egui::FontData::from_static(MY_FONTS_BYTES,),);// Put my font first (highest priority) for proportional text:fonts.families.entry(egui::FontFamily::Proportional).or_default().insert(0, "my_font".to_owned());// Put my font as last fallback for monospace:fonts.families.entry(egui::FontFamily::Monospace).or_default().push("my_font".to_owned());// Tell egui to use these fonts:ctx.set_fonts(fonts);
}#[derive(Default)]
struct MyApp {show_confirmation_dialog: bool,allowed_to_close: bool,
}impl MyApp{fn new(cc: &eframe::CreationContext<'_>) -> Self {setup_custom_fonts(&cc.egui_ctx);Self {show_confirmation_dialog:false,allowed_to_close:false,}}
}impl eframe::App for MyApp {fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {egui::CentralPanel::default().show(ctx, |ui| {ui.heading("尝试关闭窗口");});if ctx.input(|i| i.viewport().close_requested()) {if self.allowed_to_close {// do nothing - we will close} else {ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);self.show_confirmation_dialog = true;}}if self.show_confirmation_dialog {egui::Window::new("你想要关闭吗?").collapsible(false).resizable(false).show(ctx, |ui| {ui.horizontal(|ui| {if ui.button("否").clicked() {self.show_confirmation_dialog = false;self.allowed_to_close = false;}if ui.button("是").clicked() {self.show_confirmation_dialog = false;self.allowed_to_close = true;ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);}});});}}
}

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

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

相关文章

应用实践之基于MobileNetv2的垃圾分类

MobileNetv2模型原理介绍 前言 MobileNet是2017年由Google团队提出的轻量级CNN网络&#xff0c;专注于移动端、嵌入式或IoT设备。它使用深度可分离卷积的思想来减小模型参数与运算量&#xff0c;同时引入宽度系数和分辨率系数以满足不同应用场景的需求。MobileNetV2则采用倒残…

STM32智能交通灯系统教程

目录 引言环境准备智能交通灯系统基础代码实现&#xff1a;实现智能交通灯系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;交通管理与优化问题解决方案与优化收尾与总结 1. 引言 智能交通灯系统通过STM…

Hadoop3:HDFS-存储优化之纠删码

一、集群环境 集群一共5个节点&#xff0c;102/103/104/105/106 二、纠删码原理 1、简介 HDFS默认情况下&#xff0c;一个文件有3个副本&#xff0c;这样提高了数据的可靠性&#xff0c;但也带来了2倍的冗余开销。Hadoop3.x引入了纠删码&#xff0c;采用计算的方式&#x…

【Python实战因果推断】37_双重差分8

目录 Diff-in-Diff with Covariates Diff-in-Diff with Covariates 您需要学习的 DID 的另一个变量是如何在模型中包含干预前协变量。这在您怀疑平行趋势不成立&#xff0c;但条件平行趋势成立的情况下非常有用&#xff1a; 考虑这种情况&#xff1a;您拥有与之前相同的营销数…

c语言唯一一个三目运算符

条件表达式由两个符号&#xff08;&#xff1f;和&#xff1a;&#xff09;组成&#xff0c;必须一起使用。要求有三个操作对象&#xff0c;称为三目运算符。 一般形式为 表达式1&#xff1f;表达式2&#xff1a;表达式3 理解如下&#xff1a; a>b?(maxa):(maxb); //相当…

Apache trino的ldap认证开启

作者&#xff1a;櫰木 1、背景 由于trino 默认没有开启用户认证体系&#xff0c;需要ldap用户进行认证。开启tls和ldap用户认证&#xff0c;提高安全性。 2、配置 前置条件。 trino 集群已经部署完成 ldap 服务 openjdk 版本大于11.0.17 生成证书 keytool -genkeypair…

【动态规划1】斐波那契数列模型篇

文章目录 声明动态规划介绍1137.第N个泰波那契数题目描述分析代码 面试题 08.01. 三步问题题目描述分析代码 746.使用最小花费爬楼梯题目描述分析代码 91.解码⽅法题目描述分析代码 声明 本篇博客为动态规的基础篇&#xff0c;从零开始学习动态规划&#xff0c;如有错误&#…

AGI 之 【Hugging Face】 的【问答系统】的 [评估并改进问答Pipeline] / [ 生成式问答 ] 的简单整理

AGI 之 【Hugging Face】 的【问答系统】的 [评估并改进问答Pipeline] / [ 生成式问答 ] 的简单整理 目录 AGI 之 【Hugging Face】 的【问答系统】的 [评估并改进问答Pipeline] / [ 生成式问答 ] 的简单整理 一、简单介绍 二、构建问答系统 三、评估并改进问答pipeline 1…

[k8s源码]4.informer

Informer 是 client-go 库中的一个核心组件,它提供了一种高效的方式来监视 Kubernetes 集群中资源的变化。Informer 通过 Watch 机制与 API Server 建立长连接&#xff0c;初次同步时会获取资源的完整列表&#xff0c;之后只接收增量更新,大大减少了网络流量。 使用informer可…

Java常用排序算法

算法复杂度 详解Java常用排序算法&#xff08;10种&#xff0c;含演示动画&#xff09; 冒泡排序&#xff08;Bubble Sort&#xff09; arr[0] 与 arr[1]比较&#xff0c;如果前面元素大就交换&#xff0c;如果后边元素大就不交换。然后依次arr[1]与arr[2]比较&#xff0c;第…

可视化工具选择指南:助力企业数字化转型和新质生产力发展

随着信息技术的快速发展和新质生产力概念的兴起&#xff0c;可视化工具在各个行业中的作用日益凸显。这些工具不仅能够帮助用户更直观地理解和分析数据&#xff0c;还能提升团队的协作效率和决策质量。 在当今数字化转型迅速发展的背景下&#xff0c;新质生产力的概念正在成为…

SpringBoot使用开发环境的application.properties

在Spring Boot项目中&#xff0c;application.properties 或 application.yml 文件是用于配置应用程序外部属性的重要文件。这些文件允许定制你的应用&#xff0c;而无需更改代码。根据不同的运行环境&#xff0c;可以通过创建以application-{profile}.properties格式命名的文件…

python-区间内的真素数(赛氪OJ)

[题目描述] 找出正整数 M 和 N 之间&#xff08;N 不小于 M&#xff09;的所有真素数。真素数的定义&#xff1a;如果一个正整数 P 为素数&#xff0c;且其反序也为素数&#xff0c;那么 P 就为真素数。 例如&#xff0c;11&#xff0c;13 均为真素数&#xff0c;因为 11 的反序…

利用Amazon Rekognition Face Liveness进行人脸活体检测的实践与探索

在人工智能、机器学习技术日渐普及的当下&#xff0c;出海企业都希望能够加快利用人工智能、机器学习技术&#xff0c;从而打造智能产品及其增值服务、为各地区提供本地化和个性化的服务体验及实现自身业务流程智能化。九河云将介绍人脸活体检测解决方案&#xff0c;亚马逊云科…

录频软件大盘点,哪款是你的最爱?

随着网络技术的飞速发展&#xff0c;人们对于录频软件的需求越来越强烈。无论是教育工作者、学生、游戏玩家还是商务人士&#xff0c;一款合适的录频软件都可以为他们提供便利。本文将介绍3款主流的录频软件&#xff0c;以帮助用户了解它们的特点、功能以及操作方法。 录频软件…

在Centos上安装MySQL

目录 在Centos上安装MySQL1.确认当前的系统版本2.添加 MySQL Yum 源2.1访问MySQL开发者专区2.2根据当前系统选择对应的发布包2.3补充 3.MySQL的历史发行版本4.安装发布包5.安装MySQL5.1启动MySQL服务器5.2查看服务器状态5.3开机自启动5.4 登入MySQL5.5修改密码 在Centos上安装M…

Spring Data Redis + Redis数据缓存学习笔记

文章目录 1 Redis 入门1.1 简介1.2 Redis服务启动与停止&#xff08;Windows&#xff09;1.2.1 服务启动命令1.2.2 客户端连接命令1.2.3 修改Redis配置文件1.2.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍 3. Redis常用命令3.1 字符串操作命令3.2 哈希操作…

Docker-Nvidia(NVIDIA Container Toolkit)

安装NVIDIA Container Toolkit工具&#xff0c;支持docker使用GPU 目录 1.NVIDIA Container Toolkit 安装1.1 nvidia-docker安装1.2 验证1.2.1 验证安装1.2.2 额外补充 1.NVIDIA Container Toolkit 安装 1.1 nvidia-docker安装 NVIDIA/nvidia-docker Installing the NVIDIA …

SQL Server Query Store Settings (查询存储设置)

参考&#xff1a;Query Store Settings - Erin Stellato 在 SQL Server 2017 中&#xff0c;有九 (9) 个设置与查询存储相关。虽然这些设置记录在sys.database_query_store_options中&#xff0c;但我经常被问到每个设置的值“应该”是多少。我在下面列出了每个设置&am…

AI数字人直播源码解析:灰豚私有化部署背后的技术分析

随着AI数字人技术的应用潜力不断显现&#xff0c;与AI数字人相关的多个项目逐渐成为创业者们的重点关注对象&#xff0c;作为当前AI数字人典型应用场景之一的数字人直播意向人数更是屡创新高&#xff0c;AI数字人直播源码部署的热度也因此不断飙升&#xff0c;与各大数字人源码…