draw信号触发时如何保留Gtk::DrawingArea的Cairo绘图内容
解决GTK DrawingArea绘制内容丢失的问题
这问题我太熟了!本质是GTK的DrawingArea每次触发draw信号时,都会给你一个全新的Cairo上下文,默认不会保留之前的绘制内容——所以你每次queue_draw()后,之前画的东西就没了,还会露出主题的灰色背景。
解决的核心思路是自己维护一个离线的Cairo Surface,把所有绘制操作都先画到这个离线surface上,每次draw信号触发时,只需要把这个离线surface完整复制到窗口的上下文里就行。下面是具体的实现步骤:
1. 添加离线Surface成员变量
在你的Gtk::DrawingArea子类里,加一个成员变量用来保存离线绘制内容:
class MyDrawingArea : public Gtk::DrawingArea { private: Cairo::RefPtr<Cairo::Surface> m_offscreen_surface; // 其他成员和方法... };
2. 初始化离线Surface
我们需要在窗口大小确定/变化时,创建和窗口尺寸匹配的离线Surface,同时初始化白色背景。可以通过on_size_allocate信号来处理:
void MyDrawingArea::on_size_allocate(Gtk::Allocation& allocation) { // 先调用父类的默认处理逻辑 Gtk::DrawingArea::on_size_allocate(allocation); auto window = get_window(); if (window) { // 创建和窗口同类型、同尺寸的离线Surface m_offscreen_surface = window->create_similar_surface( Cairo::CONTENT_COLOR_ALPHA, allocation.get_width(), allocation.get_height() ); // 初始化Surface为白色背景,避免一开始就显示主题灰色 auto cr = Cairo::Context::create(m_offscreen_surface); cr->set_source_rgb(1.0, 1.0, 1.0); // 白色 cr->paint(); } }
3. 在鼠标事件中绘制到离线Surface
比如处理鼠标点击事件,在离线Surface上画方块,之后触发重绘:
bool MyDrawingArea::on_button_press_event(GdkEventButton* event) { // 只处理左键点击,且离线Surface已初始化 if (event->button == GDK_BUTTON_PRIMARY && m_offscreen_surface) { auto cr = Cairo::Context::create(m_offscreen_surface); // 在鼠标位置画一个10x10的黑色方块(中心对齐鼠标) cr->set_source_rgb(0.0, 0.0, 0.0); cr->rectangle(event->x - 5, event->y - 5, 10, 10); cr->fill(); queue_draw(); // 触发draw信号,把离线Surface画到窗口 return true; // 标记事件已处理 } // 其他情况交给父类处理 return Gtk::DrawingArea::on_button_press_event(event); }
4. 处理draw信号,复制离线Surface到窗口
最后在on_draw方法里,只需要把离线Surface完整绘制到当前上下文即可:
bool MyDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { if (m_offscreen_surface) { // 将离线Surface设置为绘制源,然后填充整个上下文 cr->set_source(m_offscreen_surface, 0, 0); cr->paint(); } return true; }
关键说明
- 为什么之前的方法不行?因为你直接在
draw的上下文里绘制,每次draw都会重置上下文,之前的内容自然就没了;而离线Surface是持久化的,所有绘制操作都存在这里,每次重绘只是把它“复制”到窗口上。 - 窗口大小变化时必须重新创建离线Surface,不然会出现内容拉伸或空白的问题,
on_size_allocate是处理这个场景的最佳时机。
内容的提问来源于stack exchange,提问作者SuperPrower
相关产品推荐
相关产品推荐

