<Rust>egui部件学习:如何在egui窗口中添加按钮button以及标签label部件?

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

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

概述
本文是本专栏的第二篇博文,主要讲述按钮button、标签label部件的使用。

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

系列博文链接:
1、<Rust>egui部件学习:如何在窗口及部件显示中文字符?

基于第一篇文章,我们将设置自定义字体的函数写到单独的mod里:
在这里插入图片描述
名称可以自己起,如setfont,然后我们在main中调用函数即可。具体函数代码和之前是一样的,就不重复贴了,但是这里稍作了修改,将字体的字节数组作为参数传给函数:

pub fn setup_custom_fonts(ctx: &egui::Context,fontbyte:&'static [u8]) 

并且为了能在其他mod里调用,函数前面添加了pub关键词。

在第一篇中,我们只是介绍了如何显示中文字符,本文我们会说明窗口的显示,以及如何添加按钮、标签部件。

部件属性
窗口显示

先来看窗口的显示,不同于iced库。egui的部件显示和更新都放在了update函数里。而iced的部件显示放在view函数,响应则放在update中。
官方给出的典型的egui代码如下:

use eframe::egui;            

fn main() {
    let native_options = eframe::NativeOptions::default();
     eframe::run_native("My egui App", native_options, Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc)))));
}

 #[derive(Default)]
 struct MyEguiApp {}

 impl MyEguiApp {
     fn new(cc: &eframe::CreationContext<'_>) -> Self {
         // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
         // Restore app state using cc.storage (requires the "persistence" feature).
         // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
         // for e.g. egui::PaintCallback.
         Self::default()
     }
 }

 impl eframe::App for MyEguiApp {
    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("Hello World!");
        });
    }
 }

和iced是有些类似的,我们创建一个结构体,里面是我们要操作的数据,然后我们为其实现eframe的app特性,窗口建立后,结构体数据就可以通过app的update来更新了。
不同于iced,iced中application是包含了new函数的,但是egui的app中,并没有直接添加new,而是需要单独实现:

impl MyApp{
    fn new(cc: &eframe::CreationContext<'_>) -> Self { 
        setfont::setup_custom_fonts(&cc.egui_ctx,MY_FONTS_BYTES);
        Self {
            show_confirmation_dialog:false,
            allowed_to_close:false,
        }
    }
}

我们设置自定义字体,就是在new函数中初始化的。

按钮部件button

窗口可以显示了,但是运行后只是一个空的窗体,我们需要在其中添加按钮等部件,以实现和窗口的交互。
egui中,部件的添加,都是在show函数里:

 egui::CentralPanel::default().show(ctx, |ui| {  
            ui.heading("尝试关闭窗口");
            ui.button("按钮1")
            
        });

如上,show有两个参数,ctx可以设置UI的格式,而add_contents用于添加其他部件:

ui.button("按钮1") 

这种方式是快捷的调用,它返回的是一个Response,即交互数据,我们可以使用Response来进行逻辑处理。比如,按钮点击响应,可以这样设置:

 let btn_res=ui.button("按钮1");                  
 if btn_res.clicked(){
        println!("按钮1点击")
 }else {
                
}

根据egui的介绍,egui是即时模式,作者在github解释了这个问题:
在这里插入图片描述
在这里插入图片描述
所以,根据作者的说明,egui是很适合集成到游戏开发中的,如果你要了解更多,可以参考作者给出的说明:
https://docs.rs/egui/latest/egui/#understanding-immediate-mode

总的来说,egui并不需要存储部件以供使用,而是即时刷新,所以,egui的缺点是布局不是很方便,因为是即时刷新,所以需要提前知道布局。而且,有些场景下,可能还会有很大的问题,这是一个需要注意的点。

好了,我们现在回到本文的内容上,我们在update中添加了按钮后,我们来运行看一下:
在这里插入图片描述
当我们点击按钮后,会在控制台打印文本:
在这里插入图片描述

标签部件label

现在我们在窗口添加标签,点击按钮,将文本显示在标签上。

 let btn_res=ui.button("按钮1"); 
            if btn_res.clicked(){
                //println!("按钮1点击")
                self.lbltext="按钮1点击".to_string();
            }else {
                
            }
            ui.label(format!("{}",self.lbltext))

