GTK   ダイアログ

ホーム   C/C++チュートリアル


ダイアログ


この章では、各種ダイアログを説明します。

メッセージダイアログ

messagedialog.c


#include <gtk/gtk.h>

void show_info();
void show_warn();
void show_ques();
void show_erro();

int main(int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *grid;
    
    GtkWidget *info;
    GtkWidget *warn;
    GtkWidget *ques;
    GtkWidget *erro;
    
    gtk_init(&argc, &argv);
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "Message dialogs");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    gtk_container_set_border_width  (GTK_CONTAINER(window), 15);
    
    grid    = gtk_grid_new          ();
    gtk_grid_set_row_spacing        (GTK_GRID(grid), 15);
    gtk_grid_set_column_spacing     (GTK_GRID(grid), 15);
    gtk_grid_set_row_homogeneous    (GTK_GRID(grid), TRUE);
    gtk_grid_set_column_homogeneous (GTK_GRID(grid), TRUE);
    gtk_container_add               (GTK_CONTAINER(window), grid);
    
    info    = gtk_button_new_with_label
                                    ("Info");
    warn    = gtk_button_new_with_label
                                    ("Warning");
    ques    = gtk_button_new_with_label
                                    ("Question");
    erro    = gtk_button_new_with_label
                                    ("Error");
    gtk_grid_attach                 (GTK_GRID(grid), info, 0, 0, 1, 1);
    gtk_grid_attach                 (GTK_GRID(grid), warn, 1, 0, 1, 1);
    gtk_grid_attach                 (GTK_GRID(grid), ques, 0, 1, 1, 1);
    gtk_grid_attach                 (GTK_GRID(grid), erro, 1, 1, 1, 1);
    
    g_signal_connect                (info,      "clicked",
                                     G_CALLBACK(show_info), window);
    g_signal_connect                (warn,      "clicked",
                                     G_CALLBACK(show_warn), window);
    g_signal_connect                (ques,      "clicked",
                                     G_CALLBACK(show_ques), window);
    g_signal_connect                (erro,      "clicked",
                                     G_CALLBACK(show_erro), window);
    g_signal_connect                (window,    "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void show_info(GtkWidget *widget, gpointer window)
{
    GtkWidget *dialog;
    dialog  = gtk_message_dialog_new(GTK_WINDOW(window),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_INFO,
                                     GTK_BUTTONS_OK,
                                     "Download Completed");
    gtk_window_set_title            (GTK_WINDOW(dialog),
                                     "Information");
    gtk_dialog_run                  (GTK_DIALOG(dialog));
    gtk_widget_destroy              (dialog);
}

void show_warn(GtkWidget *widget, gpointer window)
{
    GtkWidget *dialog;
    dialog  = gtk_message_dialog_new(GTK_WINDOW(window),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_WARNING,
                                     GTK_BUTTONS_OK,
                                     "Unallowed operation");
    gtk_window_set_title            (GTK_WINDOW(dialog),
                                     "Warning");
    gtk_dialog_run                  (GTK_DIALOG(dialog));
    gtk_widget_destroy              (dialog);
}

void show_ques(GtkWidget *widget, gpointer window)
{
    GtkWidget *dialog;
    dialog  = gtk_message_dialog_new(GTK_WINDOW(window),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_QUESTION,
                                     GTK_BUTTONS_YES_NO,
                                     "Are you sure to quit?");
    gtk_window_set_title            (GTK_WINDOW(dialog),
                                     "Question");
    gtk_dialog_run                  (GTK_DIALOG(dialog));
    gtk_widget_destroy              (dialog);
}

void show_erro(GtkWidget *widget, gpointer window)
{
    GtkWidget *dialog;
    dialog  = gtk_message_dialog_new(GTK_WINDOW(window),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_ERROR,
                                     GTK_BUTTONS_OK,
                                     "Error loading file");
    gtk_window_set_title            (GTK_WINDOW(dialog),
                                     "Error");
    gtk_dialog_run                  (GTK_DIALOG(dialog));
    gtk_widget_destroy              (dialog);
}
    

実行結果

コード説明

  1. void show_info();
    GTKでは、プロトタイプ(関数前方宣言)に引数を記述しなくても大丈夫みたいです。 もしコンパイル時にエラーや警告がある場合は引数を記述してください。
  2. grid = gtk_grid_new();
    今回はグリッド(Grid)というコンテナーを使います。 グリッドはテーブル(Table)と同じくウィジェットをマス目状に配置します。 テーブルは現在非推奨(Deprecated)になっています。
  3. gtk_grid_set_row_spacing(GTK_GRID(grid), 15);
    この関数は、第1引数のグリッドに配置するウィジェット間の縦の空間(Space)を、 第2引数で指定します。
  4. gtk_grid_set_column_spacing(GTK_GRID(grid), 15);
    この関数は、第1引数のグリッドに配置するウィジェット間の横の空白(space)を 第2引数で指定します。
  5. gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
    この関数は、第1引数のグリッドに配置するウィジェットの縦のサイズを同じにするかを 第2引数のTRUEかFALSEで指定します。 この関数を使うことによってグリッド内のウィジェットは縦一杯に広がるようになります。
  6. gtk_grid_set_column_homogeneous (GTK_GRID(grid), TRUE);
    この関数は、第1引数のグリッドに配置するウィジェットの横のサイズを同じにするかを 第2引数のTRUEかFALSEで指定します。 この関数を使うことによってグリッド内のウィジェットは横一杯に広がることになります。
  7. gtk_grid_attach(GTK_GRID(grid), info, 0, 0, 1, 1);
    この関数でグリッドにウィジェットを配置します。引数は次の通りです。
    1. 第1引数にグリッドを指定します
    2. 第2引数に配置するウィジェットを指定します
    3. 第3引数に配置するウィジェットの横位置を列番号で指定します。 列番号は 0 から始まっています
    4. 第4引数に配置するウィジェットの縦位置を行番号で指定します。 行番号は 0 から始まっています
    5. 第5引数に配置するウィジェットの横サイズをマス数で指定します
    6. 第5引数に配置するウィジェットの縦サイズをマス数で指定します
  8. dialog = gtk_message_dialog_new関数でメッセージダイアログを作ります。 引数は次のとおりです。
    1. 第1引数に親ウィンドウを指定します。親ウィンドウを指定すると、 メッセージダイアログが親ウィンドウの上に表示されます。
      親ウィンドウを指定しない場合は NULL を指定します。
    2. 第2引数にダイアログの表示状態を定数で指定します。 用意されている定数は3つありますが、 実際にはどれを指定してもあまり変わりはありません。
      用意されている定数は次のとおりです。
      • GTK_DIALOG_MODAL
      • GTK_DIALOG_DESTROY_WITH_PARENT
      • GTK_DIALOG_USE_HEADER_BAR
    3. 第3引数にメッセージダイアログの種類を定数で指定します
    4. 第4引数にメッセージダイアログに表示されるボタンの種類を指定します。
    5. 第5引数にメッセージダイアログに表示される文字列を指定します
  9. gtk_window_set_title(GTK_WINDOW(dialog),"Question");
    メッセージダイアログのタイトルを設定しています。 メッセージダイアログもウィンドウの一種類だと見なされています。
  10. gtk_dialog_run(GTK_DIALOG(dialog));
    この関数で、引数で指定したダイアログを表示させます。 プログラムは、ダイアログのボタンが押されるか、ダイアログを閉じられるまでは、 ここで処理が止まります。
    そして、メッセージダイアログはボタンが押されて閉じられる時に、 押されたボタンの種類を整数として返します。
  11. <>gtk_widget_destroy(dialog);
    メッセージダイアログを閉じると、目には見えなくなりますが、 その実体はまだ存在しています。
    gtk_widget_destroy関数でダイアログを破棄して、 メッセージダイアログに割り当てられていたメモリーを解放します。


フォントダイアログ

fontdialog.c


#include <gtk/gtk.h>

GtkWidget   *window;
void        select_font();

int main(int argc, char *argv[])
{
    GtkWidget *vbox;   
    GtkWidget *menubar;
    GtkWidget *editmenu;
    GtkWidget *editmenuitem;
    GtkWidget *fontmenuitem;
    GtkWidget *label;
    
    gtk_init(&argc, &argv);
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window), 
                                     "Font dialog");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    
    vbox    = gtk_box_new           (GTK_ORIENTATION_VERTICAL, 0); // 1
    gtk_container_add               (GTK_CONTAINER(window), vbox);
    
    menubar = gtk_menu_bar_new      ();
    editmenu
            = gtk_menu_new          ();
    editmenuitem
            = gtk_menu_item_new_with_label("Edit");
    fontmenuitem
            = gtk_menu_item_new_with_label("Font");
    
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),
                                     editmenuitem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(editmenuitem),
                                     editmenu);
    gtk_menu_shell_append           (GTK_MENU_SHELL(editmenu),
                                     fontmenuitem);
    
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
                        /* 第3引数と第4引数の 0 は、FALSE という意味です */
    
    label   = gtk_label_new         ("GTK Font dialog");
    gtk_label_set_justify           (GTK_LABEL(label),
                                     GTK_JUSTIFY_CENTER);
                                     
    gtk_box_pack_end                (GTK_BOX(vbox), label, 1, 0, 0);
                /* 第3引数の 1 はTRUE、第4引数の 0 はFALSEという意味です */
    
    g_signal_connect                (fontmenuitem,  "activate",
                                     G_CALLBACK(select_font),   label);
    
    g_signal_connect                (window,        "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void select_font(GtkWidget *widget, gpointer label)
{
    GtkWidget               *dialog;
    gint                    result;
    GtkCssProvider          *provider;
    PangoFontDescription    *desc;
    const char              *family;
    gint                    size;
    PangoStyle              style;
    PangoWeight             weight;
    GtkStyleContext         *context;
    
    
    dialog  = gtk_font_chooser_dialog_new
                                    ("Select Font",
                                     GTK_WINDOW(window));
    
    result  = gtk_dialog_run        (GTK_DIALOG(dialog));
    if (result == GTK_RESPONSE_OK || result == GTK_RESPONSE_APPLY)
    /* GTK_RESPONSE_OKには-5、GTK_RESPONS_APPLEには-10が定義済されています*/
    {
        provider    = gtk_css_provider_new();
        desc        = gtk_font_chooser_get_font_desc
                                    (GTK_FONT_CHOOSER(dialog));
        
        family      = pango_font_description_get_family(desc);
        size        = pango_font_description_get_size(desc)/1000;
        weight      = pango_font_description_get_weight(desc);
        style       = pango_font_description_get_style(desc);
                
        gchar *str  = g_strdup_printf
                    ("window label {font-family: \"%s\";\
                                    font-size: %dpx;\
                                    font-weight: %d;\
                                    font-style: %s;}",
                                    family, size, weight,
                                    style ? "italic" : "normal");
        
        gtk_css_provider_load_from_data(provider,str, -1, NULL);
        context     = gtk_widget_get_style_context(label);
        gtk_style_context_add_provider(context,
                                       GTK_STYLE_PROVIDER(provider),
                                       GTK_STYLE_PROVIDER_PRIORITY_USER
                                       );
        
        g_free                      (str);
    }
    gtk_widget_destroy(dialog);
}
    

実行結果

コード説明

  1. GtkWidget *window;
    g_signal_connect関数では、イベントハンドラーに2つの引数しか渡せないので ウィンドウをグローバル変数にしました。
  2. void select_font();
    GTKでは、プロトタイプ(関数前方宣言)に引数を記述しなくても大丈夫みたいです。 もしコンパイルできないようでしたらプロトタイプに引数を記述してください。
  3. gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_CENTER);
    このコードによってラベルの文字が常に中央に表示されるようになると思います。
  4. GtkCssProvider *provider;
    GTK3ではフォントの設定にCssProviderを使うことになりました。
  5. PangoFontDescription *desc;
    フォントの詳細が記述されているものはPangoFontDescription型になります。
  6. PangoStyle style;
    PangoWeight weight;
    この二つはともに整数の列挙体です。
  7. dialog = gtk_font_chooser_dialog_new( )
    フォントダイアログを作っています。第1引数にダイアログのタイトルを、 第2引数に親ウィンドウを指定します。
  8. result = gtk_dialog_run(GTK_DIALOG(dialog));
    ダイアログを表示しています。引数にダイアログを指定します。 ダイアログのボタンが押されるまで処理が止まります。
    ボタンが押されてダイアログが閉じると、どのボタンが押されたかを 表す整数が返されます。
  9. provider = gtk_css_provider_new();
    GtkCssProviderを作っています。引数はありません。
  10. desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER(dialog));
    フォントダイアログで選ばれたフォントの、詳細が記述されたフォントデスクリプション (font description)を取得しています。
  11. family = pango_font_description_get_family(desc);
    フォントデスクリプションからフォントの名前を取得しています。
  12. size = pango_font_description_get_size(desc)/1000;
    フォントデスクリプションからフォントのサイズを取得しています。1 ピクセルが 1000 という単位になっていますので、1000 で割っています。
  13. weight = pango_font_description_get_weight(desc);
    フォントデスクリプションからフォントの太さを取得しています。
  14. style = pango_font_description_get_style(desc);
    フォントデスクリプションからフォントのスタイル(ノーマル、斜体)を取得しています。
  15. gchar *str = g_strdup_printf( );
    g_strdup_printf関数でCSSの文字列を作ります。
    "window label {font-family: \"%s\";\ ラベルはwindow labelになります。font-family:のあとに"と"で囲んで フォント名を指定します。文字列引数内で改行する場合は\が必要です。
    font-size: %dpx;\ font-size:のあとにフォントのサイズを指定します。サイズのあとにpx が必要です。
    font-weight: %d;\ font-weight:のあとにフォントの太さを指定します。PangoWeight型は もともと整数値です。
    font-style: %s;}", font-style:の あとにフォントのスタイルを表す、nomal、oblique、italic のどれかの文字列を指定します。
    style ? "italic" : "normal"); これは三項演算子と呼ばれるものです。?の前の式がTRUEなら :の前の式が実行され、FALSEなら:の後ろの式が実行されます。
    styleにはNormalの場合0が、Obliqueの場合1が、Italicの場合2 が入っています。0はFALSEと評価されますので"normal"が返されます。
    1と2の場合には"italic"が返されます。 フォントデスクリプションではObliqueとItalicはともに2と評価されます。
  16. gtk_css_provider_load_from_data(provider,str, -1, NULL);
    CssPrroviderにデータを読み込んでいます。引数は次のとおりです。
    1. 第1引数にCssProviderを指定します
    2. 第2引数にCSS文字列を指定します
    3. 第3引数に第2引数がヌル終了文字列の場合は-1を指定します
    4. 第4引数にエラーの場所を指定します。特にない場合はNULLを指定します
  17. context = gtk_widget_get_style_context(label);
    ラベルのコンテキスト(ウィジェットの詳細が記述されているもの)を取得しています。
  18. gtk_style_context_add_provider( )
    ラベルのコンテキストにCssProviderを追加しています。引数は次のとおりです。
    1. 第1引数にプロバイダーを追加したいウィジェットのコンテキストを指定します
    2. 第2引数に追加するプロバイダーを指定します
    3. 第3引数にプロバイダーの優先順位を1から800の間で指定するそうです。 値には次の定数があります
      GTK_STYLE_PROVIDER_PRIORITY_FALLBACK1
      GTK_STYLE_PROVIDER_PRIORITY_THEME200
      GTK_STYLE_PROVIDER_PRIORITY_SETTINGS400
      GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600
      GTK_STYLE_PROVIDER_PRIORITY_USER800
  19. g_free(str);
    str 文字列を破棄しています。変数は関数が終了する時に自動的に破棄されます。 しかし文字列の場合は、文字列ポインターは破棄されますが
    その実際の値が入っているメモリー部分は破棄されません。g_free( )関数を使うと その実際の値が入っているメモリー部分が破棄されてメモリーが解放されます。


