最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Rust中GUI庫(kù)egui的簡(jiǎn)單應(yīng)用指南

 更新時(shí)間:2024年03月13日 17:05:54   作者:二次元攻城獅  
egui(發(fā)音為“e-gooey”)是一個(gè)簡(jiǎn)單、快速且高度可移植的 Rust 即時(shí)模式 GUI 庫(kù),跨平臺(tái)、Rust原生,適合一些小工具和游戲引擎GUI,下面就跟隨小編一起來(lái)看看它的具體使用吧

簡(jiǎn)介

egui(發(fā)音為“e-gooey”)是一個(gè)簡(jiǎn)單、快速且高度可移植的 Rust 即時(shí)模式 GUI 庫(kù),跨平臺(tái)、Rust原生,適合一些小工具和游戲引擎GUI:

文檔:https://docs.rs/egui/latest/egui/

演示:https://www.egui.rs/#demo

github:https://github.com/emilk/egui

關(guān)于即時(shí)模式GUI,可以參考 使用C++界面框架ImGUI開(kāi)發(fā)一個(gè)簡(jiǎn)單程序 里面的介紹,ImGUI是C++的一個(gè)即時(shí)模式GUI庫(kù)。

簡(jiǎn)單示例

創(chuàng)建項(xiàng)目

首先使用cargo工具快速構(gòu)建項(xiàng)目:

cargo new eguitest

然后添加依賴:

cargo add eframe

egui只是一個(gè)圖形庫(kù),而不是圖形界面開(kāi)發(fā)框架,eframe是與egui配套使用的圖形框架

為了靜態(tài)插入圖片,還需要增加egui_extras依賴:

cargo add egui_extras

然后在Cargo.toml文件中編輯features

egui_extras = { version = "0.26.2", features = ["all_loaders"] }

界面設(shè)計(jì)

打開(kāi)src/main.rc,編寫(xiě)第一個(gè)eframe示例程序:

//隱藏Windows上的控制臺(tái)窗口
#![windows_subsystem = "windows"]

use eframe::egui;

fn main() -> Result<(), eframe::Error> {
    // 創(chuàng)建視口選項(xiàng),設(shè)置視口的內(nèi)部大小為320x240像素
    let options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
        ..Default::default()
    };

    // 運(yùn)行egui應(yīng)用程序
    eframe::run_native(
        "My egui App", // 應(yīng)用程序的標(biāo)題
        options, // 視口選項(xiàng)
        Box::new(|cc| {
            // 為我們提供圖像支持
            egui_extras::install_image_loaders(&cc.egui_ctx);
            // 創(chuàng)建并返回一個(gè)實(shí)現(xiàn)了eframe::App trait的對(duì)象
            Box::new(MyApp::new(cc))
        }),
    )
}

//定義 MyApp 結(jié)構(gòu)體
struct MyApp {
    name: String,
    age: u32,
}

//MyApp 結(jié)構(gòu)體 new 函數(shù)
impl MyApp {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {        
        // 結(jié)構(gòu)體賦初值
        Self {
            name: "Arthur".to_owned(),
            age: 42,
        }
    }
}

//實(shí)現(xiàn) eframe::App trait 
impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        // 在中央面板上顯示egui界面
        egui::CentralPanel::default().show(ctx, |ui| {
            // 顯示標(biāo)題
            ui.heading("My egui Application"); 
            // 創(chuàng)建一個(gè)水平布局
            ui.horizontal(|ui| {
                // 顯示姓名標(biāo)簽
                let name_label = ui.label("Your name: "); 
                // 顯示姓名輸入框(單行文本框)
                ui.text_edit_singleline(&mut self.name) 
                    .labelled_by(name_label.id); // 關(guān)聯(lián)標(biāo)簽
            });

            // 顯示年齡滑塊
            ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age")); 

            if ui.button("Increment").clicked() {
                // 點(diǎn)擊按鈕后將年齡加1
                self.age += 1;
            }

            // 顯示問(wèn)候語(yǔ)
            ui.label(format!("Hello '{}', age {}", self.name, self.age));            
            // 顯示圖片,圖片放在main.rs的同級(jí)目錄下(可以自定義到其它目錄)
            ui.image(egui::include_image!("ferris.png")); 
        });
    }
}

運(yùn)行結(jié)果如下:

切換主題

egui提供了明亮、暗黃兩種主題,在APP結(jié)構(gòu)體上添加 theme_switcher 方法:

impl MyApp {
    // 切換主題
    fn theme_switcher(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) {
        ui.horizontal(|ui| {
            if ui.button("Dark").clicked() {
                ctx.set_visuals(egui::Visuals::dark());
            }
            if ui.button("Light").clicked() {
                ctx.set_visuals(egui::Visuals::light());
            }
        });
    }
}

然后在update函數(shù)中調(diào)用:

