試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

C言語のGTK+でListStoreからデータを取り出す処理に関する追加メモ(後半)

C言語のGTK+でListStoreからデータを取り出す処理に関する追加メモ(前半)」の続き。
C言語でGTK+ 2を扱う上での幾つかのメモ(第9回)」の例と同じ処理をgtk_tree_model_get()を用いたものに書き換えると下のようになり、動作は同じものとなる。
[任意]ファイル名: treeviewliststoretest2.c

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

/*
 * C言語によるGTK+のTreeView(ListStore使用)のテスト2
 * gtk_tree_model_get()を用いた例
 *
 * gcc -O2 -Wall -Wextra $(pkg-config --cflags --libs gtk+-2.0) treeviewliststoretest2.c -o treeviewliststoretest2
 */

enum
{
  COLUMN_A,     /* 最初は0 */
  COLUMN_B,
  COLUMN_C,
  NUM_COLUMNS,  /* 最後のコラム番号の次がコラム数になる */
};

void
on_button_clicked (GtkTreeView *tv)  /* swapped指定なのでボタンではない */
{
  gboolean ret_a;
  gint ret_b;
  gchar *ret_c;
  GtkTreeIter iter;
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  selection = gtk_tree_view_get_selection (tv);
  /*
   * 現在ツリービュー上で選択されている項目(全コラムのまとまり)を取得
   * ツリービューに関連付けられているモデル(ここではListStore)の場所を受け取って
   * 内容にアクセスできるようにする(コピーするのではない)
   * 関数の中でmodelとiterの内容が書き換えられる
   */
  gtk_tree_selection_get_selected (selection, &model, &iter);
  /* 各コラムの値をListStoreからそれぞれ取り出して書き込む */
  gtk_tree_model_get (model, &iter,
                      COLUMN_A, &ret_a,
                      COLUMN_B, &ret_b,
                      COLUMN_C, &ret_c,
                      -1);
  /* それぞれを端末に表示 */
  g_print ("A:%s B:%d C:%s\n", ((ret_a) ? "TRUE" : "FALSE"), ret_b, ret_c);
  /* 文字列はg_free()で解放する */
  g_free (ret_c);
}

int
main (int argc, char **argv)
{
  GtkListStore *ls;
  GtkWidget *mainwindow, *menubar, *tv, *sw, *button, *vbox;
  GtkWidget *item_quit, *item_file, *menu_file;
  GtkAccelGroup *accelgroup;
  GtkTreeIter iter;
  GtkTreeViewColumn *col_a, *col_b, *col_c;
  gtk_init (&argc, &argv);
  mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  /***** ショートカットキー(アクセラレータ) *****/
  accelgroup = gtk_accel_group_new ();
  gtk_window_add_accel_group (GTK_WINDOW (mainwindow), accelgroup);
  /***** メニュー項目 *****/
  item_quit = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, accelgroup);
  menu_file = gtk_menu_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu_file), item_quit);
  item_file = gtk_menu_item_new_with_mnemonic ("_File");
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item_file), menu_file);
  menubar = gtk_menu_bar_new ();
  gtk_menu_bar_append (GTK_MENU_BAR (menubar), item_file);
  /***** ツリービュー *****/
  /*** コラム ***/
  /* 最初の2つの引数は表示文字列とセルレンダラオブジェクト */
  col_a = gtk_tree_view_column_new_with_attributes ("Column A",
                                                    gtk_cell_renderer_toggle_new (),
          /* 「[セルレンダラのGObjectプロパティ名], [コラム番号]」の繰り返し */
                                                    "active", COLUMN_A,
                                                    NULL);  /* 最後にNULL */
  col_b = gtk_tree_view_column_new_with_attributes ("Column B",
                                                    gtk_cell_renderer_text_new (),
                                                    "text", COLUMN_B,
                                                    NULL);
  col_c = gtk_tree_view_column_new_with_attributes ("Column C",
                                                    gtk_cell_renderer_text_new (),
                                                    "text", COLUMN_C,
                                                    NULL);
  /*** データ(ListStore) ***/
  ls = gtk_list_store_new (NUM_COLUMNS,
                           G_TYPE_BOOLEAN,  /* 真偽値 */
                           G_TYPE_INT,      /* 整数   */
                           G_TYPE_STRING);  /* 文字列 */
  /*** ツリービューとその設定 ***/
  tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ls));  /* モデルと関連付け */
  gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col_a);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col_b);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col_c);
  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tv), TRUE);
  sw = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_container_add (GTK_CONTAINER (sw), tv);
  /*
   * ListStoreへのデータの追加
   * 今回
   * (FALSE, 12345, "test"), (TRUE, 99999, "GTK+"), (FALSE, 838861, "ListStore")
   * という3つのデータを続けて追加するものとする
   */
  gtk_list_store_append (ls, &iter);
  gtk_list_store_set (ls, &iter,
                      COLUMN_A, FALSE,  /* コラム番号と値のペア(引数2つ単位) */
                      COLUMN_B, 12345,
                      COLUMN_C, "test",
                      -1);              /* -1を最後に付ける */
  gtk_list_store_append (ls, &iter);
  gtk_list_store_set (ls, &iter,
                      COLUMN_A, TRUE,
                      COLUMN_B, 99999,
                      COLUMN_C, "GTK+",
                      -1);
  gtk_list_store_append (ls, &iter);
  gtk_list_store_set (ls, &iter,
                      COLUMN_A, FALSE,
                      COLUMN_B, 838861,
                      COLUMN_C, "ListStore",
                      -1);
  /***** ボタン *****/
  button = gtk_button_new_with_mnemonic ("_Get");
  /***** 垂直ボックス(縦方向分割) *****/
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  /***** ウィンドウ *****/
  gtk_container_add (GTK_CONTAINER (mainwindow), vbox);
  gtk_widget_show_all (mainwindow);
  gtk_widget_set_size_request (mainwindow, 250, 160);
  gtk_window_resize (GTK_WINDOW (mainwindow), 300, 220);
  /***** シグナル *****/
  g_signal_connect (G_OBJECT (mainwindow), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
  g_signal_connect (G_OBJECT (item_quit), "activate", G_CALLBACK (gtk_main_quit), NULL);
  g_signal_connect_object (G_OBJECT (button), "clicked", G_CALLBACK (on_button_clicked), G_OBJECT (tv), G_CONNECT_SWAPPED);
  /***** メインループ開始 *****/
  gtk_main ();
  return EXIT_SUCCESS;
}

