Как я могу приостановить обратные вызовы отрисовки GtkDrawingArea во время изменения размера окна?

Я разрабатываю небольшую программу 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 ответ

Попробуйте заблокировать обратный вызов отрисовки, когда кнопка мыши нажата. Сохраните идентификатор обратного вызова:

draw_callback_id = g_signal_connect(draw_area, "draw",
                                    G_CALLBACK(draw_callback), NULL);

Когда сигнал нажатой кнопки обнаружен, выполните

g_signal_handler_block(draw_area, draw_callback_id);

И, конечно же, после события button-release:

g_signal_handler_block(draw_area, draw_callback_id);

Затем вы можете вручную вызвать событие перерисовки. Для оптимизации вы можете использовать gtk_widget_queue_draw_region() вызов, который перерисовывает только указанный прямоугольник.

Другой возможностью (хотя я не пробовал этого) может быть рисование только границ окна при изменении размера или перемещении. У оконного менеджера (XFCE) есть эта опция, но я не видел, как это сделать изнутри GTK.

Другие вопросы по тегам