Rust GUI库egui/eframe初探入门(四):使用egui_plotters进行绘图

在上一篇中,我们实现了动态地加载图片到窗口中:
Rust GUI库egui/eframe初探入门(三):实现动态读取图片并显示
我们使用了plotters库进行绘图,并将绘制地曲线保存在本地。然后我们再动态地读取图片并显示。这样显然开销很大,还浪费了存储空间。这次我们将使用egui_plotter这个库来方便地让egui/eframe在内存中直接使用plotters绘制的图形。
但是遗憾的是,目前egui_plotter的版本是0.3.0,只能支持到egui/eframe的0.22.x版本。而目前最新的egui/eframe版本是0.25.0版本。egui/eframe的0.25与0.22版本在API上还是有不少的不同,需要我们去注意。
实际上在github的egui_plotter仓库中已经有贡献者提交了支持0.25版本egui/eframed的egui_plotter修改。但该库的原作者似乎很长时间没有活跃了。后续如果想要在0.25及以后版本的egui/eframe库中使用egui_plotter,或许只能自行下载egui_plotter的github版本进行修改。
本次我们将直接使用0.22.0的egui/eframe来体验一下egui_plotters这个库。

修改eframe依赖版本

我们在cargo.toml中,修改一下导入的eframe版本:

[dependencies]
eframe = "0.22.0"
egui-plotter = "0.3.0"
image = "0.24.7"
plotters = "0.3.5"

修改main.rs程序文件

在该系列的前文中,我们实现过修改程序的图标。当我们使用0.22.0的egui/eframe时,修改图标的代码略有不同。我们不再需要使用一个Arc智能指针去包裹图标,也不再需要导入Arc包。image_loader不再需要,所以egui_extras库也就不再需要了。
修改库的导入区如下:

use eframe::egui;
use plotters::prelude::*;
use egui_plotter::EguiBackend;
use image;

修改main函数如下:

fn main() {
    let mut native_options = eframe::NativeOptions::default();
    let icon_data = include_bytes!("icon.png");
    let img = image::load_from_memory_with_format(icon_data, image::ImageFormat::Png).unwrap();
    let rgba_data = img.into_rgba8();
    let (w,h)=(rgba_data.width(),rgba_data.height());
    let raw_data: Vec<u8> = rgba_data.into_raw();
    native_options.icon_data=Some(eframe::IconData { rgba:  raw_data, width: w, height: h });
    eframe::run_native("外特性计算", native_options, Box::new(|cc| Box::new(MyEguiApp::new(cc))));
}

接下来我们修改上一篇代码中的plot_characteristic函数部分内容。
实际上只需要将赋值给root变量的backend修改一下即可。完整的plot_characteristic函数内容如下:

fn plot_characteristic(data:&MyEguiApp,ui:&egui::Ui)-> Result<(), Box<dyn std::error::Error>> {
    let max_speed=data.n as f32;
    let max_torque=data.T as f32;
    let max_power=data.P as f32;
    let rated_speed=max_power*9550.0/max_torque;

    let root = EguiBackend::new(ui).into_drawing_area();
    root.fill(&WHITE)?;
    let mut chart = ChartBuilder::on(&root)
        .caption("外特性", ("sans-serif", 25).into_font())
        .margin(5)
        .x_label_area_size(30)
        .y_label_area_size(30)
        .build_cartesian_2d(0f32..max_speed*1.05, 0f32..max_torque*1.05)?;

    chart.configure_mesh().draw()?;

    chart
        .draw_series(LineSeries::new(
            (0..=max_speed as i32).map(|x| x as f32).map(|x| {if x<=rated_speed{(x,max_torque)}else{(x,max_power*9550.0/x)}}),
            &RED,
        ))?
        .label("Torque")
        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));

    chart
        .configure_series_labels()
        .background_style(&WHITE.mix(0.8))
        .border_style(&BLACK)
        .draw()?;
    root.present()?;
    Ok(())
}

接下来对应用的update函数部分进行修改。
在上一篇的基础上,我们将绘制图形按钮改变为“显示曲线”/“隐藏曲线”这两个按钮。在显示曲线的情况下,将在每一帧中不停更新曲线图像。同时我们修改电机最高转速的DragValue滑动速度,因为该值较大,所以使用.speed(200)来让其滑动时值的变化更快。
该段代码如下:

impl eframe::App for MyEguiApp {
   fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
        egui::SidePanel::left("LeftBar").show(ctx,|ui|{
            ui.add(egui::DragValue::new(&mut self.P).prefix("最大功率:").suffix("kW").clamp_range(0.1..=1500.0));
            ui.add(egui::DragValue::new(&mut self.T).prefix("最大扭矩:").suffix("Nm").clamp_range(0.1..=3000.0));
            ui.add(egui::DragValue::new(&mut self.n).prefix("最高转速:").suffix("rpm").clamp_range(0.1..=25000.0).speed(200));
            if ui.button("显示曲线").clicked(){
                self.image_show=true;
            }
            if ui.button("隐藏曲线").clicked(){
                self.image_show=false;
            }
        });
        egui::CentralPanel::default().show(ctx, |ui| {
            if self.image_show==true{
                plot_characteristic(&self,ui);
            }
        });
   }
}

编译运行后界面如下:
image
现在我们能够实时地修改数据,然后立即显示更改后的图线了。

posted @ 2024-02-05 19:01  AbsalomT  阅读(760)  评论(0编辑  收藏  举报