如何在Rust中使用egui为自定义坐标的图形实现悬浮提示?
在macroquad+egui中实现圆形顶点的信息展示
核心思路
不用为每个圆形单独写自定义widget,而是在渲染循环里统一处理鼠标交互逻辑,再结合egui的组件来展示信息,这种方式简洁高效,适配大量圆形的场景。
方案一:鼠标悬停显示Tooltip(推荐,直观流畅)
适合字段内容较少的场景,用户无需额外操作就能快速查看信息:
- 在macroquad渲染循环中获取鼠标实时位置
- 遍历所有圆形实例,通过计算鼠标到圆心的距离判断是否悬停在圆上
- 用egui在鼠标位置附近绘制悬浮信息框,显示选中圆形的字段内容
// 示例圆形结构体 #[derive(Debug)] struct Circle { x: f32, y: f32, radius: f32, field1: String, field2: i32, // 其他自定义字段 } fn main() { let mut circles: Vec<Circle> = vec![ // 初始化你的圆形实例列表 Circle { x: 100.0, y: 100.0, radius: 20.0, field1: "示例1".to_string(), field2: 10 }, Circle { x: 200.0, y: 200.0, radius: 20.0, field1: "示例2".to_string(), field2: 20 }, ]; let mut hovered_circle: Option<&Circle> = None; loop { clear_background(WHITE); // 绘制所有圆形(macroquad部分) for circle in &circles { // 悬停的圆高亮显示 let color = if hovered_circle.as_ref() == Some(circle) { RED } else { BLUE }; draw_circle(circle.x, circle.y, circle.radius, color); } // 检测鼠标悬停 let (mouse_x, mouse_y) = mouse_position(); hovered_circle = circles.iter().find(|circle| { let dx = mouse_x - circle.x; let dy = mouse_y - circle.y; dx*dx + dy*dy <= circle.radius*circle.radius }); // egui绘制悬浮信息 egui_macroquad::ui(|egui_ctx| { if let Some(circle) = hovered_circle { egui::Area::new("circle_tooltip") .fixed_pos(egui::pos2(mouse_x + 10.0, mouse_y + 10.0)) // 偏移避免遮挡鼠标 .frame(egui::Frame::default().fill(egui::Color32::from_rgb(240,240,240))) .show(egui_ctx, |ui| { ui.label(format!("字段1: {}", circle.field1)); ui.label(format!("字段2: {}", circle.field2)); // 依次添加其他字段 }); } }); egui_macroquad::draw(); next_frame().await; } }
方案二:点击弹出信息窗口(适合信息量大的场景)
如果圆形的字段很多,Tooltip会过于冗长,这时点击弹窗更合适:
- 检测鼠标左键点击事件,找到被点击的圆形实例
- 触发egui弹出窗口,显示该圆形的详细信息
- 支持主动关闭窗口,避免遮挡视图
// 沿用上面的Circle结构体定义 fn main() { let mut circles: Vec<Circle> = vec![/* 初始化实例 */]; let mut selected_circle: Option<&Circle> = None; loop { clear_background(WHITE); // 绘制圆形,点击的圆高亮 for circle in &circles { let color = if selected_circle.as_ref() == Some(circle) { RED } else { BLUE }; draw_circle(circle.x, circle.y, circle.radius, color); } // 检测鼠标点击 if is_mouse_button_pressed(MouseButton::Left) { let (mouse_x, mouse_y) = mouse_position(); selected_circle = circles.iter().find(|circle| { let dx = mouse_x - circle.x; let dy = mouse_y - circle.y; dx*dx + dy*dy <= circle.radius*circle.radius }); } // egui弹出窗口 egui_macroquad::ui(|egui_ctx| { if let Some(circle) = selected_circle { egui::Window::new("圆形详情") .default_size(egui::vec2(220.0, 180.0)) .show(egui_ctx, |ui| { ui.label(format!("字段1: {}", circle.field1)); ui.label(format!("字段2: {}", circle.field2)); // 添加更多字段... if ui.button("关闭").clicked() { selected_circle = None; } }); } }); egui_macroquad::draw(); next_frame().await; } }
优雅性选择
- 若字段少、需要快速浏览:选悬停Tooltip,交互流畅不打断操作
- 若字段多、信息复杂:选点击弹窗,避免信息拥挤,让用户专注查看详情
性能优化(可选)
如果圆形数量极大(上万级),直接遍历会影响性能,可以用**空间划分(比如四叉树)**先筛选出鼠标附近的圆形,再做距离判断,减少遍历次数。
内容的提问来源于stack exchange,提问作者taciturno
相关产品推荐
相关产品推荐