egui::CentralPanel::default().show(ctx, |ui| {
   //...
   // 切換主題
   self.theme_switcher(ui, ctx);
   // 顯示圖片
   ui.image(egui::include_image!("ferris.png")); 
});

egui的Style結(jié)構(gòu)體可以自定義主題,不過(guò)一般默認(rèn)主題就夠用了。

自定義字體

egui默認(rèn)不支持中文,實(shí)現(xiàn)一個(gè) setup_custom_fonts 函數(shù):

//自定義字體
fn setup_custom_fonts(ctx: &egui::Context) {
    // 創(chuàng)建一個(gè)默認(rèn)的字體定義對(duì)象
    let mut fonts = egui::FontDefinitions::default();

    //安裝的字體支持.ttf和.otf文件
    //文件放在main.rs的同級(jí)目錄下(可以自定義到其它目錄)
    fonts.font_data.insert(
        "my_font".to_owned(),
        egui::FontData::from_static(include_bytes!(
            "msyh.ttc"  
        )),
    );

    // 將字體添加到 Proportional 字體族的第一個(gè)位置
    fonts
        .families
        .entry(egui::FontFamily::Proportional)
        .or_default()
        .insert(0, "my_font".to_owned());

    // 將字體添加到 Monospace 字體族的末尾
    fonts
        .families
        .entry(egui::FontFamily::Monospace)
        .or_default()
        .push("my_font".to_owned());

    // 將加載的字體設(shè)置到 egui 的上下文中
    ctx.set_fonts(fonts);
}

然后再M(fèi)yApp結(jié)構(gòu)體的new方法中調(diào)用:

//...
impl MyApp {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {
        //加載自定義字體
        setup_custom_fonts(&cc.egui_ctx);     
        //...
    }
}
//...

運(yùn)行結(jié)果:

自定義圖標(biāo)

先導(dǎo)入image庫(kù),在終端中運(yùn)行:

cargo add image

還需要導(dǎo)入std::sync::Arc、eframe::egui::IconData ,庫(kù)引入?yún)^(qū)如下:

use eframe::egui;
use eframe::egui::IconData;
use std::sync::Arc;
use image;

在main()函數(shù)中將native_options的聲明改為可變變量的聲明,并加入改變圖標(biāo)代碼:

fn main() -> Result<(), eframe::Error> {
    // 創(chuàng)建視口選項(xiàng),設(shè)置視口的內(nèi)部大小為320x240像素
    let mut options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
        ..Default::default()
    };

    //導(dǎo)入圖標(biāo),圖片就用上面的
    let icon_data = include_bytes!("ferris.png");
    let img = image::load_from_memory_with_format(icon_data, image::ImageFormat::Png).unwrap();
    let rgba_data = img.into_rgba8();
    let (width, height) =(rgba_data.width(),rgba_data.height());
    let rgba: Vec<u8> = rgba_data.into_raw();
    options.viewport.icon=Some(Arc::<IconData>::new(IconData { rgba, width, height}));
    
    // ...    
}

經(jīng)典布局

在上面示例的基礎(chǔ)上,實(shí)現(xiàn)一個(gè)上中下或左中右的經(jīng)典三欄布局,main函數(shù)不需要修改,只需要修改MyApp結(jié)構(gòu)體的定義即可。

定義導(dǎo)航變量

先定義一個(gè)導(dǎo)航枚舉,用來(lái)在標(biāo)記當(dāng)前要顯示的界面:

//導(dǎo)航枚舉
enum Page {
    Test,
    Settings,
}

為了方便理解示例,在 MyApp 中只定義一個(gè) page 字段,并同步修改new函數(shù):

//定義 MyApp 結(jié)構(gòu)體
struct MyApp {
    page:Page,
}
//MyApp 結(jié)構(gòu)體 new 函數(shù)
impl MyApp {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {
        setup_custom_fonts(&cc.egui_ctx);     
        // 結(jié)構(gòu)體賦初值
        Self {
            page:Page::Test,
        }
    }
}

實(shí)現(xiàn)導(dǎo)航界面

在 MyApp 中定義導(dǎo)航欄的界面,

impl MyApp {  

    //左側(cè)導(dǎo)航按鈕,egui沒(méi)有內(nèi)置樹(shù)控件,有需要可以自己實(shí)現(xiàn)
    fn left_ui(&mut self, ui: &mut egui::Ui)  {   
        //一個(gè)垂直布局的ui,內(nèi)部控件水平居中并對(duì)齊(填充全寬)
        ui.vertical_centered_justified(|ui| {          
            
            if ui.button("測(cè)試").clicked() {
                self.page=Page::Test;
            }

            if ui.button("設(shè)置").clicked() {
                self.page=Page::Settings;
            }
            //根據(jù)需要定義其它按鈕
        });
    }

    //...其它方法
}