オブジェクト(GdkPixbuf)をListStoreに入れた例は下のようになる。
[任意]ファイル名: treeviewliststoretest3.c

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

/*
 * C言語によるGTK+のTreeView(ListStore使用)のテスト3
 * gtk_tree_model_get()を用いた例・データにオブジェクト(GdkPixbuf)を使用
 *
 * gcc -O2 -Wall -Wextra $(pkg-config --cflags --libs gtk+-2.0) treeviewliststoretest3.c -o treeviewliststoretest3
 */

static const char *xpm1[] = {
"16 16 2 1",
" 	c None",
".	c #FF6666",
"     ......     ",
"    ........    ",
"  ............  ",
"  ............  ",
" .............. ",
"................",
"................",
"................",
"................",
"................",
"................",
" .............. ",
"  ............  ",
"  ............  ",
"    ........    ",
"     ......     "};
static const char *xpm2[] = {
"16 16 2 1",
" 	c None",
".	c #EDDB20",
"                ",
"       ..       ",
"       ..       ",
"      ....      ",
"      ....      ",
"   ..........   ",
"................",
" .............. ",
"  ............  ",
"   ..........   ",
"    ........    ",
"    ........    ",
"   ..........   ",
"   ..........   ",
"   ...    ...   ",
"   .        .   "};
static const char *xpm3[] = {
"16 16 2 1",
" 	c None",
".	c #2995E0",
"   ..........   ",
" .............. ",
"................",
"................",
"................",
" .............. ",
" .............. ",
" .............. ",
"  ............  ",
"  ............  ",
"   ..........   ",
"    ........    ",
"    ........    ",
"     ......     ",
"      ....      ",
"       ..       "};


enum
{
  COLUMN_A,     /* 最初は0 */
  COLUMN_B,
  NUM_COLUMNS,  /* 最後のコラム番号の次がコラム数になる */
};

void
on_button_clicked (GtkTreeView *tv)  /* swapped指定なのでボタンではない */
{
  gint ret_a;
  GObject *ret_b;
  gint i, j;
  int width, height;
  int n_channels;
  GtkTreeIter iter;
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  guchar *p, *r, *g, *b;
  selection = gtk_tree_view_get_selection (tv);
  /*
   * 現在ツリービュー上で選択されている項目(全コラムのまとまり)を取得
   * ツリービューに関連付けられているモデル(ここではListStore)の場所を受け取って
   * 内容にアクセスできるようにする(コピーするのではない)
   * 関数の中でmodelとiterの内容が書き換えられる
   */
  gtk_tree_selection_get_selected (selection, &model, &iter);
  /* 各コラムの値をListStoreからそれぞれ取り出して書き込む */
  gtk_tree_model_get (model, &iter,
                      COLUMN_A, &ret_a,
                      COLUMN_B, &ret_b,
                      -1);
  p = gdk_pixbuf_get_pixels (GDK_PIXBUF (ret_b));
  /* それぞれを端末に表示 */
  g_print ("A:%d\nB:\n", ret_a);
  n_channels = gdk_pixbuf_get_n_channels (GDK_PIXBUF (ret_b));
  width = gdk_pixbuf_get_width (GDK_PIXBUF (ret_b));
  height = gdk_pixbuf_get_height (GDK_PIXBUF (ret_b));
  /* GdkPixbufオブジェクトの中の各ピクセルの色を取得 */
  for (i = 0; i < height; i++)
  {
    for (j = 0; j < width; j++)
    {
      r = p;
      g = p + 1;
      b = g + 1;
      /*
       * a = b + 1;
       * 今回のデータではアルファチャンネルの値は0
       */
      g_print ("[#%02x%02x%02x]", *r, *g, *b);
      p += n_channels;
    }
    g_print ("\n");
  }
  g_print ("\n");
  /* オブジェクトはg_object_unref()で参照カウンタを減らす */
  g_object_unref (ret_b);
}

