我正在开发实时绘图应用程序,其中数据流要在屏幕上绘制。早些时候使用gtkmm2,我使用自定义小部件(派生自Gtk::Bin
(完成了此操作,其中我有一个成员函数来创建开罗上下文并进行绘图。
现在使用gtkmm3我无法以除on_draw
以外的任何方法绘制.这是我的自定义绘制方法主体的外观
Gtk::Allocation oAllocation = get_allocation();
Glib::RefPtr <Gdk::Window> refWindow = get_window();
Cairo::RefPtr <Cairo::Context> refContext =
refWindow->create_cairo_context();
refWindow->begin_paint_rect(oAllocation); //added later
refContext->save();
refContext->reset_clip();
refContext->set_source_rgba(1,
1,
1,
1);
refContext->move_to(oAllocation.get_x(),
oAllocation.get_y());
refContext->line_to(oAllocation.get_x()
+ oAllocation.get_width(),
oAllocation.get_y()
+ oAllocation.get_height());
refContext->stroke();
refContext->restore();
refWindow->end_paint();
最初,我从Gtk::DrawingArea
派生了类,然后在添加begin_paint_rect
调用时尝试使用Gtk::Bin
。
禁止在on_draw
以外的任何地方绘画吗?
对于情节之类的东西(或任何绘制起来相当复杂的东西(,我建议使用缓冲区;我失去了一个月的生命,因为我读到 gtkmm3 进行缓冲,因此不再需要使用"双缓冲"(与 gtkmm2 相反(,但它很简单(阅读:这不是真的(。
所以,你应该做的是画到你自己的表面;每次你改变一些东西时,都叫queue_draw_region
或queue_draw_area
。
然后在on_draw
获取剪辑矩形的列表,并将其从专用图面复制到传递给on_draw
函数的cr
。开罗通常这样做 完全相同的东西(或者他们声称(,将您刚刚再次复制的内容复制到屏幕上;所以你应该关闭它(我读到这应该是可能的(。
你不能使用Cairo的缓冲的原因是因为它不保留该缓冲区;你得到的是一些损坏的表面,所以你被迫重新绘制剪辑矩形列表中的所有内容。如果您(您的应用程序(是唯一进行更改的人(根据您的 queue_draw_* 调用(,那也不会太糟糕:然后您可以设置一个标志,使需要重绘的部分无效,并简单地推迟绘制直到您到达on_draw
。但有时出于其他原因调用on_draw
,例如,当您打开超出绘图区域的菜单时。我认为这是一个错误(或设计错误(,但事实就是如此。结果是,除非查看剪辑矩形列表,否则您无法知道必须重绘的内容;这使得只绘制区域的一部分变得非常困难,除非您的绘图由许多单独的矩形(例如棋盘(组成。唯一可行的方法是在内存(您的私有表面(中保留图像的完整副本,并在on_draw
时从那里复制剪辑矩形列表。
禁止在on_draw以外的任何地方绘画吗?
基本上:是的。
这个想法是,当您想要导致重绘时,您可以调用gtk_widget_queue_draw()
或gtk_widget_queue_draw_area()
。
- https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-queue-draw
- https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-queue-draw-area