メニュバーの表示


さて、メニューバーを表示させるサンプル・プログラムを作成してみたが、 vboxの上段に表示されるはずのメニューバーが現れない。 しかし、コンパイルは通るし、コアダンプも無い。 思い出した。Ubuntu11.10以降はウィンドウを広く使うため、 メニュバーは画面の左上にマウスのアイコンを移した時に、表示されるんだった。 しかし、それでは説明しづらいので、メニューバーをウィンドウ内に戻してみた。 所が、Firefoxの起動に不具合が出たので、やむなく元に戻した。 よって、Ubuntu流に説明するしかない。 4章のvboxでは上にスクロール付きイメージ、下にボタンを配置してみたが、 今回は上にメニューバー、下にスクロールバー付きイメージを表示する。

#include <gtk/gtk.h>
#include <stdlib.h>

//Openメニューが選択された時に呼び出される関数
static void cb_open(GtkAction *action, gpointer user_data)
{
  //内容はまだ未処理のまま
  g_print("This function isn't implemented yet.\n");
}

//Quitメニューが選択された時に呼び出される関数
static void cb_quit(GtkAction *action, gpointer user_data)
{
  GObject *window = G_OBJECT(user_data);
  //uiは共用データkeyの名称である
  g_object_unref(g_object_get_data(window, "ui"));
  gtk_main_quit();
}

//メニューの構造をXML形式で記述
static const gchar *menu_info =
  "<ui>"
  "  <menubar name='Menubar'>"
  "    <menu name='File' action='File'>"
  "      <menuitem name='Open' action='Open'/>"
  "      <separator/>"
  "      <menuitem name='Quit' action='Quit'/>"
  "    </menu>"
  "  </menubar>"
  "</ui>";

//メニューアイテムの詳細情報
static GtkActionEntry entries[] = {
  {"File", NULL, "_File"},
  {"Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open an image", G_CALLBACK(cb_open)},
  {"Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q", "Quit this program", G_CALLBACK(cb_quit)},
};

//メニューを作成する関数
static GtkUIManager* create_menu(GtkWidget *parent)
{
  GtkUIManager *ui;
  GtkActionGroup *actions;

  //UIマネージャの作成
  ui = gtk_ui_manager_new();
  //アクショングループの作成
  actions = gtk_action_group_new("menu");
  //アクショングループにメニューアイテムの詳細情報を追加
  gtk_action_group_add_actions(actions, entries, sizeof(entries) / sizeof(entries[0]), parent);
  //アクショングループをUIマネージャに登録
  gtk_ui_manager_insert_action_group(ui, actions, 0);
  //メニュー構成情報をUIマネージャに登録
  gtk_ui_manager_add_ui_from_string(ui, menu_info, -1, NULL);
  //ウィンドウ上でメニューアイテムのショートカットキーを有効にする設定
  gtk_window_add_accel_group(GTK_WINDOW(parent), gtk_ui_manager_get_accel_group(ui));
  return ui;
}

int main(int argc, char** argv)
{
  GtkWidget *window;
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_size_request(window, 300, 200);
  {
    GtkWidget *vbox;
    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    {
      //GTK UIマネージャ
      GtkUIManager *ui;
      //メニューバー・ウィジェット
      GtkWidget *menubar;
      GtkWidget *scroll_window;

      //ウィンドウ上にメニューを作成
      ui = create_menu(window);
      //ウィンドウに"ui"という識別子でUIマネージャを登録
      g_object_set_data(G_OBJECT(window), "ui", (gpointer)ui);
      //メニューバーを取得
      menubar = gtk_ui_manager_get_widget(ui, "/Menubar");
      //メニュバーをvboxに配置
      gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
      scroll_window = gtk_scrolled_window_new(NULL, NULL);
      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
      gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
      {
        GtkWidget *image;
        image = gtk_image_new_from_file("goshikinuma.jpg");
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_window), image);
      }
    }
  }
  gtk_widget_show_all(window);
  gtk_main();

  return 0;
}

Fileをクリックすると、

Open Ctrl+O
Quit Ctrl+Q

という項目が現れ、両項目の間にはXML部分の<separator/>タグによって、 境界線が引かれている。XML部分だが、例えば

static const gchar *menu_info =
  "<ui>"
  "  <menubar name='Menubar'>"
  "    <menu name='File' action='File'>"
  "      <menuitem name='Open' action='Open'/>"
  "      <separator/>"
  "      <menuitem name='Quit' action='Quit'/>"
  "    </menu>"
  "    <menu name='Edit' action='Edit'>"
  "      <menuitem name='Copy' action='Copy'/>"
  "      <menuitem name='Paste' action='Paste'/>"
  "    </menu>"
  "  </menubar>"
  "</ui>";

と記述し、関連動作部分の変更を行えば、メニューバーの項目を

