You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中使用egui为自定义坐标的图形实现悬浮提示?

在macroquad+egui中实现圆形顶点的信息展示

核心思路

不用为每个圆形单独写自定义widget,而是在渲染循环里统一处理鼠标交互逻辑,再结合egui的组件来展示信息,这种方式简洁高效,适配大量圆形的场景。


方案一:鼠标悬停显示Tooltip(推荐,直观流畅)

适合字段内容较少的场景,用户无需额外操作就能快速查看信息:

  1. 在macroquad渲染循环中获取鼠标实时位置
  2. 遍历所有圆形实例,通过计算鼠标到圆心的距离判断是否悬停在圆上
  3. 用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会过于冗长,这时点击弹窗更合适:

  1. 检测鼠标左键点击事件,找到被点击的圆形实例
  2. 触发egui弹出窗口,显示该圆形的详细信息
  3. 支持主动关闭窗口,避免遮挡视图
// 沿用上面的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 22:25:22