egui是库 将输入根据回调计算成图形
epi是库 后端的库
eframe是框架 将上面两个封装整合
居中
ui.vertical_centered(|ui| {
});
分割线
ui.separator();
复选框
ui.checkbox(show, "Perspect");
大字标头/小标签
ui.heading("Camera");
ui.small("Camera");
按钮
if ui.button("Record").clicked() {
}
保留按下状态的按钮
if ui.selectable_label(checked, "Record").clicked() {
}
水平放置
ui.horizontal(|ui| {
});
ui.add(egui::Slider::new(value, 0.0..=10.0).text("value"));
折叠
ui.collapsing("Click to see what is hidden!", |ui| {
});
frame边框
ui.group(|ui| {
});
滚动区
egui::ScrollArea::auto_sized().show(ui, |ui| {
});
egui::ComboBox::from_label("Take your pick")
.selected_text(format!("{}", radio))
.show_ui(ui, |ui| {
ui.selectable_value(radio, "First".to_owned(), "First");
ui.selectable_value(radio, "Second".to_owned(), "Second");
});
侧标栏
egui::SidePanel::left("side_panel").show(ctx, |ui| {
};
use native_dialog::{FileDialog, MessageDialog, MessageType};
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar:
egui::menu::bar(ui, |ui| {
egui::menu::menu(ui, "File", |ui| {
if ui.button("Open").clicked() {
let path = FileDialog::new()
.set_location("~/Desktop")
.add_filter("PNG Image", &["png"])
.add_filter("JPEG Image", &["jpg", "jpeg"])
.show_open_single_file()
.unwrap();
println!("{:?}", path);
}
if ui.button("Save").clicked() {
}
if ui.button("Save As").clicked() {
}
if ui.button("Quit").clicked() {
frame.quit();
}
});
egui::menu::menu(ui, "Help", |ui| {
if ui.button("About").clicked() {
MessageDialog::new()
.set_type(MessageType::Info)
.set_title("Do you want to open the file?")
.set_text("Path")
.show_alert()
.unwrap();
}
});
});
});
带状态的UI Widget
//! 创建使用 egui::Memory 存储UI状态的 widget
/// 密码输入框能切换字符是否隐藏
pub fn password_ui(ui: &mut egui::Ui, text: &mut String) -> egui::Response {
// 这个 widget 有自己的状态 — 显示或隐藏密码的字符
// 1. 声明状态的struct
// 此 struct 表示 widget 的状态.
// 必须实现 Clone 和 'static
#[derive(Clone, Copy, Default)]
struct State(bool);
// 2. 创建 id
let id = ui.id().with("show_password");
// 3. 获取此widget的状态
// 可以在 egui::Memory 和 egui::any 了解更多的内存函数
// 应该使用值来获取状态,而非引用以避免内存的借用
let mut plaintext = *ui.memory().id_data_temp.get_or_default::<State>(id);
// 4. 处理UI, 改变状态的局部副本
// 为了右侧放一个按钮后,文本域填充剩下的空间,从右到左布局
let result = ui.with_layout(egui::Layout::right_to_left(), |ui| {
// 这是使用能被用户改变的状态副本
let response = ui
.add(egui::SelectableLabel::new(plaintext.0, "👁"))
.on_hover_text("Show/hide password");
if response.clicked() {
plaintext.0 = !plaintext.0;
}
let text_edit_size = ui.available_size();
// 这里使用局部状态
ui.add_sized(
text_edit_size,
egui::TextEdit::singleline(text).password(!plaintext.0),
);
});
// 5. 保存改变的状态
ui.memory().id_data_temp.insert(id, plaintext);
result.response
}
新建一个内部窗口
egui::Window::new("Window").show(ctx, |ui| {
});
顶栏(常用作菜单栏)
底栏(常用作通知栏)
egui::TopBottomPanel::top("my_panel").show(ctx, |ui| {
});
egui::TopBottomPanel::bottom("my_panel").show(ctx, |ui| {
});
拖入文件
// Collect dropped files:
if !ctx.input().raw.dropped_files.is_empty() {
let dropped_files: Vec<egui::DroppedFile> = ctx.input().raw.dropped_files.clone();
}
i18n
fn setup(
&mut self,
ctx: &egui::CtxRef,
_frame: &mut epi::Frame<'_>,
storage: Option<&dyn epi::Storage>,
) {
let mut fonts = FontDefinitions::default();
fonts.font_data.insert("my_font".to_owned(),
std::borrow::Cow::Borrowed(include_bytes!("../font/SourceHanSans-Normal.otf"))); // .ttf and .otf supported
fonts.fonts_for_family.get_mut(
&FontFamily::Proportional).unwrap().push("my_font".to_owned()
);
ctx.set_fonts(fonts);
}
改变光标形状
ui.output().cursor_icon = CursorIcon::Grab;
egui::Response::dragged 鼠标左键按下
egui::Response::clicked 鼠标左键抬起
请求重绘,即使是在reactive模式,也会刷新
ui.ctx().request_repaint();