如何让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()只负责把离屏表面的内容复制到屏幕上下文,无需处理具体绘制逻辑
代码示例
- 在类中添加离屏表面成员变量:
class drawing_test : public Gtk::DrawingArea { private: Cairo::RefPtr<Cairo::ImageSurface> m_offscreen_surface; // 其他成员变量... };
- 初始化/更新离屏表面(在尺寸变化时触发):
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(); }
- 增量绘制的触发函数(比如外部调用添加线条/文本):
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(); }
- 简化后的
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
相关产品推荐
相关产品推荐

