如何在调整窗口大小时暂停 GtkDrawingArea 绘制回调?
Posted
技术标签:
【中文标题】如何在调整窗口大小时暂停 GtkDrawingArea 绘制回调?【英文标题】:How can I suspend the GtkDrawingArea draw callbacks while the window is being resized? 【发布时间】:2015-06-22 21:03:13 【问题描述】:我正在开发一个小型 GTK+ 程序,我在其中放置了 GtkDrawingArea
。我用它是为了画一种比较具体的数据表示图,结果还是比较满意的。
问题是:“图形”有很多数据要处理,并且绘制信号的回调被频繁调用。最重要的是,每次将窗口 (GtkWindow
/GtkContainer
) 调整几个像素时都会调用它。为了避免过多地减慢应用程序的速度,我想在调整窗口大小时“暂停”绘制回调。我们可以想象整个区域会同时被一个灰色的矩形覆盖,或者类似的东西......
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
/* A lot of drawing with Cairo
* This is called WAY too often. */
int main(int argc, char* argv[])
GtkBuilder* builder;
GtkWidget *window;
GtkWidget *draw_area;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("myapp.ui");
window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
draw_area = GTK_WIDGET(gtk_builder_get_object(builder, "draw_area"));
g_signal_connect(draw_area, "draw", G_CALLBACK(draw_callback), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
g_object_unref(builder);
gtk_main();
return 0;
注意:调整窗口大小后仍必须执行回调(发生这种情况时需要重新计算一些坐标)。我只是想在 调整窗口大小时避免它。
我的第一个想法是将回调连接到 check-resize
事件,在该事件中可以设置和取消设置布尔值,因为窗口被抓取和释放(同时调整大小):
gboolean resizing = false;
void resize_callback(GtkContainer* container, gpointer data)
/* Set "resizing"...
* Is the window being grabbed? Released? */
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
if(resizing)
/* Draw a gray overlay or something if necessary... */
return true;
/* Draw the actual stuff here... */
int main(int argc, char* argv[])
GtkWidget *window;
GtkWidget *draw_area;
// ...
g_signal_connect(window, "check-resize", G_CALLBACK(resize_callback), NULL);
g_signal_connect(draw_area, "draw", G_CALLBACK(draw_callback), NULL);
// ...
但是这个事件并不适合我,因为它不会在窗口被抓取/释放时触发(仅当它的大小实际改变时)。
有没有办法在窗口被抓取和释放(调整大小)时得到通知?或者在调整窗口大小时是否有更好的方法来暂停/简化对draw_callback
的调用?
【问题讨论】:
【参考方案1】:考虑在鼠标按钮按下时阻止绘制回调。保存回调 id:
draw_callback_id = g_signal_connect(draw_area, "draw",
G_CALLBACK(draw_callback), NULL);
当检测到按键信号时,做
g_signal_handler_block(draw_area, draw_callback_id);
当然,在按钮释放事件之后:
g_signal_handler_block(draw_area, draw_callback_id);
然后您可以手动触发重绘事件。要优化,可以使用gtk_widget_queue_draw_region()
调用,它只重绘指定的矩形。
另一种可能性(虽然我没有尝试过)可能是在调整大小或移动时仅绘制窗口边框。窗口管理器 (XFCE) 有这个选项,但我还没有看到如何从 GTK 内部做到这一点。
【讨论】:
以上是关于如何在调整窗口大小时暂停 GtkDrawingArea 绘制回调?的主要内容,如果未能解决你的问题,请参考以下文章
在 Tailwind 中调整窗口大小时如何避免 div 混乱?