實(shí)現(xiàn)導(dǎo)航邏輯

在 MyApp 中定義一個(gè) show_page 方法來(lái)進(jìn)行界面調(diào)度,每個(gè)界面再單獨(dú)實(shí)現(xiàn)自己的UI函數(shù)

impl MyApp {  
    //...其它方法

    //根據(jù)導(dǎo)航顯示頁(yè)面
    fn show_page(&mut self, ui: &mut egui::Ui)  {   

        match self.page {
            Page::Test => {
                self.test_ui(ui);
            }
            Page::Settings => {
                //...
            }
        }       
    }

    //為了方便理解示例這里只顯示一張圖片
    fn test_ui(&mut self, ui: &mut egui::Ui)  {         
        ui.image(egui::include_image!("ferris.png"));
    }

    //...其它方法
}

實(shí)現(xiàn)主框架布局

在 MyApp 中間實(shí)現(xiàn) main_ui 方法,可以根據(jù)自己的需要調(diào)整各個(gè)欄的位置:

impl MyApp {  
    //...其它方法
    //主框架布局
    fn main_ui(&mut self, ui: &mut egui::Ui)  {        
        // 添加面板的順序非常重要,影響最終的布局
        egui::TopBottomPanel::top("top_panel")
        .resizable(true)
        .min_height(32.0)
        .show_inside(ui, |ui| {
            egui::ScrollArea::vertical().show(ui, |ui| {
                ui.vertical_centered(|ui| {
                    ui.heading("標(biāo)題欄");
                });
                ui.label("標(biāo)題欄內(nèi)容");
            });
        });

        egui::SidePanel::left("left_panel")
        .resizable(true)
        .default_width(150.0)
        .width_range(80.0..=200.0)
        .show_inside(ui, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("左導(dǎo)航欄");
            });
            egui::ScrollArea::vertical().show(ui, |ui| {
                self.left_ui(ui);
            });
        });

        egui::SidePanel::right("right_panel")
        .resizable(true)
        .default_width(150.0)
        .width_range(80.0..=200.0)
        .show_inside(ui, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("右導(dǎo)航欄");
            });
            egui::ScrollArea::vertical().show(ui, |ui| {
                ui.label("右導(dǎo)航欄內(nèi)容");
            });
        });

        egui::TopBottomPanel::bottom("bottom_panel")
        .resizable(false)
        .min_height(0.0)
        .show_inside(ui, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("狀態(tài)欄");
            });
            ui.vertical_centered(|ui| {
                ui.label("狀態(tài)欄內(nèi)容");
            });
        });

        egui::CentralPanel::default().show_inside(ui, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("主面板");
            });
            egui::ScrollArea::vertical().show(ui, |ui| {
                ui.label("主面板內(nèi)容");

                self.show_page(ui);
            });
        });
    }       
}

調(diào)試運(yùn)行

在 main 函數(shù)中稍微調(diào)整一下窗口大?。?/p>

// 創(chuàng)建視口選項(xiàng)
let mut options = eframe::NativeOptions {
    viewport: egui::ViewportBuilder::default().with_inner_size([1000.0, 500.0]),
    ..Default::default()
};

在 update 函數(shù)中調(diào)用 main_ui 函數(shù):

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        //設(shè)置主題
        ctx.set_visuals(egui::Visuals::dark());
        // 在中央面板上顯示egui界面
       egui::CentralPanel::default().show(ctx, |ui| {
        self.main_ui(ui); 
       });        
    }
}

運(yùn)行結(jié)果如下:

