GtkTreeViewのGTK_SELECTION_MULTIPLEモード(その1)
GtkTreeView で選択された項目を取得するには、 gtk_tree_model_get () を使えば良いという記事を書きましたが、これは、 GtkTreeView の選択オブジェクト GtkTreeSelection のモードが GTK_SELECTION_SINGLE と GTK_SELECTION_BROWSE の時だけで、GTK_SELECTION_MULTIPLE の時には、違う処理が必要になります。
ということで、サンプルは以下の通り。最初は GtkBuilder 用の m_treeview.ui ファイル。
<?xml version="1.0" encoding="UTF-8"?> <interface> <!-- interface-requires gtk+ 3.0 --> <object class="GtkListStore" id="liststore1"> <columns> <!-- column-name column1 --> <column type="gchararray"/> </columns> </object> <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <signal name="destroy" handler="cb_quit" swapped="no"/> <child> <object class="GtkScrolledWindow" id="scrolledwindow1"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <object class="GtkTreeView" id="treeview1"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">liststore1</property> <property name="reorderable">True</property> <child internal-child="selection"> <object class="GtkTreeSelection" id="treeview-selection1"> <property name="mode">multiple</property> </object> </child> <child> <object class="GtkTreeViewColumn" id="treeviewcolumn1"> <property name="title" translatable="yes">fruit</property> <property name="clickable">True</property> <property name="reorderable">True</property> <signal name="clicked" handler="cb_click" swapped="no"/> <child> <object class="GtkCellRendererText" id="renderer1"/> <attributes> <attribute name="text">0</attribute> </attributes> </child> </object> </child> </object> </child> </object> </child> </object> </interface>
注意するところは、
<child internal-child="selection"> <object class="GtkTreeSelection" id="treeview-selection1"> <property name="mode">multiple</property> </object> </child>
のように、 GtkTreeSelection のプロパティ "mode" が multiple になっていることです。
それ以外では、 signal 処理として、 GtkWindow 型オブジェクト "window1" の "destroy" singal に cb_quit() を割り当て、GtkTreeViewColumn 型のオブジェクト "treeviewcolumn1" の、 "clicked" signale に "cb_click" を割り当てていることに注意してください。
プログラムは、m_treeview.cとします。
#include <gtk/gtk.h> GtkBuilder *builder; G_MODULE_EXPORT void cb_quit (GtkAction *action) { gtk_main_quit (); } void cb_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { gchar *fruit; gtk_tree_model_get (model, iter, 0, &fruit, -1); g_print ("%s\n", fruit); g_free (fruit); } G_MODULE_EXPORT void cb_click (GtkAction *action) { GtkTreeView *treeview; GtkTreeSelection *selection; treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview1")); selection = gtk_tree_view_get_selection (treeview); gtk_tree_selection_selected_foreach (selection, cb_foreach, NULL); } int main (int argc, char* argv[]) { GtkWindow *window; GError *error = NULL; gchar *fruit[] = {"banana", "apple", "orange", "grape", "strawberry", "peach", "melon", "marron", "papaya", "pear", "mango", NULL}; GtkTreeView *treeview; GtkTreeIter iter; GtkListStore *store; gint i; gtk_init (&argc, &argv); builder = gtk_builder_new (); gtk_builder_add_from_file (builder, "m_treeview.ui", &error); g_assert_no_error (error); gtk_builder_connect_signals (builder, NULL); treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview1")); store = GTK_LIST_STORE (gtk_tree_view_get_model (treeview)); for (i = 0; fruit[i] != NULL; i++) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, fruit[i], -1); } gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0, GTK_SORT_ASCENDING); window = GTK_WINDOW (gtk_builder_get_object (builder, "window1")); gtk_widget_show_all (GTK_WIDGET (window)); gtk_main(); return 0; }
ということで、個別に見ていきます。
最初の関数 cb_quit() は、 window1 の X ボタンを押すと発信される signal "destroy" のコールバック関数で、単純に gtk_main_quit() を呼び出しています。
G_MODULE_EXPORT void cb_quit (GtkAction *action) { gtk_main_quit (); }
次の関数 cb_foreach() は、更に次の関数 cb_click() 内の gtk_tree_selection_selected_foreach() で指定されている関数で。GtkTreeView で使用しているインターフェースモデル GtkTreeModel と選択されている個々の GtkTreeIter を用いて値を取得し、 g_print() で出力しています。
void cb_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { gchar *fruit; gtk_tree_model_get (model, iter, 0, &fruit, -1); g_print ("%s\n", fruit); g_free (fruit); }
この関数は、以下のように宣言されています。
void (*GtkTreeSelectionForeachFunc) (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
その次が、 GtkTreeView の項目名 "fruit" をクリックした時に実行されるコールバック関数です。
単純に GtkTreeView 型の treeview で複数選択されている行を gtk_tree_view_get_selection() で取得し、 gtk_tree_selection_selected_foreach() で、それぞれを第2引数で指定した関数 cb_foreach() で処理します。
G_MODULE_EXPORT void cb_click (GtkAction *action) { GtkTreeView *treeview; GtkTreeSelection *selection; treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview1")); selection = gtk_tree_view_get_selection (treeview); gtk_tree_selection_selected_foreach (selection, cb_foreach, NULL); }
main() 関数では、 GTK+ の初期化、 GtkBuilder の初期化、signale の処理後、GtkTreeView の中身を登録します。次に、 gtk_tree_sortable_set_sort_column_id() でソートされるようにしています。
後は、GtkWindowを表示してメインループに入ります。
int main (int argc, char* argv[]) { GtkWindow *window; GError *error = NULL; gchar *fruit[] = {"banana", "apple", "orange", "grape", "strawberry", "peach", "melon", "marron", "papaya", "pear", "mango", NULL}; GtkTreeView *treeview; GtkTreeIter iter; GtkListStore *store; gint i; gtk_init (&argc, &argv); builder = gtk_builder_new (); gtk_builder_add_from_file (builder, "m_treeview.ui", &error); g_assert_no_error (error); gtk_builder_connect_signals (builder, NULL); treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview1")); store = GTK_LIST_STORE (gtk_tree_view_get_model (treeview)); for (i = 0; fruit[i] != NULL; i++) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, fruit[i], -1); } gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0, GTK_SORT_ASCENDING); window = GTK_WINDOW (gtk_builder_get_object (builder, "window1")); gtk_widget_show_all (GTK_WIDGET (window)); gtk_main(); return 0; }
Makefile とビルド・実行結果は以下の通りです。apple grape melon を選んで、fruit と書かれたラベルをクリックした結果です。
$ cat Makefile CFLAGS = -pthread -DGSEAL_ENABLE -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/gtk-3.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 LDFLAGS = -pthread -Wl,--export-dynamic -lgtk-3 -lgdk-3 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lpangocairo-1.0 -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lrt -lglib-2.0 all : m_treeview $ make cc -pthread -DGSEAL_ENABLE -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/gtk-3.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -pthread -Wl,--export-dynamic -lgtk-3 -lgdk-3 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lpangocairo-1.0 -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lrt -lglib-2.0 m_treeview.c -o m_treeview $ ./m_treeview apple grape melon
きちんと全て出力されました。
今回は、 gtk_tree_selection_selected_foreach() を使って作りましたが、これではうまく行かない場合もあるので、それについては別の機会で述べたいと思います。