2012-02-22 30 views
3

私はここで少し気になりません。GtkDrawingArea - 描画可能にするにはどうすればいいですか?

私はカイロを使用して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 (描画可能)」がセグメンテーション違反が続く

に失敗しました。私は 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、イベントはに起こったことをウィジェットへのポインタが渡されることを公開するイベントに関する情報を含む構造体へのポインタを意味し、追加したい他の情報へのポインタへのポインタ。あなたがgdk_cairo_createを呼び出すとき

答えて

8

カイロを使用したウィジェットでの描画は公開イベントでのみ動作します。これは、カイロは、線や形が記憶され操作可能なオブジェクトであるベクター描画プログラムのようなものではないためです。カイロはその図形を描画領域に塗りつぶして、それらを忘れてしまいます。

ウィンドウを最小化して復元したり、別のウィンドウを上に移動すると、図形が消えます。シェイプがなくなり、ウィジェットを再描画する必要があることを知らせるエクスポーズイベントが生成されます。そこで、あなたはexposeイベントハンドラでカイロを使って再描画を行います。

+1

私たちのフォームには2つのボタンがあり、1つは描画エリアに赤い円を描画し、もう1つは青い四角形を描きます。 これを行う方法です - 各ボタンクリックイベントは 'mode'変数を変更し、gtk_widget_queue_draw()を呼び出し、expose_eventsはモードが何であるかによって描画するものを決定します。 サンプルコード:http://pastebin.com/7ZvwcCXb – dwjohnston

+1

はい、それは私に聞こえます。 – ptomato

+0

昔は何かをダブルバッファーにするか、アンダーを使って設定することができましたが、それは何とかGTKで可能です。ウィンドウをピクスマップにコピーして、必要に応じてコピーすることもできます。しかし、XLibとMotifで何かを描き、それを覆い隠すと、私の描くものは元に戻りません。 –

2

警告し、あなたの最初のコードでは、結果としてクラッシュが原因darea->windowはすなわちGdkWindowdarea->windowNULLであるという事実であるが、プログラムでの時点でまだ作成されていません。描画領域ウィジェットがで実現されると、描画領域用の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_は、公開イベントで動作します。 – ptomato

+0

@ptomato:あなたは描画について正しいです。私は応答の言葉を台無しにしたと思う。私はコードがハンドラに追加されたときにクラッシュが発生しなかった理由を説明しようとしていました。そして、ウィジェットが実現されると、タイムハンドラによって 'GdkWindow'が作成されます。それに応じて回答を更新します。ありがとうございます –

+0

あまりにも更新していただきありがとうございます!私は-1を+1に変えました。 – ptomato

関連する問題