FileEdit
┣Open Ctrl+O┣Copy Ctrl+C
┗ Quit Ctrl+Q┗ Paste Ctrl+V

と変化させる事もできる。


ファイル選択ダイアログ


難しいUIマネージャを使ったのだから、ファイルの参照くらいはしておきたい。 次のサンプルは、新しくダイアログを表示させ、選択した画像ファイルを、 スクロールバー付きウィンドウに表示させる物である。

#include <gtk/gtk.h>
#include <stdlib.h>

//イメージ・ウィジェットはあちこちで使うので、ここで宣言
GtkWidget *image;

static void cb_open(GtkAction *action, gpointer user_data)
{
  GtkWidget *window;
  GtkWidget *dialog;
  gint response;

  window = GTK_WIDGET(user_data);
  //ファイル選択ダイアログを作成
  dialog = gtk_file_chooser_dialog_new("Open an image file", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
  //ファイル選択ダイアログを表示
  gtk_widget_show_all(dialog);
  //ファイル選択処理を開始
  response = gtk_dialog_run(GTK_DIALOG(dialog));
  //ファイル選択処理が終了した戻り値を受け取ったら
  if( response == GTK_RESPONSE_ACCEPT){
    gchar *filename;
    //選択したファイル名を取得
    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    //取得したファイル名から画像を表示
    gtk_image_set_from_file(GTK_IMAGE(image), filename);
    //ファイル名取得に確保したメモリ領域を開放
    g_free(filename);
  }
  //ファイル選択ダイアログを閉じる
  gtk_widget_destroy(dialog);
}

static void cb_quit(GtkAction *action, gpointer user_data)
{
  GObject *window = G_OBJECT(user_data);

  g_object_unref(g_object_get_data(window, "ui"));
  gtk_main_quit();
}

static const gchar *menu_info =
  "<ui>"
  "  <menubar name='Menubar'>"
  "    <menu name='File' action='File'>"
  "      <menuitem name='Open' action='Open'/>"
  "      <separator/>"
  "      <menuitem name='Quit' action='Quit'/>"
  "    </menu>"
  "  </menubar>"
  "</ui>";

static GtkActionEntry entries[] = {
  {"File", NULL, "_File"},
  {"Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open an image", G_CALLBACK(cb_open)},
  {"Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q", "Quit this program", G_CALLBACK(cb_quit)},
};

static GtkUIManager* create_menu(GtkWidget *parent)
{
  GtkUIManager *ui;
  GtkActionGroup *actions;
  GError *gErrors = NULL;
  ui = gtk_ui_manager_new();
  actions = gtk_action_group_new("menu");
  gtk_action_group_add_actions(actions, entries, sizeof(entries) / sizeof(entries[0]), parent);
  gtk_ui_manager_insert_action_group(ui, actions, 0);
  gtk_ui_manager_add_ui_from_string(ui, menu_info, -1, NULL);
  gtk_window_add_accel_group(GTK_WINDOW(parent), gtk_ui_manager_get_accel_group(ui));
  return ui;
}

int main(int argc, char** argv)
{
  GtkWidget *window;
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_size_request(window, 300, 200);
  {
    GtkWidget *vbox;
    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    {
      GtkUIManager *ui;
      GtkWidget *menubar;
      GtkWidget *scroll_window;

      ui = create_menu(window);
      g_object_set_data(G_OBJECT(window), "ui", (gpointer)ui);
      menubar = gtk_ui_manager_get_widget(ui, "/Menubar");
      gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
      scroll_window = gtk_scrolled_window_new(NULL, NULL);
      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
      gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
      {
        //今回、初期表示画像は無し
        image = gtk_image_new();
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_window), image);
      }
    }
  }
  gtk_widget_show_all(window);
  gtk_main();

  return 0;
}

指定したアプリケーションのみに、ウィンドウ内にメニューバーを入れるコマンドが有った。 重ねて記すが、OSはLinuxのUbuntuである。 testという実行ファイルを作成したので、端末から
env UBUNTU_MENUPROXY=0 ./test
と実行する。 まず、イメージ無しのウィンドウが表示される。 メニューバーからOpenをクリックする。

ファイル選択ダイアログを作成した時に、「開く(O)」ボタンと「キャンセル(C)」ボタンを作成していた。
dialog = gtk_file_chooser_dialog_new("Open an image file", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
ここで、第3引数にGTK_FILE_CHOOSER_ACTION_OPENを選択しているが、 GtkFileChooseActionには

GTK_FILE_CHOOSER_ACTION_OPEN ファイルを開く
GTK_FILE_CHOOSER_ACTION_SAVE ファイルを保存
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER フォルダを選択
GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER フォルダを作成

の4種類が有る。実際に、ファイルを開いてみる。

 

少し難しかったが、ファイル選択ダイアログが使えるようになった。 次は時間経過から、タイマー機能を使うプログラムを作ってみたい。


前章  | 目次 |  次章



トップ



/