我想在Gtk::Layout内使用自定义绘图。也就是说,我正在使用Gtk3(GTKmm 3.14.0
)的C ++绑定,并且我在自定义绘图之上放置了嵌入在“画布”上的小部件。基本上这很好用。
现在问题与滚动有关。 Gtk::Layout
可以放在Gtk::ScrolledWindow
中,当可滚动区域设置为大于可见分配的值时,滚动条将显示出来。不幸的是,这些滚动条仅影响 嵌入式小部件的位置,而我的自定义绘图仍保留在窗口内的固定位置。
这意味着,Gtk::Allocation
和cairo上下文似乎都与精确可见区域相关,而不是与扩展虚拟“画布”相关。我可以通过从滚动条访问调整然后相应地翻译cairo上下文来解决这个问题...
我的问题是:
答案 0 :(得分:1)
根据gtk+3.0-3.14.5
(在Debian / Stable中)的源代码判断,Gtk::Layout
无法调整绘图上下文。它只调用draw()
中继承的GtkWidget
函数。另一方面,Gtk::Layout
是一个完整的容器(它继承自Gtk::Container
),它是可滚动的,这意味着它通过传递合适的分配来处理gtk_layout_size_allocate()
(屏幕区域)到每个嵌入的子窗口小部件 - 在这方面它确实处理与滚动虚拟画布相关的移动和剪切(调用gdk_window_move_resize()
)。
因此,如果我们想要将嵌入式子窗口小部件与自定义绘图结合起来,我们需要手动弥补这种差异。这实际上非常简单:我们需要做的就是查看与滚动条对应的Gtk::Adjusment
。因为这些调整的值恰好是可见视口的左上角。现在,如果我们希望自定义绘图使用绝对画布坐标,我们只需要translate()
给定的Cairo上下文。注意:save()
状态是重要的,restore()
它在完成状态时对原始状态很重要,否则这些翻译将会累积。
以下是一些演示此自定义绘图的示例代码
Canvas
Gtk::Layout
的自定义容器类
on_draw()
处理程序,因为只有已经处理了嵌入式子窗口小部件的所有大小分配Gtk::Layout
容器的顺序绘制。在调用继承的on_draw()
函数之前完成的任何自定义绘图将位于这些小部件之下;之后完成的任何绘图将在它们之上发生。如有必要,我们可以使用foreach(callback)
机制访问所有子窗口小部件,以查找其当前位置和扩展名
void
Canvas::determineExtension()
{
if (not recalcExtension_) return;
uint extH=20, extV=20;
Gtk::Container::ForeachSlot callback
= [&](Gtk::Widget& chld)
{
auto alloc = chld.get_allocation();
uint x = alloc.get_x();
uint y = alloc.get_y();
x += alloc.get_width();
y += alloc.get_height();
extH = max (extH, x);
extV = max (extV, y);
};
foreach(callback);
recalcExtension_ = false;
set_size (extH, extV); // define extension of the virtual canvas
}
bool
Canvas::on_draw(Cairo::RefPtr<Cairo::Context> const& cox)
{
if (shallDraw_)
{
uint extH, extV;
determineExtension();
get_size (extH, extV);
auto adjH = get_hadjustment();
auto adjV = get_vadjustment();
double offH = adjH->get_value();
double offV = adjV->get_value();
cox->save();
cox->translate(-offH, -offV);
// draw red diagonal line
cox->set_source_rgb(0.8, 0.0, 0.0);
cox->set_line_width (10.0);
cox->move_to(0, 0);
cox->line_to(extH, extV);
cox->stroke();
cox->restore();
// cause child widgets to be redrawn
bool event_is_handled = Gtk::Layout::on_draw(cox);
// any drawing which follows happens on top of child widgets...
cox->save();
cox->translate(-offH, -offV);
cox->set_source_rgb(0.2, 0.4, 0.9);
cox->set_line_width (2.0);
cox->rectangle(0,0, extH, extV);
cox->stroke();
cox->restore();
return event_is_handled;
}
else
return Gtk::Layout::on_draw(cox);
}