在绘图信号上保留 DrawingArea 'image'
Preserve DrawingArea 'image' on draw signal
我正在尝试制作简单的正方形,您可以在其中使用鼠标进行绘画。问题是,每当绘制信号发生时,cairo 表面似乎已完全清除。我理解这一点,因为在第一个 queue_draw()
白色背景消失后,我看到了我的 GTK 主题颜色(灰色)。
我以为我可以保存表面或上下文,但你不能只在开罗创建空表面,我不能使用 this->get_window()->create_cairo_surface()
创建它(其中 this
是 class 继承自 Gtk::DrawingArea
) 因为当调用构造函数时,widget 还没有附加到任何 window,所以它是一个空指针。我的意思是,我可以创建一些名为 you_are_added_to_window_create_cairo_surface()
的 public 函数,但我真的不想这样做。
所以我真的不知道该怎么做,我对开罗有什么不了解。
如何保留或保存 'canvas' 当前状态,使实际绘制的内容仅应用于现有绘图?
这是我的回调函数 class:
bool MyDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> & cr) {
/* clear and fill background with white in the beginning */
if (first_draw) {
cr->save();
cr->set_source_rgb(255.0, 255.0, 255.0);
cr->paint();
cr->restore();
first_draw = false;
}
cr->save();
cr->set_source_rgb(0.0, 0.0, 0.0);
cr->begin_new_path();
while (!dots_queue.empty()) {
auto dot = dots_queue.front();
cr->line_to(dot.first, dot.second);
dots_queue.pop();
}
cr->close_path();
cr->stroke();
cr->restore();
return false;
}
删除 first_draw
而不是 dots_queue.pop()
,只需遍历 dots_queue
并每次都重绘它们。
draw
函数不适用于 "I want to add some drawing"。相反,它是 "hey, the windowing system has no idea what should be drawn here, please fill this with content"。这就是开罗表面被清除的原因。
因此,虽然存储所有动作都有效,但如果您试图让程序保存您的绘图,那真的不行,您将不得不使用第二个表面来保存所有内容。
我的解决方案结合了 Uli Schlachter 的两个答案。
首先,我有一个结构,我在其中存储自上次按下按钮到释放按钮的最后一次绘图操作。这让我可以实时显示诸如线条之类的东西,同时保持 canvas 干净。
其次,我将 canvas 上绘制的所有内容存储在一个表面上,它是这样创建的:
// this - is object of class, derived from DrawingArea
auto allocation = this->get_allocation();
this->surface = Cairo::ImageSurface::create(
Cairo::Format::FORMAT_ARGB32,
allocation.get_width(),
allocation.get_height()
);
然后,在每个 draw
信号上,我这样恢复它:
cr->save();
cr->set_source(surface, 0.0, 0.0);
cr->paint();
cr->restore();
每当我想保存表面时,即将绘图应用于 canvas,我会执行以下操作:
Cairo::RefPtr<Cairo::Context> t_context = Cairo::Context::create(surface);
t_context->set_source(cr->get_target(), -allocation.get_x(), -allocation.get_y());
t_context->paint();
重要的时刻到了。如果不调整分配坐标,您的 canvas 将在每次表面保存和恢复时滑开。
有了它,我可以轻松地将绘图保存在 canvas、从文件加载 canvas(因为我使用的是 ImageSurface),或将其保存到文件。
我正在尝试制作简单的正方形,您可以在其中使用鼠标进行绘画。问题是,每当绘制信号发生时,cairo 表面似乎已完全清除。我理解这一点,因为在第一个 queue_draw()
白色背景消失后,我看到了我的 GTK 主题颜色(灰色)。
我以为我可以保存表面或上下文,但你不能只在开罗创建空表面,我不能使用 this->get_window()->create_cairo_surface()
创建它(其中 this
是 class 继承自 Gtk::DrawingArea
) 因为当调用构造函数时,widget 还没有附加到任何 window,所以它是一个空指针。我的意思是,我可以创建一些名为 you_are_added_to_window_create_cairo_surface()
的 public 函数,但我真的不想这样做。
所以我真的不知道该怎么做,我对开罗有什么不了解。
如何保留或保存 'canvas' 当前状态,使实际绘制的内容仅应用于现有绘图?
这是我的回调函数 class:
bool MyDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> & cr) {
/* clear and fill background with white in the beginning */
if (first_draw) {
cr->save();
cr->set_source_rgb(255.0, 255.0, 255.0);
cr->paint();
cr->restore();
first_draw = false;
}
cr->save();
cr->set_source_rgb(0.0, 0.0, 0.0);
cr->begin_new_path();
while (!dots_queue.empty()) {
auto dot = dots_queue.front();
cr->line_to(dot.first, dot.second);
dots_queue.pop();
}
cr->close_path();
cr->stroke();
cr->restore();
return false;
}
删除 first_draw
而不是 dots_queue.pop()
,只需遍历 dots_queue
并每次都重绘它们。
draw
函数不适用于 "I want to add some drawing"。相反,它是 "hey, the windowing system has no idea what should be drawn here, please fill this with content"。这就是开罗表面被清除的原因。
因此,虽然存储所有动作都有效,但如果您试图让程序保存您的绘图,那真的不行,您将不得不使用第二个表面来保存所有内容。
我的解决方案结合了 Uli Schlachter 的两个答案。
首先,我有一个结构,我在其中存储自上次按下按钮到释放按钮的最后一次绘图操作。这让我可以实时显示诸如线条之类的东西,同时保持 canvas 干净。
其次,我将 canvas 上绘制的所有内容存储在一个表面上,它是这样创建的:
// this - is object of class, derived from DrawingArea
auto allocation = this->get_allocation();
this->surface = Cairo::ImageSurface::create(
Cairo::Format::FORMAT_ARGB32,
allocation.get_width(),
allocation.get_height()
);
然后,在每个 draw
信号上,我这样恢复它:
cr->save();
cr->set_source(surface, 0.0, 0.0);
cr->paint();
cr->restore();
每当我想保存表面时,即将绘图应用于 canvas,我会执行以下操作:
Cairo::RefPtr<Cairo::Context> t_context = Cairo::Context::create(surface);
t_context->set_source(cr->get_target(), -allocation.get_x(), -allocation.get_y());
t_context->paint();
重要的时刻到了。如果不调整分配坐标,您的 canvas 将在每次表面保存和恢复时滑开。
有了它,我可以轻松地将绘图保存在 canvas、从文件加载 canvas(因为我使用的是 ImageSurface),或将其保存到文件。