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);
}
});
}
}
编译运行后界面如下:
现在我们能够实时地修改数据,然后立即显示更改后的图线了。