GTK4使用GtkColumnView最佳实践之三
GTK4使用GtkColumnView最佳实践之二
gtk4丢弃很多gtk3的类,GtkColumnView是新版本的其中之一,今天就用GtkColumnView实现常用的操作。
以下示例代码实现了动态增加列表数据,一行用多个控件,双击响应事件,以及单选和多选处理逻辑
新增:自定义过滤、同步更新行数显示
新增:列自适应优化、所有列支持自定义排序
#ifdef _MSC_VER #include <gdk/win32/gdkwin32.h> HWND gtk_window_get_nativehandle(GtkWidget* w) { return GDK_SURFACE_HWND(gtk_native_get_surface(gtk_widget_get_native(w))); } void gtk_window_set_position_center(GtkWidget* w) { RECT rc = { 0,0,0,0, }; HWND hwnd = gtk_window_get_nativehandle(w); RECT rcwin = { 0,0,0,0, }; SystemParametersInfo(SPI_GETWORKAREA, 0, &rcwin, 0); GetWindowRect(hwnd, &rc); MoveWindow(hwnd, (rcwin.right - (rc.right - rc.left)) / 2, (rcwin.bottom - (rc.bottom - rc.top)) / 2, rc.right - rc.left, rc.bottom - rc.top, FALSE); } #else #endif // _MSC_VER #define ELEM_NUM 2 #define G_UTF8(s) g_locale_to_utf8(s, -1, 0, 0, 0) GtkWidget* g_window = NULL; static void columnview_setup_listitem_cb(GtkListItemFactory* factory, GtkListItem* list_item, gpointer user_data) { int col = (int)user_data; //printf("columnview_setup_listitem_cb %d\n", col); GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); for (int i = 0; i < ELEM_NUM; i++) { GtkWidget* label = gtk_label_new(""); gtk_box_append(GTK_BOX(box), label); } gtk_list_item_set_child(list_item, box); } static void columnview_bind_listitem_cb(GtkListItemFactory* factory, GtkListItem* list_item, gpointer user_data) { int col = (int)user_data; //printf("columnview_bind_listitem_cb %d\n", col); GtkWidget* box = gtk_list_item_get_child(list_item); GListModel* listmodel = G_LIST_MODEL(gtk_list_item_get_item(list_item)); GtkStringList* stringlist = GTK_STRING_LIST(g_list_model_get_item(listmodel, col)); GtkWidget* label = gtk_widget_get_first_child(box); for (int i = 0; i < ELEM_NUM; i++) { gtk_label_set_label(GTK_LABEL(label), gtk_string_list_get_string(stringlist, i)); label = gtk_widget_get_next_sibling(label); } } static void on_columnview_list_item_double_click(GtkGestureClick* gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { g_print("n_press=%d\n", n_press); if (n_press == 2) { GtkColumnView* columnview = GTK_COLUMN_VIEW(user_data); } else if (n_press == 1) { } } static gboolean match_text(gpointer item, gpointer user_data) { GListStore* liststore = G_LIST_STORE(item); GtkWidget* searchentry = GTK_WIDGET(user_data); gboolean result = FALSE; for (int i = 0; (i < ELEM_NUM) && (result == FALSE); i++) { GtkStringList* stringlist = GTK_STRING_LIST(g_list_model_get_item(G_LIST_MODEL(liststore), i)); for (int j = 0; (j < ELEM_NUM) && (result == FALSE); j++) { const gchar* text = gtk_string_list_get_string(stringlist, j); const gchar* find = gtk_editable_get_text(GTK_EDITABLE(searchentry)); result = (strstr(text, find) != NULL); } } return result; } static void search_changed_cb(GtkSearchEntry* entry, GtkFilter* custom_filter) { gtk_filter_changed(custom_filter, GTK_FILTER_CHANGE_DIFFERENT); } static void update_title_cb(GtkFilterListModel* model, gpointer user_data) { guint total; char* title; guint pending; total = g_list_model_get_n_items(gtk_filter_list_model_get_model(model)); pending = gtk_filter_list_model_get_pending(model); title = g_strdup_printf(G_UTF8("GTK4列表例子(总行数:%d)"), g_list_model_get_n_items(G_LIST_MODEL(model))); //gtk_widget_set_visible(progress, pending != 0); //gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), total > 0 ? (total - pending) / (double)total : 0.); gtk_window_set_title(GTK_WINDOW(g_window), title); g_free(title); } static int compare_text(gconstpointer item1, gconstpointer item2, gpointer user_data) { int col = (int)user_data; GtkStringList* stringlist1 = GTK_STRING_LIST(g_list_model_get_item(G_LIST_MODEL(gpointer(item1)), col)); GtkStringList* stringlist2 = GTK_STRING_LIST(g_list_model_get_item(G_LIST_MODEL(gpointer(item2)), col)); return(strcmp(gtk_string_list_get_string(stringlist1, 0), gtk_string_list_get_string(stringlist2, 0))); } static void on_row_activated(GtkColumnView* column_view, guint position, gpointer user_data) { g_print("Activated row: %d\n", position); GtkSelectionModel* selectionmodel = gtk_column_view_get_model(column_view); //单选/多选通用方法 GtkBitset* selected_items = gtk_selection_model_get_selection(selectionmodel); if (selected_items) { guint value = 0; GtkBitsetIter iter = {}; for (gboolean b = gtk_bitset_iter_init_first(&iter, selected_items, &value); b == TRUE; b = gtk_bitset_iter_next(&iter, &value)) { value = gtk_bitset_iter_get_value(&iter); g_print("Selected item: %u\n", value); GListStore* _liststore = G_LIST_STORE(g_list_model_get_object(G_LIST_MODEL(selectionmodel), value)); for (int i = 0; i < ELEM_NUM + 1; i++) { GtkStringList* stringlist = GTK_STRING_LIST(g_list_model_get_item(G_LIST_MODEL(_liststore), i)); for (int j = 0; j < ELEM_NUM; j++) { g_print("%s\n", gtk_string_list_get_string(stringlist, j)); } } } } //若单选可如此 gpointer selecteditem = gtk_single_selection_get_selected_item(GTK_SINGLE_SELECTION(selectionmodel)); GListStore* _liststore = G_LIST_STORE(selecteditem); g_print("Double-clicked on item: \n"); for (int i = 0; i < ELEM_NUM + 1; i++) { GtkStringList* stringlist = GTK_STRING_LIST(g_list_model_get_item(G_LIST_MODEL(_liststore), i)); for (int j = 0; j < ELEM_NUM; j++) { g_print("%s\n", gtk_string_list_get_string(stringlist, j)); } } { GtkFilterListModel* filterlistmodel = GTK_FILTER_LIST_MODEL(gtk_single_selection_get_model(GTK_SINGLE_SELECTION(selectionmodel))); GtkSortListModel* sortlistmodel = GTK_SORT_LIST_MODEL(gtk_filter_list_model_get_model(filterlistmodel)); GListStore* liststore = G_LIST_STORE(gtk_sort_list_model_get_model(sortlistmodel)); int n_old = g_list_model_get_n_items(G_LIST_MODEL(liststore)); const char* listdata[][ELEM_NUM + 1][ELEM_NUM + 1] = { {{G_UTF8("ccc"),G_UTF8("ddd"),}, {G_UTF8("ddd"),G_UTF8("eee"),}, {G_UTF8("ddd"),G_UTF8("eee"),}, }, {{G_UTF8("ccc1"),G_UTF8("ddd1"),}, {G_UTF8("ddd1"),G_UTF8("eee1"),}, {G_UTF8("ddd1"),G_UTF8("eee1"),}, }, }; int n = sizeof(listdata) / sizeof(*listdata); printf("n_old=%d,%d\n", n_old, n); for (int i = 0; i < n; i++) { GListStore* _liststore = g_list_store_new(G_TYPE_OBJECT); for (int j = 0; j < ELEM_NUM + 1; j++) { printf("%d,%s,%s\n", i, listdata[i][j][0], listdata[i][j][1]); GtkStringList* stringlist = gtk_string_list_new(listdata[i][j]); //GtkStringList* stringlist = gtk_string_list_new(NULL); //for (int k = 0; k < ELEM_NUM; k++) //{ // gtk_string_list_append(_liststore, listdata[i][j][k]); //} g_list_store_append(_liststore, stringlist); } g_list_store_append(liststore, _liststore); } g_list_model_items_changed(G_LIST_MODEL(liststore), n_old - 1, 0, 0); update_title_cb(GTK_FILTER_LIST_MODEL(filterlistmodel), NULL); } } void columnview_test(GtkApplication* app) { GtkWidget* win = gtk_application_window_new(app); gtk_window_set_title(GTK_WINDOW(win), G_UTF8("GTK4列表例子")); gtk_window_set_default_size(GTK_WINDOW(win), 800, 600); g_window = win; GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_window_set_child(GTK_WINDOW(win), box); GtkWidget* searchentry = gtk_search_entry_new(); gtk_box_append(GTK_BOX(box), searchentry); gtk_search_entry_set_key_capture_widget(GTK_SEARCH_ENTRY(searchentry), win); GtkWidget* scrolledwindow = gtk_scrolled_window_new(); gtk_box_append(GTK_BOX(box), scrolledwindow); gtk_widget_set_vexpand(scrolledwindow, TRUE); GListStore* liststore = g_list_store_new(G_TYPE_OBJECT); const char* listdata[][ELEM_NUM + 1][ELEM_NUM + 1] = { {{G_UTF8("aaa"),G_UTF8("bbb"),}, {G_UTF8("uuu"),G_UTF8("ccc"),},{G_UTF8("ttt"),G_UTF8("ccc"),},}, {{G_UTF8("eee"),G_UTF8("fff"),}, {G_UTF8("ccc"),G_UTF8("bbb"),},{G_UTF8("vvv"),G_UTF8("bbb"),},}, }; int n = sizeof(listdata) / sizeof(*listdata); printf("n=%d\n", n); for (int i = 0; i < n; i++) { GListStore* _liststore = g_list_store_new(G_TYPE_OBJECT); for (int j = 0; j < ELEM_NUM + 1; j++) { printf("%d,%s,%s\n", i, listdata[i][j][0], listdata[i][j][1]); GtkStringList* stringlist = gtk_string_list_new(listdata[i][j]); //GtkStringList* stringlist = gtk_string_list_new(NULL); //for (int k = 0; k < ELEM_NUM; k++) //{ // gtk_string_list_append(_liststore, listdata[i][j][k]); //} g_list_store_append(_liststore, stringlist); } g_list_store_append(liststore, _liststore); } GtkTreeExpander; GtkWidget* columnview = gtk_column_view_new(NULL); gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolledwindow), columnview); //{ GtkSorter* sorter = gtk_column_view_get_sorter(GTK_COLUMN_VIEW(columnview)); GtkSortListModel* sortlistmodel = gtk_sort_list_model_new(G_LIST_MODEL(liststore), sorter); GtkFilter* customfilter = GTK_FILTER(gtk_custom_filter_new(match_text, g_object_ref(searchentry), g_object_unref)); GtkFilterListModel* filterlistmodel = gtk_filter_list_model_new(G_LIST_MODEL(sortlistmodel), customfilter); g_signal_connect(filterlistmodel, "items-changed", G_CALLBACK(update_title_cb), NULL); g_signal_connect(filterlistmodel, "notify::pending", G_CALLBACK(update_title_cb), NULL); g_signal_connect(searchentry, "search-changed", G_CALLBACK(search_changed_cb), customfilter); GtkSingleSelection* singleselection = gtk_single_selection_new(G_LIST_MODEL(filterlistmodel)); gtk_single_selection_set_autoselect(singleselection, TRUE); gtk_single_selection_set_can_unselect(singleselection, TRUE); GtkSelectionModel* selectionmodel = GTK_SELECTION_MODEL(singleselection); gtk_column_view_set_model(GTK_COLUMN_VIEW(columnview), selectionmodel); //} g_signal_connect(columnview, "activate", G_CALLBACK(on_row_activated), NULL); const char* column_names[] = { G_UTF8("姓名"),G_UTF8("性别"),G_UTF8("备注"), }; for (int i = 0; i < sizeof(column_names) / sizeof(*column_names); i++) { GtkListItemFactory* factory = gtk_signal_list_item_factory_new(); g_signal_connect(factory, "setup", G_CALLBACK(columnview_setup_listitem_cb), (gpointer)i); g_signal_connect(factory, "bind", G_CALLBACK(columnview_bind_listitem_cb), (gpointer)i); GtkColumnViewColumn* columnviewcolumn = gtk_column_view_column_new(column_names[i], factory); if (i == (sizeof(column_names) / sizeof(*column_names) - 1)) { gtk_column_view_column_set_expand(columnviewcolumn, TRUE); } gtk_column_view_column_set_resizable(columnviewcolumn, TRUE); { GtkSorter* sorter = GTK_SORTER(gtk_custom_sorter_new(compare_text, (gpointer)i, NULL)); gtk_column_view_column_set_sorter(columnviewcolumn, sorter); } gtk_column_view_append_column(GTK_COLUMN_VIEW(columnview), columnviewcolumn); } gtk_column_view_set_show_column_separators(GTK_COLUMN_VIEW(columnview), TRUE); gtk_column_view_set_show_row_separators(GTK_COLUMN_VIEW(columnview), TRUE); GtkGesture* gesture = gtk_gesture_click_new(); gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), GDK_BUTTON_PRIMARY); gtk_widget_add_controller(columnview, GTK_EVENT_CONTROLLER(gesture)); g_signal_connect(gesture, "pressed", G_CALLBACK(on_columnview_list_item_double_click), columnview); gtk_window_present(GTK_WINDOW(win)); gtk_window_set_position_center(win); { int n_old = g_list_model_get_n_items(G_LIST_MODEL(liststore)); printf("n_old=%d,%d\n", n_old, n); for (int i = 0; i < n; i++) { GListStore* _liststore = g_list_store_new(G_TYPE_OBJECT); for (int j = 0; j < ELEM_NUM + 1; j++) { printf("%d,%s,%s\n", i, listdata[i][j][0], listdata[i][j][1]); GtkStringList* stringlist = gtk_string_list_new(listdata[i][j]); //GtkStringList* stringlist = gtk_string_list_new(NULL); //for (int k = 0; k < ELEM_NUM; k++) //{ // gtk_string_list_append(_liststore, listdata[i][j][k]); //} g_list_store_append(_liststore, stringlist); } g_list_store_append(liststore, _liststore); } g_list_model_items_changed(G_LIST_MODEL(liststore), n_old - 1, 0, 0); update_title_cb(filterlistmodel, NULL); } }
收藏的用户(0)
X
正在加载信息~
2
最新回复 (0)