如何在调整窗口大小时暂停 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 混乱?

如何在窗口调整大小时隐藏 Facebook 聊天框?

调整窗口大小时如何使用鼠标单击获取图像坐标?

在 FabricJS 中调整窗口大小时如何始终将剪切区域居中?

当我调整窗口大小时如何使用滚动

opengl:调整大小时如何将对象保留在窗口中