• 【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>,
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    • 我们可以使用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);
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      结果如下
      在这里插入图片描述

    绝对定位

    • 虽然我们绘制出了一个矩形,但是它显示的位置却有些奇怪,这是因为我们使用的是绝对定位
    • 我们使用矩形的左上、右下两个点来确定该矩形,如下图(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);
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      在这里插入图片描述
    • 在转换后,我们的矩形为:
      在这里插入图片描述

    拖拽

    • 在添加矩形后,我们可以对其进行拖拽:
      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);
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      在这里插入图片描述
      但是好像拖不动,这是因为每次update的时候,我们定义的矩形位置都是固定的:
      let mut body_rect = egui::Rect::from_min_size(
              egui::Pos2 { x: 10.0, y: 100.0 },
              egui::vec2(100.0, 200.0),
          );
      
      • 1
      • 2
      • 3
      • 4
      因此我们需要记下上一次的位置:
      pub struct TemplateApp {
      	// ..
          // pos
          #[serde(skip)]
          rect_pos: egui::Pos2,
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      然后在创建矩形的时候使用上一次的位置:
      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);
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      在这里插入图片描述

    参考

  • 相关阅读:
    Android 10.0后创建文件
    Linux Cgroup 系列:CentOS 7 Systemd Cgroup 层级
    CV目标检测模型小抄(2)
    【python入门专项练习】-N02.字符串
    防抖(debounce)和节流(throttle)
    SpringCloud Alibaba 整合Sentinel的基本使用
    宝塔Nginx配置反向代理后如何配置跨域?
    MySQL时间差函数 TimeStampDiff 怎么用
    【正点原子Linux连载】第二十五章 语音识别项目 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2
    C语言的基本概念
  • 原文地址:https://blog.csdn.net/qq_33446100/article/details/132778862