fontdialog2.c


#include <gtk/gtk.h>

GtkWidget   *window;
void        select_font();

int main(int argc, char *argv[])
{
    GtkWidget *vbox;   
    GtkWidget *toolbar;
    GtkToolItem *font;
    GtkWidget *label;
    
    gtk_init(&argc, &argv);
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window), 
                                     "Font dialog");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    //gtk_container_set_border_width  (GTK_CONTAINER(window), 15);
    
    vbox    = gtk_box_new           (GTK_ORIENTATION_VERTICAL, 0); // 1
    gtk_container_add               (GTK_CONTAINER(window), vbox);
    
    toolbar = gtk_toolbar_new       ();
    gtk_toolbar_set_style           (GTK_TOOLBAR(toolbar),
                                     GTK_TOOLBAR_ICONS);
    font    = gtk_tool_button_new_from_stock
                                    (GTK_STOCK_SELECT_FONT);
    gtk_toolbar_insert              (GTK_TOOLBAR(toolbar), font, -1);
    gtk_box_pack_start              (GTK_BOX(vbox), toolbar, 0, 0, 0);
                        /* 第3引数と第4引数の 0 は、FALSE という意味です */
    
    label   = gtk_label_new         ("GTK Font dialog");
    gtk_label_set_justify           (GTK_LABEL(label),
                                     GTK_JUSTIFY_CENTER);
    gtk_box_pack_end                (GTK_BOX(vbox), label, 1, 0, 0);
                /* 第3引数の 1 はTRUE、第4引数の 0 はFALSEという意味です */
    
    g_signal_connect                (font,          "clicked",
                                     G_CALLBACK(select_font),   label);
    
    g_signal_connect                (window,        "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void select_font(GtkWidget *widget, gpointer label)
{
    GtkWidget               *dialog;
    gint                    result;
    gchar                   *fontname;
    PangoFontDescription    *fontdesc;
    
    dialog  = gtk_font_chooser_dialog_new
                                    ("Select Font",
                                     GTK_WINDOW(window));
    result  = gtk_dialog_run        (GTK_DIALOG(dialog));
    if (result == GTK_RESPONSE_OK || result == GTK_RESPONSE_APPLY)
    /* GTK_RESPONSE_OKには-5、GTK_RESPONS_APPLEには-10が定義済されています*/
    {
        fontname    = gtk_font_chooser_get_font
                                    (GTK_FONT_CHOOSER(dialog));
        fontdesc    = pango_font_description_from_string
                                    (fontname);
        gtk_widget_override_font    (GTK_WIDGET(label), fontdesc);
        g_free                      (fontname);
    }
    gtk_widget_destroy(dialog);
}
	

実行結果

コード説明

  1. GtkWidget *window;
    g_signal_connect関数では、イベントハンドラーに2つの引数しか渡せないので ウィンドウをグローバル変数にしました。
  2. void select_font();
    GTKでは、プロトタイプ(関数前方宣言)に引数を記述しなくても大丈夫みたいです。 もしコンパイルできないようでしたらプロトタイプに引数を記述してください。
  3. gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_CENTER);
    このコードによってラベルの文字が常に中央に表示されるようになると思います。
  4. font = gtk_tool_button_new_from_stock( )
    この関数は現在、非推奨(deprecated)ですが、 代わりの関数はまだ見つかりません。
  5. GTK_STOCK_SELECT_FONT
    GTK_STOCK定数は非推奨(deprecated)ですが、代わりの定数がまだ見つかりません。
  6. PangoFontDescription *fontdesc;
    フォントの詳細が記述されているものをPangoFontDescription型で受けています。
  7. dialog = gtk_font_chooser_dialog_new( )
    この関数でフォントダイアログを作ります。第1引数にダイアログのタイトルを、 第2引数に親ウィンドウを指定します。
  8. result = gtk_dialog_run(GTK_DIALOG(dialog));
    この関数で引数に指定したダイアログを表示して、ダイアログのボタンが押されるまで 処理が止まります。
    ボタンが押されてダイアログが閉じると、どのボタンが押されたかを 表す整数が返されます。
  9. fontname = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
    gtk_font_chooser_get_font( )関数で引数のフォントチューザーダイアログで選択 されたフォントの名前が返されます。
  10. fontdesc = pango_font_description_from_string(fontname);
    pango_font_description_from_string( )関数で、フォント名前から フォントデスクリプションというフォントの詳細が記述されたものを取得します。
  11. gtk_widget_override_font(GTK_WIDGET(label), fontdesc);
    gtk_widget_override_font( )関数で、第1引数のウィジェットのフォントを 第2引数のフォントデスクリプションで設定します。
    この関数は非推奨(deprecated)ですが、代わりの関数はまだ見つかりません。
  12. g_free(fontname);
    fontname文字列を破棄しています。変数は関数が終了する時に自動的に破棄されます。 しかし文字列の場合は、文字列ポインターは破棄されますが
    その実際の値が入っているメモリー部分は破棄されません。g_free( )関数を使うと その実際の値が入っているメモリー部分が破棄されてメモリーが解放されます。


