なんか久しぶりすぎるが気にしない。w
今回はメニューの追加について。
メニューの構造は「ファイル」→「新規作成」「開く」など、階層構造になっていることが多い。1つの階層の構造は以下のようなクラスを使った構造で表される。
GtkMenuShell (メニューバー、サブメニュー) GtkMenuItem (メニュー上のアイテム) GtkMenuItem ....
GtkMenuItem というのは、メニューに表示されるアイテム一つ一つのことで、例えば「ファイル」「新規作成」「開く」など、メニュー上で選択可能なものはすべて GtkMenuItem。
GtkMenuShell は、これら GtkMenuItem を入れるためのコンテナ。たとえば画面上部のメニューバーが GtkMenuShell であれば、その上に表示される「ファイル」「編集」などの文字が GtkMenuItem であって、GtkMenuShell は、これらの GtkMenuItem をまとめる役割を行う。
また、GtkMenuItem には、サブメニューとして GtkMenuShell を紐付けることができる。これにより、メニューの階層構造を実現できる。
なお、GtkMenuShell というのは抽象クラスであり、実際には以下の2つが使用される。
- GtkMenuBar : 常時表示されている横長のメニュー
- GtkMenu : 必要なときにのみ表示されるポップアップメニュー
実際には、最上位のメニューに GtkMenuBar を使用し、それ以下の階層、例えば「ファイル」メニューをクリックしたときに表示されるサブメニューなどに GtkMenu を使用するとよい。
さて実際の例。今回は、メニューにいくつかのアイテムを追加し、それらが選択されたときに、ウィンドウ内の文字列を変化されるサンプルを作ってみた。
(ソースは以下の場所に上げてあります)
http://github.com/egawata/hatena_blog/tree/master/menu
// (1)MenuBar 'menubar' を作成する menubar = gtk_menu_bar_new(); // (1)MenuBar 'menubar' を BOX に追加する gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
まず一番上の階層であるメニューバーから。メニューバーの生成には gtk_menu_bar_new() を使用する。生成時点では、内容は空。
// (2)MenuItem 'lunch' を作成する lunch = gtk_menu_item_new_with_label("メニュー"); … // (2)MenuItem 'lunch' を MenuBar 'menubar' に追加する gtk_menu_shell_append(GTK_MENU_SHELL(menubar), lunch);
メニューバーに入れるアイテムを作成し、メニューバーに追加する。今回は1つだけ、「メニュー」というアイテムを追加する。
// (3)Menu 'lunchmenu' を作成する lunchmenu = gtk_menu_new(); ... // (3)Menu 'lunchmenu' を MenuItem 'lunch' のサブメニューとする gtk_menu_item_set_submenu(GTK_MENU_ITEM(lunch), lunchmenu);
先ほど追加したアイテム「メニュー」に、サブメニュー lunchmenu を紐付ける。これにより、メニューバー上の「メニュー」を押すとサブメニューが現れるようになる。ただし現時点では内容は空。
// (4a)MenuItem 'menu*' を作成する menu1 = gtk_menu_item_new_with_label("カレー"); menu2 = gtk_menu_item_new_with_label("おにぎり"); menu3 = gtk_menu_item_new_with_label("俺の塩"); // (4b)MenuItem 'menu*' を Menu 'lunchmenu' に追加する gtk_menu_shell_append(GTK_MENU_SHELL(lunchmenu), menu1); gtk_menu_shell_append(GTK_MENU_SHELL(lunchmenu), menu2); gtk_menu_shell_append(GTK_MENU_SHELL(lunchmenu), menu3);
このサブメニューに入れるアイテムを3つ作成し、それをサブメニューに追加していく。
これでメニューが一通り表示されるようにはなったのだが、今の状態では、サブメニュー内の「カレー」などのアイテムを選択しても何も起こらない。メニューが選択されたときに何かをさせたい場合は、コールバック関数を登録する。
// (5)MenuItem 'menu*' が選択されたときに呼ばれるコールバック関数を // menu_activated() に設定する。 // また、このときの引数として label も渡すようにする g_signal_connect(G_OBJECT(menu1), "activate", G_CALLBACK(menu_activated), (gpointer)label); g_signal_connect(G_OBJECT(menu2), "activate", G_CALLBACK(menu_activated), (gpointer)label); g_signal_connect(G_OBJECT(menu3), "activate", G_CALLBACK(menu_activated), (gpointer)label);
各メニューが選択されたら、関数 menu_activated が呼ばれるようにする。menu_activated() は、ラベル label に書かれた文字列を変更している。
static void menu_activated(GtkMenuItem *menuitem, GtkWidget *label) { const gchar *name = gtk_menu_item_get_label(menuitem); char message[100]; snprintf(message, 100, "%sの注文を承りました。", name); gtk_label_set_text(GTK_LABEL(label), message); }
(実行結果)
- 初期状態
- 「カレー」が選択された
実はサブメニューが表示されているときのキャプチャも取りたかったんだけど、サブメニューが表示されてる間はキャプチャできないのねorz