int
main (int argc, char **argv)
{
  GdkPixbuf *pixbuf1, *pixbuf2, *pixbuf3;
  GtkListStore *ls;
  GtkWidget *mainwindow, *menubar, *tv, *sw, *button, *vbox;
  GtkWidget *item_quit, *item_file, *menu_file;
  GtkAccelGroup *accelgroup;
  GtkTreeIter iter;
  GtkTreeViewColumn *col_a, *col_b;
  gtk_init (&argc, &argv);
  mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  /***** ショートカットキー(アクセラレータ) *****/
  accelgroup = gtk_accel_group_new ();
  gtk_window_add_accel_group (GTK_WINDOW (mainwindow), accelgroup);
  /***** メニュー項目 *****/
  item_quit = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, accelgroup);
  menu_file = gtk_menu_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu_file), item_quit);
  item_file = gtk_menu_item_new_with_mnemonic ("_File");
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item_file), menu_file);
  menubar = gtk_menu_bar_new ();
  gtk_menu_bar_append (GTK_MENU_BAR (menubar), item_file);
  /***** 画像(GdkPixbuf) *****/
  pixbuf1 = gdk_pixbuf_new_from_xpm_data (xpm1);
  pixbuf2 = gdk_pixbuf_new_from_xpm_data (xpm2);
  pixbuf3 = gdk_pixbuf_new_from_xpm_data (xpm3);
  /***** ツリービュー *****/
  /*** コラム ***/
  /* 最初の2つの引数は表示文字列とセルレンダラオブジェクト */
  col_a = gtk_tree_view_column_new_with_attributes ("Column A",
                                                    gtk_cell_renderer_text_new (),
          /* 「[セルレンダラのGObjectプロパティ名], [コラム番号]」の繰り返し */
                                                    "text", COLUMN_A,
                                                    NULL);  /* 最後にNULL */
  col_b = gtk_tree_view_column_new_with_attributes ("Column B",
                                                    gtk_cell_renderer_pixbuf_new (),
                                                    "pixbuf", COLUMN_B,
                                                    NULL);
  /*** データ(ListStore) ***/
  ls = gtk_list_store_new (NUM_COLUMNS,
                           G_TYPE_INT,
                           G_TYPE_OBJECT);
  /*** ツリービューとその設定 ***/
  tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ls));  /* モデルと関連付け */
  gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col_a);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col_b);
  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tv), TRUE);
  sw = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_container_add (GTK_CONTAINER (sw), tv);
  /*
   * ListStoreへのデータの追加
   * 今回
   * (192, pixbuf1), (168, pixbuf2), (1, pixbuf3)
   * という3つのデータを続けて追加するものとする
   */
  gtk_list_store_append (ls, &iter);
  gtk_list_store_set (ls, &iter,
                      COLUMN_A, 192,  /* コラム番号と値のペア(引数2つ単位) */
                      COLUMN_B, pixbuf1,
                      -1);              /* -1を最後に付ける */
  gtk_list_store_append (ls, &iter);
  gtk_list_store_set (ls, &iter,
                      COLUMN_A, 168,
                      COLUMN_B, pixbuf2,
                      -1);
  gtk_list_store_append (ls, &iter);
  gtk_list_store_set (ls, &iter,
                      COLUMN_A, 1,
                      COLUMN_B, pixbuf3,
                      -1);
  /***** ボタン *****/
  button = gtk_button_new_with_mnemonic ("_Get");
  /***** 垂直ボックス(縦方向分割) *****/
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  /***** ウィンドウ *****/
  gtk_container_add (GTK_CONTAINER (mainwindow), vbox);
  gtk_widget_show_all (mainwindow);
  gtk_widget_set_size_request (mainwindow, 150, 150);
  gtk_window_resize (GTK_WINDOW (mainwindow), 170, 170);
  /***** シグナル *****/
  g_signal_connect (G_OBJECT (mainwindow), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
  g_signal_connect (G_OBJECT (item_quit), "activate", G_CALLBACK (gtk_main_quit), NULL);
  g_signal_connect_object (G_OBJECT (button), "clicked", G_CALLBACK (on_button_clicked), G_OBJECT (tv), G_CONNECT_SWAPPED);
  /***** メインループ開始 *****/
  gtk_main ();
  return EXIT_SUCCESS;
}

この例では

コラムBはGdkPixbufの画像となり、ボタンを押すと

A:192
B:
[#000000][#000000][#000000][#000000][#000000][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#000000][#000000][#000000][#000000][#000000]
[#000000][#000000][#000000][#000000][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#000000][#000000][#000000][#000000]
[#000000][#000000][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#000000][#000000]
[#000000][#000000][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#000000][#000000]
(中略)
[#000000][#000000][#000000][#000000][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#000000][#000000][#000000][#000000]
[#000000][#000000][#000000][#000000][#000000][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#ff6666][#000000][#000000][#000000][#000000][#000000]

のように各ピクセルの色が順に端末に表示される。

関連記事:

参考URL: