GtkDrawingArea - как сделать его рисованным? - PullRequest
4 голосов
/ 22 февраля 2012

Я немного схожу с ума здесь.

Я пытаюсь нарисовать простую графику в моей форме GTK, используя cairo.

#include <stdio.h>
#include <gtk/gtk.h>
#include <cairo.h>

GtkWidget* window;
GtkWidget* darea; 


int main(int argc, char **argv)
{
    gtk_init(&argc, &argv);     
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 390, 240);

    darea = gtk_drawing_area_new();
    gtk_container_add(GTK_CONTAINER(window), darea); 

    cairo_t *cr; 
    cr = gdk_cairo_create(darea->window);
    cairo_rectangle(cr, 0, 0, 100, 100); 
    cairo_fill(cr);


    gtk_widget_show_all(window);

    gtk_main(); 

    return 0;
}

Это компилируется, но дает мне

Gdk-CRITICAL **: IA__gdk_cairo_create: утверждение `GDK_IS_DRAWABLE (отрисовка) 'не удалось

с последующим сегфоутом.

Я смотрел учебник здесь

Поэтому я изменил свой код следующим образом, чтобы вызовы cairo происходили внутри события expose.

    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <cairo.h>

    GtkWidget* window;
    GtkWidget* darea; 

    static gboolean
    on_expose_event(GtkWidget *widget,
        GdkEventExpose *event,
        gpointer data)
    {
        cairo_t *cr; 
        cr = gdk_cairo_create(darea->window);
        cairo_rectangle(cr, 0, 0, 100, 100); 
        cairo_fill(cr);

    }    

    int main(int argc, char **argv)
    {
        gtk_init(&argc, &argv);     
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        gtk_window_set_default_size(GTK_WINDOW(window), 390, 240);

        darea = gtk_drawing_area_new();
        gtk_container_add(GTK_CONTAINER(window), darea); 

        g_signal_connect(darea, "expose-event",
          G_CALLBACK(on_expose_event), NULL);


        gtk_widget_show_all(window);

        gtk_main(); 

        return 0;
    }

Почему это исправляет? Мое понимание: разоблачение: Символ

g_signal_connect(darea, "expose-event", G_GCALLBACK(on_expose_event), NULL); 

сообщает программе: «когда событие expose происходит с darea, тогда вызовите on_expose_event». Нулевое значение - это место, где вы можете передать указатель на структуру дополнительной информации, которую должна использовать функция.

и

    static gboolean
    on_expose_event(GtkWidget *widget,
        GdkEventExpose *event,
        gpointer data)
    {

означает, что on_expose_event передается указатель на виджет, с которым произошло событие, и в этом случае, потому что это событие expose, указатель на структуру, содержащую информацию о событии expose, и указатель на структуру на любую другую информацию Вы можете добавить.

Ответы [ 2 ]

9 голосов
/ 22 февраля 2012

Рисование на виджете только в Каире работает в событии разоблачения.Это потому, что Каир не похож на программу векторного рисования, где линии и фигуры являются объектами, которые запоминаются и которыми можно манипулировать;Каир просто рисует фигуры в области рисования и забывает о них.

Поэтому, когда вы минимизируете и восстанавливаете свое окно или перемещаете поверх него другое окно, фигуры исчезают.Событие expose генерируется, чтобы сообщить вам, что формы исчезли, и виджет должен быть перерисован.Итак, вы делаете перерисовку с помощью Cairo в обработчике события expose.

2 голосов
/ 22 февраля 2012

Предупреждение и последующий сбой в вашем первом коде из-за того, что darea->window равно NULL, т.е. GdkWindow (darea->window) еще не было создано в той точке программы, когда вы вызываете gdk_cairo_create.GdkWindow для области рисования создается после того, как виджет области рисования реализован .Попробуйте добавить gtk_widget_realize(darea); перед звонком gdk_cairo_create.Кроме того, вместо прямого доступа к window, могу ли я предложить использовать функцию доступа gtk_widget_get_window.
Причину, по которой она не подтверждена и вылетает при добавлении того же кода в expose-eventобратный вызов вызван тем, что GdkWindow, связанный с областью рисования, уже создан в тот момент выполнения программы.

Редактировать:
Приведенная выше причина: только , чтобы объяснить, почему код не сбой в обратном вызове expose-event и почему вызов gdk_cairo_createне утверждал, когда программа была запущена.Считайте приведенный выше ответ просто объяснением, связанным с падением.Пожалуйста, обратитесь к ответу ptomato для получения подробной информации о механизме рисования

Надеюсь, это поможет!

...