カラーダイアログ

colordialog.c


#include <gtk/gtk.h>

GdkRGBA     color;

void        select_color();
void        draw_callback();
void        select_color();

int main(int argc, char *argv[])
{
    GtkWidget   *window;
    GtkWidget   *vbox;
    GtkWidget   *menubar;
    GtkWidget   *editmenu;
    GtkWidget   *editmenuitem;
    GtkWidget   *colormenuitem;
    GtkWidget   *darea;
    GtkWidget   *frame;
    
    gtk_init(&argc, &argv);
    
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "Color dialog");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    
    vbox    = gtk_box_new           (GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add               (GTK_CONTAINER(window), vbox);
    
    menubar = gtk_menu_bar_new      ();
    
    editmenu
            = gtk_menu_new          ();
    editmenuitem
            = gtk_menu_item_new_with_label("Edit");
    colormenuitem
            = gtk_menu_item_new_with_label("Color");
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),
                                     editmenuitem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(editmenuitem),
                                     editmenu);
    gtk_menu_shell_append           (GTK_MENU_SHELL(editmenu),
                                     colormenuitem);
    
    darea   = gtk_drawing_area_new  ();
    frame   = gtk_frame_new         (NULL);
    gtk_container_set_border_width  (GTK_CONTAINER(frame), 15);
    gtk_container_add               (GTK_CONTAINER(frame), darea);
    gtk_box_pack_end                (GTK_BOX(vbox), frame, 1, 1, 0);
    /* 第3引数と第4引数の 1 は、TRUE の意味です。第5引数は数値の 0 です */
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
    /* 第3引数と第4引数の 0 は、FALSEの意味です。第5引数は数値の 0 です */
    
    gdk_rgba_parse                  (&color ,"rgb(127, 127, 127)");
    
    g_signal_connect                (darea,         "draw",
                                     G_CALLBACK(draw_callback), NULL);
    
    g_signal_connect                (colormenuitem, "activate",
                                     G_CALLBACK(select_color), window);
    
    g_signal_connect                (window,        "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void    draw_callback(GtkWidget *darea, cairo_t *cr)
{
    gdk_cairo_set_source_rgba       (cr, &color);
    cairo_paint                     (cr);
}

void    select_color(GtkWidget *widget, gpointer window)
{
    GtkWidget   *dialog;
    gint        result;
    
    dialog  = gtk_color_chooser_dialog_new
                                    ("Select color",
                                     GTK_WINDOW(window));
    
    result = gtk_dialog_run         (GTK_DIALOG(dialog));
    //printf("%d\n", GTK_RESPONSE_OK);
    if (result == GTK_RESPONSE_OK)
    {
        gtk_color_chooser_get_rgba  (GTK_COLOR_CHOOSER(dialog),
                                     &color);
        gtk_widget_queue_draw       (window);
    }
    gtk_widget_destroy              (dialog);
}
    

実行結果

コード説明

  1. GdkRGBA color;
    最新のGTK3では、GdkRGBAが色を保存する型です。今回はグローバル変数にしました。
  2. void select_color();
    GTK3では、プロトタイプ(関数前方宣言)に引数を記述しなくても良いみたいです。 もし、コンパイルできないようでしたら、引数を記述してください。
  3. darea = gtk_drawing_area_new ();
    DrawingAreaというウィジェットを作っています。ドローイングエリアは図形など描く 土台として使われます。
  4. gdk_rgba_parse(&color ,"rgb(127, 127, 127)");
    この関数で色を作ります。引数は次のとおりです。
    1. 第1引数にGdkRGBA型変数のアドレスを指定します
    2. 第2引数に色を表す文字列を指定します。次の2種類の文字列が使えます。
      • "#f0f"、"#ff00ff"
      • "rgb(255, 0, 255)"、数値には 0 から 255 までが指定できます
  5. g_signal_connect(darea, "draw",
    ドローイングエリアは、ドローイングエリアが再描画されるタイミングで、"draw" イベントシグナルを発します。
  6. void draw_callback(GtkWidget *darea, cairo_t *cr)
    ドローイングエリアの "draw" イベントシグナルと接続したイベントハンドラーには、 自動的に、ドローイングエリアとカイロ(cairo_t *型)が引数として渡されます。
    ドローイングエリアは図形などを描く土台ですが、カイロは実際に図形などを描く システムです。
  7. gdk_cairo_set_source_rgba(cr, &color);
    この関数でカイロの現在の色を設定します。
    1. 第1引数にカイロを指定します
    2. 第2引数に色を保存した GdkRGBA 型変数のアドレスを渡します
  8. cairo_paint(cr);
    この関数で、ドローイングエリア全体に、現在の色を塗ります。 引数にカイロを指定します。
  9. void select_color(GtkWidget *widget, gpointer window)
    カラーツールボタンがクリックされた時のイベントハンドラーには、第1引数に自動的に イベントシグナルを発したツールボタンが渡されます。
    そして第2引数には、g_signal_connect( )関数の第4引数が渡されます。
  10. dialog = gtk_color_chooser_dialog_new
    この関数で色選択ダイアログを作ります。
    1. 第1引数にダイアログのタイトルを文字列で指定します
    2. 第2引数に親ウィンドウを指定します
  11. result = gtk_dialog_run(GTK_DIALOG(dialog));
    この関数は、引数で指定したダイアログを表示します。 この関数が呼び出されるとダイアログを閉じるまでは、処理がここで止まります。
    この関数は、ダイアログで押されたボタンを表す整数を返します。
  12. if (result == GTK_RESPONSE_OK)
    OKボタンが押された場合に返される整数は -5 です。 GTK_RESPONSE_OK定数には -5 が定義されています。
  13. gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
    この関数でカラー選択ダイアログで選択した色を GdkRGBA 型変数に代入します。
    1. 第1引数にカラー選択ダイアログを指定します
    2. 第2引数に色を保存する GdkRGBA 型変数のアドレスを渡します
  14. gtk_widget_queue_draw(window);
    この関数は、引数で指定したウィジェットを再描画します。
    ウィンドウを再描画すれば、その中のドローイングエリアも再描画され "draw" イベントシグナルに接続したイベントハンドラーが呼ばれます。
  15. gtk_widget_destroy(dialog);
    ダイアログは閉じただけでは、目に見えなくなるだけで、 メモリー上には存在しています。
    この関数は引数で指定したウィジェット(この場合はダイアログ)を メモリー上から破棄して、そのメモリー領域を解放します。


colordialog2.c


#include <gtk/gtk.h>

GdkRGBA     color;

void        select_color();
void        draw_callback();
void        select_color();

int main(int argc, char *argv[])
{
    GtkWidget   *window;
    GtkWidget   *vbox;
    GtkWidget   *toolbar;
    GtkToolItem *coloritem;
    GtkWidget   *darea;
    GtkWidget   *frame;
    
    gtk_init(&argc, &argv);
    
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "Color dialog");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    
    vbox    = gtk_box_new           (GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add               (GTK_CONTAINER(window), vbox);
    
    toolbar = gtk_toolbar_new       ();
    gtk_box_pack_start              (GTK_BOX(vbox), toolbar, 0, 0, 0);
    /* 第3引数と第4引数の 0 は、FALSEの意味です。第5引数は数値の 0 です */
    
    coloritem
            = gtk_tool_button_new_from_stock
                                    (GTK_STOCK_SELECT_COLOR);
    /*この関数とGTK_STOCK定数は非推奨(deprecated)です。実行に問題はありません*/
    
    gtk_toolbar_insert              (GTK_TOOLBAR(toolbar), coloritem,
                                     -1);
    
    darea   = gtk_drawing_area_new  ();
    frame   = gtk_frame_new         (NULL);
    gtk_container_set_border_width  (GTK_CONTAINER(frame), 15);
    gtk_container_add               (GTK_CONTAINER(frame), darea);
    gtk_box_pack_end                (GTK_BOX(vbox), frame, 1, 1, 0);
    /* 第3引数と第4引数の 1 は、TRUE の意味です。第5引数は数値の 0 です */
    
    gdk_rgba_parse                  (&color ,"rgb(127, 127, 127)");
    
    g_signal_connect                (darea,         "draw",
                                     G_CALLBACK(draw_callback), NULL);
    
    g_signal_connect                (coloritem,     "clicked",
                                     G_CALLBACK(select_color), window);
    
    g_signal_connect                (window,        "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void    draw_callback(GtkWidget *darea, cairo_t *cr)
{
    gdk_cairo_set_source_rgba       (cr, &color);
    cairo_paint                     (cr);
}

void    select_color(GtkWidget *widget, gpointer window)
{
    GtkWidget   *dialog;
    gint        result;
    
    dialog  = gtk_color_chooser_dialog_new
                                    ("Select color",
                                     GTK_WINDOW(window));
    
    result = gtk_dialog_run         (GTK_DIALOG(dialog));
    if (result == GTK_RESPONSE_OK)
    {
        gtk_color_chooser_get_rgba  (GTK_COLOR_CHOOSER(dialog),
                                     &color);
        gtk_widget_queue_draw       (window);
    }
    gtk_widget_destroy              (dialog);
}
	

実行結果


ファイルダイアログ

filedialog.c


#include <gtk/gtk.h>

GtkWidget   *label;
void        select_file();

int main(int argc, char *argv[])
{
    GtkWidget   *window;
    GtkWidget   *vbox;
    GtkWidget   *menubar;
    GtkWidget   *filemenu;
    GtkWidget   *filemenuitem;
    GtkWidget   *openmenuitem;
    
    gtk_init(&argc, &argv);
    
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "File dialog");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    
    vbox    = gtk_box_new           (1, 0); // 1
    /* GTK_ORIENTATION_VERTICAL定数の値は 1 です */
    gtk_container_add               (GTK_CONTAINER(window), vbox);
    
    menubar = gtk_menu_bar_new      ();
    filemenu
            = gtk_menu_new          ();
            
    filemenuitem
            = gtk_menu_item_new_with_label("File");
    openmenuitem
            = gtk_menu_item_new_with_label("Open");
    
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),
                                     filemenuitem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(filemenuitem),
                                     filemenu);
    gtk_menu_shell_append           (GTK_MENU_SHELL(filemenu),
                                     openmenuitem);
    
    label   = gtk_label_new         ("未選択");
    gtk_label_set_justify           (GTK_LABEL(label),
                                     GTK_JUSTIFY_CENTER);   // 2
    
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
    gtk_box_pack_end                (GTK_BOX(vbox), label,   1, 0, 0);
    /* 第3引数と第4引数の0はFALSE、1はTRUEの意味です。第5引数は数値の0です */
    
    g_signal_connect                (openmenuitem,  "activate",
                                     G_CALLBACK(select_file), window);
    
    g_signal_connect                (window,        "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void    select_file(GtkWidget *widget, gpointer window)
{
    GtkWidget   *dialog;
    gint        result;
    
    dialog  = gtk_file_chooser_dialog_new
                                    ("Select File",
                                     window,
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
    /* 保存ダイアログの場合は、GTK_FILE_CHOOSER_ACTION_SAVE にします */
                                     ("Cancel"),
                                     GTK_RESPONSE_CANCEL,
                                     ("Select"),
                                     GTK_RESPONSE_ACCEPT,
                                     NULL);
    
    result  = gtk_dialog_run        (GTK_DIALOG(dialog));
    
    if (result == GTK_RESPONSE_ACCEPT)
    /* GTK_RESPONSE_ACCEPT定数は -3 です */
    {
        char *filename;
        GtkFileChooser *chooser
            = GTK_FILE_CHOOSER(dialog);
        filename
            = gtk_file_chooser_get_filename
                                    (chooser);
        
        gtk_label_set_text          (GTK_LABEL(label), filename);
        g_free                      (filename);
    } else {
        gtk_label_set_text          (GTK_LABEL(label), "未選択");
    }
    gtk_widget_destroy              (dialog);
}
    

実行結果

コード説明

  1. GtkWidget *label;
    ラベルをグローバル変数にしました。
  2. void select_file();
    GTK3では、プロトタイプ(関数前方宣言)の引数の記述を省略できるみたいです。 もし、コンパイルでエラーになるようなら、引数を記述してください。
  3. gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
    この関数を使うと、ラベルの文字列が中央寄せになるみたいです。
  4. gtk_file_chooser_dialog_new
    この関数でファイル選択ダイアログを作ります。引数は次のとおりです。
    1. 第1引数にダイアログのタイトルを文字列で指定します
    2. 第2引数に親ウィンドウを指定します
    3. 第3引数にオープンダイアログにするかセーブダイアログにするか指定します
      • GTK_FILE_CHOOSER_ACTION_OPEN にすると、ファイルを開くダイアログになります
      • GTK_FILE_CHOOSER_ACTION_SAVE にすると、ファイル保存ダイアログになります
    4. 第4引数にボタンの名前を("文字列")の形で指定します
    5. 第5引数にキャンセルかアクセプトかの定数を指定します
      • キャンセルの場合は、GTK_RESPONSE_CANCELを指定します
      • アクセプト(Accept、承認)の場合は、GTK_RESPONSE_ACCEPTを指定します
    6. 第6引数に次のボタンの名前を指定します
    7. 第7引数にキャンセルかアクセプトかの定数を指定します
    8. 第8引数はNULLにしていますが、可変長引数になっていますので、 おそらく拡張子フィルターなどを設定できるのではないかと思います
  5. GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
    GtkFileChooser 型ポインターに、 ファイル選択ダイアログのポインターを代入します。
  6. filename = gtk_file_chooser_get_filename(chooser);
    この関数でファイル選択ダイアログが選択したファイルのパスを取得できます。
  7. g_free (filename);
    filenameを書き込んだメモリー部分を破棄して、メモリーを解放しています。
  8. gtk_widget_destroy(dialog);
    ダイアログを格納したメモリー部分を破棄して、メモリーを解放しています。


filedialog2.c


#include <gtk/gtk.h>

GtkWidget   *label;
void        select_file();

int main(int argc, char *argv[])
{
    GtkWidget   *window;
    GtkWidget   *vbox;
    GtkWidget   *toolbar;
    GtkToolItem *fileitem;
    
    gtk_init(&argc, &argv);
    
    window  = gtk_window_new        (GTK_WINDOW_TOPLEVEL);  // 0
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "File dialog");
    gtk_window_set_default_size     (GTK_WINDOW(window), 320, 240);
    gtk_window_set_position         (GTK_WINDOW(window),
                                     GTK_WIN_POS_CENTER);   // 1
    
    vbox    = gtk_box_new           (GTK_ORIENTATION_VERTICAL, 0); // 1
    gtk_container_add               (GTK_CONTAINER(window), vbox);
    
    toolbar = gtk_toolbar_new       ();
    gtk_box_pack_start              (GTK_BOX(vbox), toolbar, 0, 0, 0);
    /* 第3引数と第4引数の 0 は、FALSEの意味です。第5引数は数値の 0 です */
    
    fileitem
            = gtk_tool_button_new_from_stock
                                    (GTK_STOCK_FILE);
    /*この関数とGTK_STOCK定数は非推奨(deprecated)です。実行に問題はありません*/
    /*macOSでは、GTK_STOCK_FILEは読み込めません                         */
    
    gtk_toolbar_insert              (GTK_TOOLBAR(toolbar), fileitem,
                                     -1);
    
    label   = gtk_label_new         ("未選択");
    gtk_label_set_justify           (GTK_LABEL(label),
                                     GTK_JUSTIFY_CENTER);   // 2
    
    gtk_box_pack_end                (GTK_BOX(vbox), label, 1, 0, 0);
    /*第3引数の 1 はTRUE、第4引数の 0 はFALSE、第5引数は数値の0という意味です*/
    
    g_signal_connect                (fileitem,      "clicked",
                                     G_CALLBACK(select_file), window);
    
    g_signal_connect                (window,        "destroy",
                                     G_CALLBACK(gtk_main_quit), NULL);
    
    gtk_widget_show_all             (window);
    gtk_main                        ();
    return                          0;
}

void    select_file(GtkWidget *widget, gpointer window)
{
    GtkWidget   *dialog;
    gint        result;
    
    dialog  = gtk_file_chooser_dialog_new
                                    ("Select File",
                                     window,
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
    /* 保存ダイアログの場合は、GTK_FILE_CHOOSER_ACTION_SAVE にします */
                                     ("Cancel"),
                                     GTK_RESPONSE_CANCEL,
                                     ("Select"),
                                     GTK_RESPONSE_ACCEPT,
                                     NULL);
    
    result  = gtk_dialog_run        (GTK_DIALOG(dialog));
    
    if (result == GTK_RESPONSE_ACCEPT)
    /* GTK_RESPONSE_ACCEPT定数は -3 です */
    {
        char *filename;
        GtkFileChooser *chooser
            = GTK_FILE_CHOOSER(dialog);
        filename
            = gtk_file_chooser_get_filename
                                    (chooser);
        
        gtk_label_set_text          (GTK_LABEL(label), filename);
        g_free                      (filename);
    } else {
        gtk_label_set_text          (GTK_LABEL(label), "未選択");
    }
    gtk_widget_destroy              (dialog);
}
    

実行結果



73080 visits
Posted: Dec. 22, 2019
Update: Jan. 01, 2020

ホーム   C/C++チュートリアル   目次