以上就是Rust中GUI庫(kù)egui的簡(jiǎn)單應(yīng)用指南的詳細(xì)內(nèi)容,更多關(guān)于Rust egui的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Rust 高性能內(nèi)存緩存 moka 完全指南

    Rust 高性能內(nèi)存緩存 moka 完全指南

    本文介紹了Rust高性能內(nèi)存緩存庫(kù)moka,涵蓋其核心特性、基礎(chǔ)環(huán)境搭建、同步/異步實(shí)戰(zhàn)、高級(jí)配置及生產(chǎn)環(huán)境最佳實(shí)踐等內(nèi)容,感興趣的可以了解一下
    2026-05-05
  • Rust 連接 SQLite 數(shù)據(jù)庫(kù)的過(guò)程解析

    Rust 連接 SQLite 數(shù)據(jù)庫(kù)的過(guò)程解析

    本文通過(guò)一個(gè)例子給大家介紹了Rust 連接 SQLite 數(shù)據(jù)庫(kù)的詳細(xì)過(guò)程,我使用rusqlite這個(gè)crate,對(duì)Rust 連接 SQLite 數(shù)據(jù)庫(kù)相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧
    2022-01-01
  • Rust 中的文件操作示例詳解

    Rust 中的文件操作示例詳解

    Rust 中的路徑操作是跨平臺(tái)的,std::path 模塊提供的了兩個(gè)用于描述路徑的類型,本文給大家介紹Rust 中的文件操作示例詳解,感興趣的朋友一起看看吧
    2021-11-11
  • Rust常用功能實(shí)例代碼匯總

    Rust常用功能實(shí)例代碼匯總

    通過(guò)一系列實(shí)用示例展示了Rust在文件操作、網(wǎng)絡(luò)請(qǐng)求、并發(fā)編程、命令行工具以及數(shù)據(jù)庫(kù)操作等方面的應(yīng)用,這些示例不僅展示了 Rust 的強(qiáng)大功能,還提供了實(shí)際開(kāi)發(fā)中的指導(dǎo)和參考,通過(guò)這些示例,您可以更好地理解 Rust 的特性,并將其應(yīng)用于您的項(xiàng)目中
    2024-12-12
  • Rust中Protobuf使用詳解

    Rust中Protobuf使用詳解

    本文介紹了如何在Rust中使用Protobuf進(jìn)行序列化和反序列化,并介紹了如何在項(xiàng)目中使用生成的Rust代碼,通過(guò)include!宏和mod.rs文件的配置,可以方便地在Rust項(xiàng)目中使用Protobuf,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • 關(guān)于Rust編譯時(shí)報(bào)link.exe?not?found錯(cuò)誤問(wèn)題

    關(guān)于Rust編譯時(shí)報(bào)link.exe?not?found錯(cuò)誤問(wèn)題

    這篇文章主要介紹了Rust編譯的時(shí)候報(bào)出link.exe?not?found錯(cuò)誤問(wèn)題,解決方法是在命令行就是CMD執(zhí)行相應(yīng)的命令即可,本文給大家分解決方法,需要的朋友可以參考下
    2022-09-09
  • Rust在寫(xiě)庫(kù)時(shí)實(shí)現(xiàn)緩存的操作方法

    Rust在寫(xiě)庫(kù)時(shí)實(shí)現(xiàn)緩存的操作方法

    Moka是一個(gè)用于Rust的高性能緩存庫(kù),它提供了多種類型的緩存數(shù)據(jù)結(jié)構(gòu),包括哈希表、LRU(最近最少使用)緩存和?支持TTL(生存時(shí)間)緩存,這篇文章給大家介紹Rust在寫(xiě)庫(kù)時(shí)實(shí)現(xiàn)緩存的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2024-01-01
  • 前端基于Rust實(shí)現(xiàn)的Wasm進(jìn)行圖片壓縮的技術(shù)文檔(實(shí)現(xiàn)方案)

    前端基于Rust實(shí)現(xiàn)的Wasm進(jìn)行圖片壓縮的技術(shù)文檔(實(shí)現(xiàn)方案)

    在現(xiàn)代Web開(kāi)發(fā)中,利用Rust編寫(xiě)的圖片壓縮代碼可以編譯成WebAssembly(Wasm)模塊,Rust的內(nèi)存安全特性和Wasm的跨平臺(tái)能力,使得這種方案既高效又安全,對(duì)Rust?Wasm圖片壓縮實(shí)現(xiàn)方案感興趣的朋友一起看看吧
    2024-09-09
  • 使用vscode配置Rust運(yùn)行環(huán)境全過(guò)程

    使用vscode配置Rust運(yùn)行環(huán)境全過(guò)程

    VS Code對(duì)Rust有著較完備的支持,這篇文章主要給大家介紹了關(guān)于使用vscode配置Rust運(yùn)行環(huán)境的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • 深入剖析Rust 中的 Move、Copy 和 Clone

    深入剖析Rust 中的 Move、Copy 和 Clone

    在 Rust 編程語(yǔ)言中,move、Copy 和 Clone 是所有權(quán)系統(tǒng)的核心概念,它們深刻影響著數(shù)據(jù)的傳遞和復(fù)制方式,這些機(jī)制不僅確保了內(nèi)存安全,還提供了高效的性能優(yōu)化手段,本文將深入探討這些概念的內(nèi)部機(jī)制、使用場(chǎng)景、性能影響以及高級(jí)用法,感興趣的朋友一起看看吧
    2025-05-05

最新評(píng)論

合作市| 清水县| 额济纳旗| 松阳县| 东至县| 全南县| 新泰市| 博湖县| 漳平市| 定兴县| 定南县| 苏尼特右旗| 贞丰县| 海盐县| 丰台区| 桃江县| 卓资县| 遂平县| 鄂托克前旗| 大石桥市| 白水县| 紫金县| 勐海县| 永康市| 巴彦淖尔市| 清流县| 榆社县| 土默特右旗| 双峰县| 平罗县| 和政县| 临桂县| 静安区| 科技| 彭州市| 五大连池市| 浦江县| 普安县| 长丰县| 福贡县| 泰和县|