GTK3   ダイアログ

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


ダイアログ


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

メッセージダイアログ

messagedialog.c


#include 

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


int main(int argc, char **argv)
{
    GtkApplication  *app;
    int             status;
    
    app     =   gtk_application_new ("jp.vivacocoa.messagedialog", 0);
    g_signal_connect                (app,       "activate",
                                     G_CALLBACK( activate),     NULL);
    status  =   g_application_run   (G_APPLICATION(app), argc,  argv);
    g_object_unref                  (app);
    return  status;
}

void activate(GtkApplication *app, gpointer data)
{
    GtkWidget   *window;
    GtkWidget   *grid;
    
    GtkWidget   *info;
    GtkWidget   *warn;
    GtkWidget   *ques;
    GtkWidget   *erro;
    
    /*  Window          */
    window  =
    gtk_application_window_new      (app);
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "MessageDialog"                );
    gtk_window_set_default_size     (GTK_WINDOW(window),    300, 200);
    gtk_window_set_position         (GTK_WINDOW(window),    1       );
    gtk_container_set_border_width  (GTK_CONTAINER(window), 15      );
    
    /*  Container       */
    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    );
    
    /*  Buttons         */
    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"    );
    
    /*  Attach to grid  */
    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);
    
    /*  Signals         */
    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  );
    
    gtk_widget_show_all             (window);
}

void show_info(GtkWidget *widget, gpointer window)
{
    GtkWidget   *dialog
    =   gtk_message_dialog_new      (window, 2, 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
    =   gtk_message_dialog_new      (window, 2, 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
    =   gtk_message_dialog_new      (window, 2, 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
    =   gtk_message_dialog_new      (window, 2, 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値は1です
      GTK_DIALOG_DESTROY_WITH_PARENT値は2です
      GTK_DIALOG_USE_HEADER_BAR値は4です
    3. 第3引数にメッセージダイアログの種類を定数で指定します
    4. 第4引数にメッセージダイアログに表示されるボタンの種類を定数で指定します
    5. 第5引数にメッセージダイアログに表示される文字列を指定します
  9. gtk_window_set_title(GTK_WINDOW(dialog),"Information");
    メッセージダイアログのタイトルを設定しています。 メッセージダイアログもウィンドウの一種類だと見なされています。
  10. gtk_dialog_run(GTK_DIALOG(dialog));
    この関数で、引数で指定したダイアログを表示させます。 ダイアログのボタンが押されるか、ダイアログを閉じられるまでは、 ここで処理が止まります。
    そして、メッセージダイアログはボタンが押されて閉じられる時に、 押されたボタンの種類を整数として返します。
  11. <>gtk_widget_destroy(dialog);
    メッセージダイアログを閉じると、目には見えなくなりますが、 その実体はまだ存在しています。
    gtk_widget_destroy関数でダイアログを破棄して、 メッセージダイアログに割り当てられていたメモリーを解放します。


ファイルダイアログ

filedialog.c


#include <gtk/gtk.h>

GtkWidget   *label;

void        activate();
void        select_file();

int main(int argc, char **argv)
{
    GtkApplication  *app;
    int             status;
    
    app     =   gtk_application_new ("jp.vivacocoa.filedialog", 0   );
    g_signal_connect                (app,       "activate",
                                     G_CALLBACK( activate), NULL    );
    status  =   g_application_run   (G_APPLICATION(app), argc,  argv);
    g_object_unref                  (app);
    return  status;
}

void activate(GtkApplication *app, gpointer data)
{
    GtkWidget   *window;
    GtkWidget   *vbox;
    GtkWidget   *menubar;
    GtkWidget   *filemenu;
    GtkWidget   *fileitem;
    GtkWidget   *openitem;
    
    /*  Window          */
    window  =
    gtk_application_window_new      (app);
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "File dialog"                  );
    gtk_window_set_default_size     (GTK_WINDOW(window),    300, 200);
    gtk_window_set_position         (GTK_WINDOW(window),    1       );
    
    /*  Container       */
    vbox    =   gtk_box_new         (GTK_ORIENTATION_VERTICAL,  0   );
    gtk_container_add               (GTK_CONTAINER(window),     vbox);
    
    /*  MenuBar         */
    menubar =   gtk_menu_bar_new    ();
    filemenu
            =   gtk_menu_new        ();
    fileitem
    =   gtk_menu_item_new_with_label("File");
    openitem
    =   gtk_menu_item_new_with_label("Open");
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),
                                     fileitem);
    gtk_menu_shell_append           (GTK_MENU_SHELL(filemenu),
                                     openitem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(fileitem),
                                     filemenu);
    
    /*  Label           */
    label   =   gtk_label_new       ("Unselected");
    gtk_label_set_justify           (GTK_LABEL(label),
                                     GTK_JUSTIFY_CENTER);
    
    /*  Pack to box     */
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
    gtk_box_pack_end                (GTK_BOX(vbox), label  , 1, 0, 0);
    
    /*  Signal          */
    g_signal_connect                (openitem,  "activate",
                                     G_CALLBACK(select_file), window);
    
    gtk_widget_show_all             (window);
}

void select_file(GtkWidget *widget, gpointer window)
{
    gint        result;
    GtkWidget   *dialog
    = gtk_file_chooser_dialog_new   ("Selec File",
                                     window,
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
                                     ("Cancel"),
                                     GTK_RESPONSE_CANCEL,
                                     ("Open"),
                                     GTK_RESPONSE_ACCEPT,
                                     NULL                           );
    result  =   gtk_dialog_run      (GTK_DIALOG(dialog)             );
    if (result == GTK_RESPONSE_ACCEPT)
    {
        char    *filename;
        char    *basename;
        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),  "Unselected");
    }
    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);
    ダイアログを格納したメモリー部分を破棄して、メモリーを解放しています。


