2012-02-22 4 views
3

나는 내 마음에서 조금 벗어날거야.GtkDrawingArea - 드로어 블 (Drawable) 만드는 법?

카이로를 사용하여 GTK 양식에 간단한 그래픽을 그리려는 중입니다. IA__gdk_cairo_create :

#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 ** 컴파일하지만 나에게주는 주장`GDK_IS_DRAWABLE (당김) '는 segfault의 다음

에 실패했습니다. 나는 tutorial here

에서 찾고 있었어요

그래서 다음과 같이, 내 코드를 변경 한 카이로의 호출이 노출 이벤트 내부에서 발생했다.

#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); 

프로그램을 알려줍니다 '는 다음, 이벤트가 darea에 어떻게 노출 on_expose_event 호출 할 때'. null은 사용할 함수에 대한 추가 정보의 구조체에 대한 포인터를 전달할 수있는 곳입니다.

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

는 on_expose_event가가 노출 이벤트는 노출 이벤트에 대한 정보를 포함하는 구조체에 대한 포인터이기 때문에이 경우 andin, 이벤트가 일어난 위젯에 대한 포인터를 전달하고 있음을 의미 추가하고자하는 다른 정보의 구조체에 대한 포인터.

답변

8

카이로로 위젯에 그리기 은 expose 이벤트에서 작동합니다. 그 이유는 카이로가 벡터 그리기 프로그램과 같지 않기 때문입니다. 선과 모양은 기억되어 조작 할 수있는 개체이기 때문입니다. 카이로는 모양을 그림 영역에 칠하고 그 그림을 잊어 버립니다.

그래서 창을 최소화하고 복원하거나 다른 창 위로 이동하면 모양이 사라집니다. 셰이프가 사라지고 위젯을 다시 그려야 함을 알리는 노출 이벤트가 생성됩니다. 그래서 당신은 노출 이벤트 핸들러에서 카이로로 다시 그리기를 수행합니다.

+1

자, 이제 폼에 두 개의 버튼이 있고, 하나는 그림 영역에 빨간색 원을 그리고 다른 하나는 파란색 사각형을 그립니다. 이렇게하는 방법입니다 - 각 버튼 클릭 이벤트는 'mode'변수를 변경하고 gtk_widget_queue_draw()를 호출 한 다음 expose_events가 모드가 무엇인지에 따라 그릴 내용을 결정합니다. 예제 코드 : http://pastebin.com/7ZvwcCXb – dwjohnston

+1

네, 저에게 맞는 것 같습니다. – ptomato

+0

예전에는 더블 버퍼링을 설정하거나 저장 언더 (save unders)를 사용하도록 설정할 수 있었지만, GTK에서는 가능하다고 가정합니다. 창을 픽스맵에 복사 한 다음 필요에 따라 다시 복사 할 수도 있습니다. 그러나 XLib와 Motif에서 무언가를 그렸다면 그 무언가를 숨기고 펼치면 아무 것도 나의 그림을 되 찾을 수 없습니다. –

2

경고와 첫 번째 코드에서 필연적 인 충돌 때문에 darea->window 당신이 gdk_cairo_create를 호출 할 때 NULLGdkWindow (darea->window)이 프로그램의 시점에서 아직 만들어지지 않은 사실이다. 도면 영역 위젯이 실현되면 이 작성되면 도면 영역에 대해 GdkWindow이 작성됩니다. 전화 gdk_cairo_create 앞에 gtk_widget_realize(darea);을 추가하십시오. 또한 window에 직접 액세스하는 대신 액세서 기능 gtk_widget_get_window의 사용을 제안 할 수 있습니다.
expose-event 콜백에 동일한 코드를 추가했을 때 &이 (가) 어설 션되지 않은 이유는 그림 영역과 연관된 GdkWindow이 프로그램 실행 중이 시점에서 이미 생성 되었기 때문입니다.

편집 :
위에 제공된 이유는 코드가 프로그램을 실행할 때 호출 gdk_cairo_create가 주장하지 않은 이유 expose-event 콜백 &에 충돌되지 않은 이유를 단지 설명하는 입니다. 위의 응답을 으로 처리하면 크래시와 관련된 설명으로이 처리됩니다. 드로잉 메커니즘에 대한 자세한 내용은 ptomato's response을 참조하십시오.

희망이 있습니다.

+0

답변의 첫 부분이 정확합니다. 위젯이 실현되지 않으면'darea-> window'는'NULL'입니다. 나머지는 잘못되었습니다 : _only_를 그리는 것은 expose 이벤트에서 작동합니다. – ptomato

+0

@ptomato : 당신은 그림 그리기에 적당합니다. 나는 응답의 문언을 엉망으로 만들었다 고 생각한다. 나는 코드가 핸들러에 추가되었을 때 왜 크래쉬가 발생하지 않았는 지와'GdkWindow' 인 드로어 블이 위젯이 구현 될 때 타임 핸들러에 의해 생성된다는 것을 설명하려고 노력했다. 그에 따라 응답을 업데이트 할 것입니다. 감사합니다. –

+0

업데이트 주셔서 감사합니다. 나는 -1을 +1로 바꿨다. – ptomato