#include #include static GtkWidget *main_window = NULL; static void sum_selected_items(GtkIconView *icon_view, gpointer user_data) { GtkLabel *label; GtkTreeModel *model; GList *list; GList *cur; gint sum = 0; gchar *str; gchar buf[64]; label = g_object_get_data(G_OBJECT(icon_view), "label"); list = gtk_icon_view_get_selected_items(icon_view); if (list == NULL) { gtk_label_set_text(label, ""); return; } model = gtk_icon_view_get_model(icon_view); for (cur = g_list_first(list); cur != NULL; cur = g_list_next(cur)) { GtkTreeIter iter; gint num; if (gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data) == TRUE) { gtk_tree_model_get(model, &iter, 0, &str, -1); sum += atoi(str); g_free(str); } gtk_tree_path_free((GtkTreePath *)cur->data); } g_list_free(list); snprintf(buf, sizeof(buf), "%d", sum); gtk_label_set_text(label, buf); } static void add_model_data(GtkButton *button, gpointer user_data) { static gint serial_num = 0; GtkIconView *icon_view = GTK_ICON_VIEW(user_data); GtkTreeModel *model; GtkTreeModel *child_model; GtkTreeIter iter; gchar buf[64]; model = gtk_icon_view_get_model(icon_view); child_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); snprintf(buf, sizeof(buf), "%d", ++serial_num); gtk_list_store_append(GTK_LIST_STORE(child_model), &iter); gtk_list_store_set(GTK_LIST_STORE(child_model), &iter, 0, buf, -1); } static void block_changed_signal(GObject *instance) { GList *list; GList *cur; list = g_object_get_data(G_OBJECT(instance), "icon_view_list"); for (cur = g_list_first(list); cur != NULL; cur = g_list_next(cur)) { GtkIconView *icon_view = cur->data; gulong handler_id; handler_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(icon_view), "changed_handler_id")); g_signal_handler_block(G_OBJECT(icon_view), handler_id); } } static void unblock_changed_signal(GObject *instance) { GList *list; GList *cur; list = g_object_get_data(G_OBJECT(instance), "icon_view_list"); for (cur = g_list_first(list); cur != NULL; cur = g_list_next(cur)) { GtkIconView *icon_view = cur->data; gulong handler_id; handler_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(icon_view), "changed_handler_id")); g_signal_handler_unblock(G_OBJECT(icon_view), handler_id); /* selection-changedシグナルをブロックしていた間の変更を反映させる */ sum_selected_items(icon_view, NULL); } } static void remove_model_data(GtkButton *button, gpointer user_data) { GtkIconView *icon_view = GTK_ICON_VIEW(user_data); GtkTreeModel *model; GtkTreeModel *child_model; GList *list; GList *reference_list; GList *cur; /* 選択されているアイテムのパスを取得する */ /* パスはツリーモデルソートのもの */ model = gtk_icon_view_get_model(icon_view); list = gtk_icon_view_get_selected_items(icon_view); child_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); /* 最初にパスからリファレンスを作成する */ /* データの削除を行なうと取得済みのパスが(大抵の場合)無効になる */ reference_list = NULL; for (cur = g_list_first(list); cur != NULL; cur = g_list_next(cur)) { GtkTreePath *child_path; GtkTreeRowReference *child_reference; /* ツリーモデルソートのパスをツリーモデルのパスに変換する */ child_path = gtk_tree_model_sort_convert_path_to_child_path(GTK_TREE_MODEL_SORT(model), (GtkTreePath *)cur->data); child_reference = gtk_tree_row_reference_new(child_model, child_path); reference_list = g_list_append(reference_list, child_reference); gtk_tree_path_free(child_path); gtk_tree_path_free((GtkTreePath *)cur->data); } g_list_free(list); /* GtkIconViewのselection-changedシグナルを一時的にブロックする */ block_changed_signal(G_OBJECT(child_model)); /* リファレンスをパスに戻して削除 */ for (cur = g_list_first(reference_list); cur != NULL; cur = g_list_next(cur)) { GtkTreePath *tree_path; GtkTreeIter iter; tree_path = gtk_tree_row_reference_get_path((GtkTreeRowReference *)cur->data); gtk_tree_model_get_iter(child_model, &iter, tree_path); /* 削除 */ gtk_list_store_remove(GTK_LIST_STORE(child_model), &iter); gtk_tree_path_free(tree_path); gtk_tree_row_reference_free((GtkTreeRowReference *)cur->data); } g_list_free(reference_list); /* selection-changedシグナルのブロックを解除する */ unblock_changed_signal(G_OBJECT(child_model)); } static GtkWidget *create_window(GtkWidget *icon_view, gint window_id) { GtkWidget *window; gchar *title; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *button; GtkWidget *label; GtkWidget *scrolled_window; GtkTreeModel *model; GtkTreeModel *child_model; gulong changed_handler_id; GList *list; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); title = g_strdup_printf("GtkTreeModelSort #%d", window_id); gtk_window_set_title(GTK_WINDOW(window), title); g_free(title); vbox = gtk_vbox_new(FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* データ追加ボタン */ button = gtk_button_new_from_stock(GTK_STOCK_ADD); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(add_model_data), icon_view); /* データ削除ボタン */ button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(remove_model_data), icon_view); /* ラベル */ label = gtk_label_new(""); gtk_box_pack_end(GTK_BOX(hbox), label, TRUE, TRUE, 0); scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_set_size_request(scrolled_window, 400, 300); gtk_container_add(GTK_CONTAINER(scrolled_window), icon_view); gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); /* * selection-changedシグナルハンドラを登録する。 * 後で同じchild_modelを使用しているicon viewのselection-changedシグナルをブロック出来るように * child_modelにicon viewのリストを、icon viewにシグナルハンドラIDを登録する。 * changedハンドラ内で使用するlabelも同様に登録しておく。 */ changed_handler_id = g_signal_connect(G_OBJECT(icon_view), "selection-changed", G_CALLBACK(sum_selected_items), NULL); g_object_set_data(G_OBJECT(icon_view), "changed_handler_id", GUINT_TO_POINTER(changed_handler_id)); g_object_set_data(G_OBJECT(icon_view), "label", label); model = gtk_icon_view_get_model(GTK_ICON_VIEW(icon_view)); child_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); list = g_object_get_data(G_OBJECT(child_model), "icon_view_list"); list = g_list_append(list, icon_view); g_object_set_data(G_OBJECT(child_model), "icon_view_list", list); gtk_widget_show_all(window); return window; } static void create_icon_view_window(GtkButton *button, gpointer user_data) { static gint window_id = 0; GtkTreeModel *child_model = GTK_TREE_MODEL(user_data); GtkTreeModel *model; GtkWidget *icon_view; /* ソート用のモデルを作成してアイコンビューにセットする */ icon_view = gtk_icon_view_new(); model = gtk_tree_model_sort_new_with_model(child_model); gtk_icon_view_set_model(GTK_ICON_VIEW(icon_view), model); gtk_icon_view_set_text_column(GTK_ICON_VIEW(icon_view), 0); gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(icon_view), -1); gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(icon_view), GTK_SELECTION_MULTIPLE); /* ウィンドウを作成する毎にソート順を変更する */ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), 0, ((window_id & 1) == 0 ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING)); /* ウィンドウ作成 */ create_window(icon_view, ++window_id); } int main(int argc, char **argv) { GtkListStore *store; GtkWidget *hbox; GtkWidget *button; srand((unsigned)time(NULL)); gtk_init(&argc, &argv); /* 空のリストストアを作成する */ store = gtk_list_store_new(1, G_TYPE_STRING); g_object_set_data(G_OBJECT(store), "icon_view_list", NULL); main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(main_window), "GtkTreeModelSort"); g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(gtk_main_quit), NULL); hbox = gtk_hbox_new(TRUE, 10); button = gtk_button_new_with_label("Create Window"); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(create_icon_view_window), store); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(main_window), hbox); gtk_container_set_border_width(GTK_CONTAINER(main_window), 10); gtk_widget_show_all(main_window); gtk_main(); return 0; }