如上,我们添加了label,其文本内容是一个格式化的参数:

format!("{}",self.lbltext)

这样设置是为了文本可以动态变化,其中self.lbltext是我们在结构体中创建的元素:

#[derive(Default)]
struct MyApp {
    show_confirmation_dialog: bool,   
    allowed_to_close: bool,
    lbltext:String,
}

这样,运行后,我们点击按钮,就可以在标签上显示内容:
在这里插入图片描述
在这里插入图片描述
当然,我们也可以是文本框输入部件,来动态输入文本,来查看标签内容变化,不够,文本输入我们将在下一个章节里介绍,本文就不在赘述了。

完整代码

main.rs

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release      
#![allow(rustdoc::missing_crate_level_docs)] // it's an example 

use eframe::egui; 

mod setfont; 

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)))), 
    )
}



#[derive(Default)]
struct MyApp {
    show_confirmation_dialog: bool, 
    allowed_to_close: bool, 
    lbltext:String, 
}

impl MyApp{
    fn new(cc: &eframe::CreationContext<'_>) -> Self { 
        setfont::setup_custom_fonts(&cc.egui_ctx,MY_FONTS_BYTES); 
        Self { 
            show_confirmation_dialog:false, 
            allowed_to_close:false, 
            lbltext:"no text".to_string(), 
        }
    }
}

