【rust/egui】(九)使用painter绘制一些图形—基本使用

说在前面

  • rust新手,egui没啥找到啥教程,这里自己记录下学习过程
  • 环境:windows11 22H2
  • rust版本:rustc 1.71.1
  • egui版本:0.22.0
  • eframe版本:0.22.0
  • 上一篇:这里

painter

  • 定义
    pub struct Painter {
        /// Source of fonts and destination of shapes
        ctx: Context,
    
        /// Where we paint
        layer_id: LayerId,
    
        /// Everything painted in this [`Painter`] will be clipped against this.
        /// This means nothing outside of this rectangle will be visible on screen.
        clip_rect: Rect,
    
        /// If set, all shapes will have their colors modified to be closer to this.
        /// This is used to implement grayed out interfaces.
        fade_to_color: Option<Color32>,
    }
    
  • 我们可以使用painter来添加一个简单的矩形:
    egui::CentralPanel::default().show(ctx, |ui| {
    	// 从ui中指定一块区域
        let response =
        ui.allocate_rect(ui.available_rect_before_wrap(), egui::Sense::hover());
    	// 添加一个空Shape
        let shape = ui.painter().add(egui::Shape::Noop);
    	// 定义圆角大小
        let rounding = egui::Rounding::same(4.0);
        // 定义要绘制的矩形大小及位置
        let body_rect = egui::Rect::from_min_size(egui::pos2(10.0, 100.0), egui::vec2(100.0, 200.0));
        // 添加一个矩形
        let body = egui::Shape::Rect(egui::epaint::RectShape {
            rect: body_rect,
            rounding: rounding,
            fill: color_from_hex("#3f3f3f").unwrap(),
            stroke: egui::Stroke::NONE,
        });
    	// 绘制
        ui.painter().set(shape, body);
    });
    
    结果如下
    在这里插入图片描述

绝对定位

  • 虽然我们绘制出了一个矩形,但是它显示的位置却有些奇怪,这是因为我们使用的是绝对定位
  • 我们使用矩形的左上、右下两个点来确定该矩形,如下图(10,100)、(110,300),其宽100高200:
    在这里插入图片描述
  • 如果想要在我们的CentralPanel中绘制,需要进行转换:
    egui::CentralPanel::default().show(ctx, |ui| {
        let response = ui.allocate_rect(ui.available_rect_before_wrap(), egui::Sense::hover());
    	// 定义转换
        let to_screen = egui::emath::RectTransform::from_to(
            egui::Rect::from_min_size(egui::Pos2::ZERO, response.rect.size()),
            response.rect,
        );
    
        let shape = ui.painter().add(egui::Shape::Noop);
    
        let rounding_radius = 4.0;
        let rounding = egui::Rounding::same(rounding_radius);
        let mut body_rect =
            egui::Rect::from_min_size(egui::pos2(10.0, 100.0), egui::vec2(100.0, 200.0));
    
        // 进行转换
        body_rect = to_screen.transform_rect(body_rect);
        let body = egui::Shape::Rect(egui::epaint::RectShape {
            rect: body_rect,
            rounding: rounding,
            fill: color_from_hex("#3f3f3f").unwrap(),
            stroke: egui::Stroke::NONE,
        });
    
        ui.painter().set(shape, body);
    });
    
    在这里插入图片描述
  • 在转换后,我们的矩形为:
    在这里插入图片描述

