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() を使って作りましたが、これではうまく行かない場合もあるので、それについては別の機会で述べたいと思います。