フォントダイアログ

fontdialog.c


#include <gtk/gtk.h>

GtkWidget   *window;

void        activate();
void        select_font();

int main(int argc, char **argv)
{
    GtkApplication  *app;
    int             status;
    
    app     =   gtk_application_new ("jp.vivacocoa.fontdialog", 0   );
    g_signal_connect                (app,       "activate",
                                     G_CALLBACK( activate),     NULL);
    status  =   g_application_run   (G_APPLICATION(app), argc,  argv);
    g_object_unref                  (app);
    return  status;
}

void activate(GtkApplication *app, gpointer data)
{
    GtkWidget   *vbox;
    GtkWidget   *menubar;
    GtkWidget   *editmenu;
    GtkWidget   *edititem;
    GtkWidget   *fontitem;
    GtkWidget   *label;
    
    /*  Window          */
    window  =
    gtk_application_window_new      (app);
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "Font dialog"                  );
    gtk_window_set_default_size     (GTK_WINDOW(window),    300, 200);
    gtk_window_set_position         (GTK_WINDOW(window),    1       );
    
    /*  Container       */
    vbox    =   gtk_box_new         (GTK_ORIENTATION_VERTICAL,  0   );
    gtk_container_add               (GTK_CONTAINER(window),     vbox);
    
    /*  MenuBar         */
    menubar =   gtk_menu_bar_new    ();
    editmenu
            =   gtk_menu_new        ();
    edititem
    =   gtk_menu_item_new_with_label("Edit");
    fontitem
    =   gtk_menu_item_new_with_label("Font");
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),
                                     edititem);
    gtk_menu_shell_append           (GTK_MENU_SHELL(editmenu),
                                     fontitem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(edititem),
                                     editmenu);
    /*  Label           */
    label   =   gtk_label_new       ("Gtk Font Dialog");
    gtk_label_set_justify           (GTK_LABEL(label),
                                     GTK_JUSTIFY_CENTER);
    
    /*  Pack to box     */
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
    gtk_box_pack_end                (GTK_BOX(vbox), label  , 1, 0, 0);
    
    /*  Signal          */
    g_signal_connect                (fontitem,  "activate",
                                     G_CALLBACK(select_font), label );
    
    /*  Show window     */
    gtk_widget_show_all             (window);
}

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)
    {
        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);
}
    

実行結果

Comic SansというフォントはmacOSだけだと思います。

コード説明

  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( )関数を使うと その実際の値が入っているメモリー部分が破棄されてメモリーが解放されます。


カラーダイアログ

colordialog.c


#include <gtk/gtk.h>

GdkRGBA color;

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

int main(int argc, char **argv)
{
    GtkApplication  *app;
    int             status;
    
    app     =   gtk_application_new ("jp.vivacocoa.colordialog", 0  );
    g_signal_connect                (app,       "activate",
                                     G_CALLBACK( activate),     NULL);
    status  =   g_application_run   (G_APPLICATION(app), argc,  argv);
    g_object_unref                  (app);
    return  status;
}

void activate(GtkApplication *app, gpointer data)
{
    GtkWidget   *window;
    GtkWidget   *vbox;
    GtkWidget   *menubar;
    GtkWidget   *editmenu;
    GtkWidget   *edititem;
    GtkWidget   *coloritem;
    GtkWidget   *darea;
    
    /*  Window          */
    window  =
    gtk_application_window_new      (app);
    gtk_window_set_title            (GTK_WINDOW(window),
                                     "Color dialog"                 );
    gtk_window_set_default_size     (GTK_WINDOW(window),    300, 200);
    gtk_window_set_position         (GTK_WINDOW(window),    1       );
    
    /*  Container       */
    vbox    =   gtk_box_new         (GTK_ORIENTATION_VERTICAL,  0   );
    gtk_container_add               (GTK_CONTAINER(window),     vbox);
    
    /*  Menubar         */
    menubar =   gtk_menu_bar_new    ();
    editmenu
            =   gtk_menu_new        ();
    edititem
    =   gtk_menu_item_new_with_label("Edit");
    coloritem
    =   gtk_menu_item_new_with_label("Color");
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),
                                     edititem);
    gtk_menu_shell_append           (GTK_MENU_SHELL(editmenu),
                                     coloritem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(edititem),
                                     editmenu);
    
    /*  Drawing area    */
    darea   = gtk_drawing_area_new  ();
    gdk_rgba_parse                  (&color, "rgb(127, 127, 127)"   );
    
    /*  Pack to box     */
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
    gtk_box_pack_end                (GTK_BOX(vbox), darea  , 1, 1, 0);
    
    /*  Signals         */
    g_signal_connect                (darea,         "draw",
                                     G_CALLBACK(draw_callback), NULL);
    g_signal_connect                (coloritem,     "activate",
                                     G_CALLBACK(select_color), window);
    
    /* Show Window      */
    gtk_widget_show_all             (window);
}

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", 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);
}
    

実行結果

コード説明

  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);
    ダイアログは閉じただけでは、目に見えなくなるだけで、 メモリー上には存在しています。
    この関数は引数で指定したウィジェット(この場合はダイアログ)を メモリー上から破棄して、そのメモリー領域を解放します。



3654 visits
Posted: Jan. 08, 2020
Update: Jan. 09, 2020

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