拖拽

  • 在添加矩形后,我们可以对其进行拖拽:
    egui::CentralPanel::default().show(ctx, |ui| {
        let response = ui.allocate_rect(ui.max_rect(), egui::Sense::hover());
        let to_screen = egui::emath::RectTransform::from_to(
            egui::Rect::from_min_size(egui::Pos2::ZERO, response.rect.size()),
            response.rect,
        );
        let shape = ui.painter().add(egui::Shape::Noop);
        let rounding_radius = 4.0;
        let rounding = egui::Rounding::same(rounding_radius);
        let mut body_rect = egui::Rect::from_min_size(
            egui::Pos2 { x: 10.0, y: 100.0 },
            egui::vec2(100.0, 200.0),
        );
        body_rect = to_screen.transform_rect(body_rect);
        // 添加拖拽事件
        let window_response = ui.interact(
            body_rect,
            egui::Id::new((1, "window")),
            egui::Sense::click_and_drag(),
        );
        // 计算拖拽偏移量
        let drag_delta = window_response.drag_delta();
        if drag_delta.length_sq() > 0.0 {
        	// 移动矩形
            body_rect = body_rect.translate(drag_delta);
        }
        let body = egui::Shape::Rect(egui::epaint::RectShape {
            rect: body_rect,
            rounding: rounding,
            fill: color_from_hex("#3f3f3f").unwrap(),
            stroke: egui::Stroke::NONE,
        });
        ui.painter().set(shape, body);
    });
    
    在这里插入图片描述
    但是好像拖不动,这是因为每次update的时候,我们定义的矩形位置都是固定的:
    let mut body_rect = egui::Rect::from_min_size(
            egui::Pos2 { x: 10.0, y: 100.0 },
            egui::vec2(100.0, 200.0),
        );
    
    因此我们需要记下上一次的位置:
    pub struct TemplateApp {
    	// ..
        // pos
        #[serde(skip)]
        rect_pos: egui::Pos2,
    }
    
    然后在创建矩形的时候使用上一次的位置:
    egui::CentralPanel::default().show(ctx, |ui| {
        let response = ui.allocate_rect(ui.max_rect(), egui::Sense::hover());
        let to_screen = egui::emath::RectTransform::from_to(
            egui::Rect::from_min_size(egui::Pos2::ZERO, response.rect.size()),
            response.rect,
        );
        let shape = ui.painter().add(egui::Shape::Noop);
        let rounding_radius = 4.0;
        let rounding = egui::Rounding::same(rounding_radius);
        let mut body_rect = egui::Rect::from_min_size(
            self.rect_pos,
            egui::vec2(100.0, 200.0),
        );
        body_rect = to_screen.transform_rect(body_rect);
        // 添加拖拽事件
        let window_response = ui.interact(
            body_rect,
            egui::Id::new((1, "window")),
            egui::Sense::click_and_drag(),
        );
        // 计算拖拽偏移量
        let drag_delta = window_response.drag_delta();
        if drag_delta.length_sq() > 0.0 {
        	// 移动矩形
            body_rect = body_rect.translate(drag_delta);
            // 改变初始位置
            self.rect_pos = self.rect_pos + drag_delta;
        }
        let body = egui::Shape::Rect(egui::epaint::RectShape {
            rect: body_rect,
            rounding: rounding,
            fill: color_from_hex("#3f3f3f").unwrap(),
            stroke: egui::Stroke::NONE,
        });
        ui.painter().set(shape, body);
    });
    
    在这里插入图片描述

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rust的async/await是一种异步编程模式,可以在代码中使用关键字async和await来创建和等待异步任务。 以下是使用async/await的基本步骤: 1. 在函数签名中添加async关键字,表示该函数是一个异步函数。 2. 在函数体内使用await关键字等待异步任务的结果。await关键字会暂停当前函数的执行,直到异步任务完成并返回结果。 3. 在异步函数内部,可以使用异步API来创建和启动异步任务。 例如,下面是一个简单的使用async/await的例子: ```rust async fn do_something_async() -> String { // 创建一个异步任务,等待1秒后返回结果 let result = tokio::time::delay_for(Duration::from_secs(1)).await; // 返回一个字符串 return "Hello, World!".to_string(); } fn main() { // 创建一个异步运行时 let rt = tokio::runtime::Runtime::new().unwrap(); // 在异步运行时中执行异步函数 let result = rt.block_on(async { // 等待异步任务完成并返回结果 let result = do_something_async().await; // 返回异步任务的结果 return result; }); // 输出结果 println!("{}", result); } ``` 在这个例子中,我们首先定义了一个异步函数do_something_async(),它创建了一个异步任务,等待1秒后返回一个字符串。然后,在main函数中,我们创建了一个异步运行时,并使用block_on函数在异步运行时中执行异步函数do_something_async(),并等待它的结果。最后,我们输出异步任务的结果。 需要注意的是,Rust的async/await需要配合异步运行时一起使用,例如上述例子中使用的tokio运行时。异步运行时提供了异步任务的执行环境和调度器,负责管理异步任务的执行和调度。因此,在使用async/await时需要选择一个合适的异步运行时,并将异步函数放入异步运行时中执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值