GTK4使用GtkColumnView最佳实践之三

xingyun86 5月前 725

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)
查看全部
全部楼主
返回