impl eframe::App for MyApp { 
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { 
        egui::CentralPanel::default().show(ctx, |ui| { 
            ui.heading("尝试关闭窗口");
            let btn_res=ui.button("按钮1"); 
            if btn_res.clicked(){ 
                //println!("按钮1点击")
                self.lbltext="按钮1点击".to_string();
            }else { 
                
            }
            ui.text_edit_singleline(&mut self.lbltext); 
            ui.label(format!("{}",self.lbltext))
            
        });

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Zookeeper源码学习

源码下载&#xff1a;https://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7.tar.gz 1、持久化源码&#xff1a; Leader和Follower中的数据会在内存和磁盘中各保存一份。所以需要将内存中的数据持久化到磁盘中。 在zookeeper-server\org.apach…

计组_微程序

2024.06.26&#xff1a;计算机组成原理微程序学习笔记 第19节 控制器 9.1 硬布线控制器&#xff08;408基本不考&#xff09;9.2 微程序控制器&#xff08;好好学&#xff09;9.2.1 微程序(1) 基本概念(2) 控制器的组成(3) 控制器的工作过程 9.2.2 微指令(1) 编码方式&#xff…

验证服务插件:单据保存或审核时进行验证

提交审核的时候,校验 using Kingdee.BOS; using Kingdee.BOS.Core; using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Core.Validation; using Kingdee.BOS.Util; using System; using System.ComponentModel;…

【LeetCode:721. 账户合并 + 哈希表 + DFS】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Linux--线程池(包含日志的解释)

线程系列&#xff1a; Linux–线程的认识(一) Linux–线程的分离、线程库的地址关系的理解、线程的简单封装&#xff08;二&#xff09; 线程的互斥&#xff1a;临界资源只能在同一时间被一个线程使用 生产消费模型 信号量 线程池 线程池&#xff08;Thread Pool&#xff09;是…

CSS实现超链接标签:鼠标光标为手形、取消下划线、当鼠标悬停时显示下划线

1、鼠标光标为手形 cursor: pointer; 2、显示/取消下划线 text-decoration: none; /* 文本取消下划线 */ text-decoration: underline; /* 文本添加下划线 */ 3、伪类选择器 伪类选择器是 CSS 中已经定义好的选择器&#xff0c;因此程序员不能随意命令。伪类选择器…

【BUG】已解决:ModuleNotFoundError: No module named ‘cv2’

已解决&#xff1a;ModuleNotFoundError: No module named ‘cv2’ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开…

C 语言指针进阶

1.0 指针的定义 指针是内存中一个最小单元的编号&#xff08;内存单元的编号称之为地址【地址就是指针指针就是地址】&#xff09;指针通常是用来存放内存地址的一个变量。本质上指针就是地址&#xff1a;口语上说的指针起始是指针变量&#xff0c;指针变量就是一个变量&#…

51单片机10(蜂鸣器介绍)

一、蜂鸣器介绍&#xff1a; 1、蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电&#xff0c;广泛应用于电子产品中作为发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器。 &#xff08;1&#xff09;压电式蜂鸣器&#xff0c;它主要由多谐的一个增胀器…

JVM--自动内存管理--JAVA内存区域

1. 运行时数据区域 灰色的线程共享&#xff0c;白色的线程独享 白色的独享就是根据个体"同生共死" 程序计数器&#xff1a; 是唯一一个没有OOM(内存溢出)的地方 是线程独享的 作用&#xff1a; 是一块较小的内存空间,是当前线程所执行的字节吗的行号指示器 由于…

C#学习3-微软C#官方文档Microsoft-dotnet-csharp.pdf

文章目录 1.内插表达式的字段宽度和对齐方式 1.内插表达式的字段宽度和对齐方式 static void Main(string[] args) {var titles new Dictionary<string, string>() {["Doyle ,Arthur"] "Hound of the Basker,The",["Lodon ,Jack"] &quo…

vue router 切换路由的时候,页面的动画效果,使页面切换好看,以及控制有的页面使用切换路由特效,有的页面不用

一、使用切换效果 在router文件中 useTransition: true代表需要动画 meta: { title: “新开卡预填表单”, keepAlive: true, useTransition: true }, [{path: "/",name: "Home",meta: {title: "首页",keepAlive: true,useTransition: false},c…

Python 给存入 Redis 的键值对设置过期时间

Redis 是一种内存中的数据存储系统&#xff0c;与许多传统数据库相比&#xff0c;它具有一些优势&#xff0c;其中之一就是可以设置数据的过期时间。通过 Redis 的过期时间设置&#xff0c;可以为存储在 Redis 中的数据设置一个特定的生存时间。一旦数据到达过期时间&#xff0…

alike-cpp 编译

1. 源码链接&#xff1a; https://github.com/Shiaoming/ALIKE-cpp 2.已经安装好显卡驱动&#xff0c;cuda&#xff0c;cudnn,没安装的参考&#xff1a; 切记装cuda-11.x的版本&#xff0c;最好cuda11.3的版本 ubuntu重装系统后&#xff0c;安装cuda,cudnn-CSDN博客 3.安装…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(十三)-更换无人机控制器

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

vitest 单元测试应用与配置

vitest 应用与配置 一、简介 Vitest 旨在将自己定位为 Vite 项目的首选测试框架&#xff0c;即使对于不使用 Vite 的项目也是一个可靠的替代方案。它本身也兼容一些Jest的API用法。 二、安装vitest // npm npm install -D vitest // yarn yarn add -D vitest // pnpm pnpm …

应用实践之基于MindNLP+MusicGen生成自己的个性化音乐

前言 MusicGen是基于单个语言模型&#xff08;LM&#xff09;的音乐生成模型&#xff0c;使用文本描述或音频提示生成高质量的音乐样本。它基于Transformer结构&#xff0c;包括文本编码器模型和音频压缩模型&#xff0c;以及一个解码器来预测离散的隐形状态音频token。与传统…

《mysql篇》--JDBC编程

JDBC是什么 JDBC就是Java DataBase Connectivity的缩写&#xff0c;翻译过来就很好理解了&#xff0c;就是java连接数据库。所以顾名思义&#xff0c;JDBC就是一种用于执行SQL语句的JavaApl&#xff0c;是Java中的数据库连接规范。为了可以方便的用Java连接各种数据库&#xff…

WSL2 的安装与运行 Linux 系统

前言 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能&#xff0c;允许开发人员在 Windows 系统上直接安装并使用 Linux 发行版。不用进行任何修改&#xff0c;也无需承担传统虚拟机或双启动设置的开销。 可以将 WSL 看作也是一个虚拟机&#xff0c;但是它更为便…

Contact Form联系表单自动发送邮件(超级简单)

前几天发现了aoksend推出的这个联系表单的组件&#xff0c;非常好用&#xff0c;只有一个php文件&#xff0c;把php文件放到网站主目录里面。然后去aoksend注册和配置好域名和发信邮箱&#xff0c;可以得到发送密钥&#xff1a;app_key&#xff0c;然后配置好邮件模板&#xff…