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

如何让Gtk::DrawingArea实现增量式绘制?

Gtk::DrawingArea 增量绘制实现方案

问题说明

不想每次调用on_draw()时重绘全部内容,希望实现增量式修改(叠加线条、矩形、文本等),无需手动跟踪已绘制的所有元素。当前代码通过cmd分支执行不同绘制操作,但无法保留之前的绘制结果:

bool drawing_test::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{    
  switch (cmd)
  {
    case 0: /* 初始化背景 */
      cr->set_source_rgba(1, 1, 1, 1);  // 白色
      cr->paint();
      break;
    case 1: /* 绘制线条 */
      DrawLine(cr, params);
      break;
    case 2: /* 绘制文本 */
      DrawText(cr, params);
      break;
    default:
      break;
  }
}

你考虑用Cairo::Context的get_target()和set_source()保存/加载状态的思路方向对,但直接操作on_draw()的上下文行不通,下面是正确的实现方案:

正确实现思路

核心是用离屏表面(Offscreen Surface)作为持久绘制缓存:

  • 自己创建一个独立的离屏表面,用来保存所有已绘制的内容
  • 每次需要增量绘制时,直接在这个离屏表面的上下文中添加内容
  • on_draw()只负责把离屏表面的内容复制到屏幕上下文,无需处理具体绘制逻辑

代码示例

  1. 在类中添加离屏表面成员变量:
class drawing_test : public Gtk::DrawingArea
{
private:
  Cairo::RefPtr<Cairo::ImageSurface> m_offscreen_surface;
  // 其他成员变量...
};
  1. 初始化/更新离屏表面(在尺寸变化时触发):
void drawing_test::on_size_allocate(Gtk::Allocation& allocation)
{
  Gtk::DrawingArea::on_size_allocate(allocation);
  
  int width = allocation.get_width();
  int height = allocation.get_height();
  
  // 创建或更新适配控件尺寸的离屏表面
  m_offscreen_surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
  auto cr = Cairo::Context::create(m_offscreen_surface);
  
  // 初始化白色背景
  cr->set_source_rgba(1, 1, 1, 1);
  cr->paint();
}
  1. 增量绘制的触发函数(比如外部调用添加线条/文本):
void drawing_test::add_line(const LineParams& params)
{
  if (!m_offscreen_surface) return;
  
  auto cr = Cairo::Context::create(m_offscreen_surface);
  DrawLine(cr, params);
  
  // 触发重绘,让on_draw()渲染最新缓存内容
  queue_draw();
}

void drawing_test::add_text(const TextParams& params)
{
  if (!m_offscreen_surface) return;
  
  auto cr = Cairo::Context::create(m_offscreen_surface);
  DrawText(cr, params);
  
  queue_draw();
}
  1. 简化后的on_draw():
bool drawing_test::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
  if (m_offscreen_surface)
  {
    // 将离屏缓存的内容复制到当前屏幕上下文
    cr->set_source(m_offscreen_surface, 0, 0);
    cr->paint();
  }
  
  return true;
}

为什么不直接用get_target()?

get_target()获取的是on_draw()的临时目标表面,这个表面会在每次重绘时被系统清空,无法持久保存绘制内容。而自己创建的离屏表面是独立的,所有增量绘制都会保存在这里,on_draw()只做缓存内容的屏幕渲染,完全符合你“无需跟踪已绘制内容,只需叠加”的需求。

内容的提问来源于stack exchange,提问作者WeirdGuy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 12:03:14