GTK4 ColumnView多列排序功能添加失败的技术求助
GTK4 ColumnView 多列排序正确实现方案
核心错误原因
出现g_list_model_get_n_items断言错误,大概率是未用GtkSortListModel包装原始数据模型,直接将GListStore等原始模型绑定到ColumnView导致的。GTK4的排序功能依赖GtkSortListModel作为中间层,负责处理排序逻辑,直接操作原始模型会触发无效访问断言。
分步实现代码
1. 定义数据结构(需注册为GObject类型)
排序需要基于GObject的类型系统,因此自定义数据需继承GObject:
#include <gtk/gtk.h> typedef struct { GObject parent; gchar *name; gint age; } Person; typedef struct { GObjectClass parent_class; } PersonClass; GType person_get_type(void); G_DEFINE_TYPE(Person, person, G_TYPE_OBJECT) static void person_init(Person *self) {} static void person_dispose(GObject *gobject) { Person *self = PERSON(gobject); g_free(self->name); G_OBJECT_CLASS(person_parent_class)->dispose(gobject); } static void person_class_init(PersonClass *klass) { G_OBJECT_CLASS(klass)->dispose = person_dispose; } Person* person_new(const gchar *name, gint age) { Person *self = g_object_new(PERSON_TYPE, NULL); self->name = g_strdup(name); self->age = age; return self; }
2. 创建排序模型并绑定原始数据
必须用GtkSortListModel包装原始GListStore,并设置排序比较函数:
int main(int argc, char *argv[]) { gtk_init(&argc, &argv); // 创建窗口与ColumnView GtkWidget *window = gtk_window_new(); GtkWidget *column_view = gtk_column_view_new(NULL); gtk_window_set_child(GTK_WINDOW(window), column_view); gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); // 1. 创建原始数据模型 GListStore *store = g_list_store_new(PERSON_TYPE); g_list_store_append(store, person_new("Alice", 30)); g_list_store_append(store, person_new("Bob", 25)); g_list_store_append(store, person_new("Charlie", 35)); // 2. 创建排序模型(核心:包装原始模型) GtkSortListModel *sort_model = gtk_sort_list_model_new(G_LIST_MODEL(store), NULL); // 定义排序比较函数 static gint compare_name(gconstpointer a, gconstpointer b, gpointer data) { Person *p1 = PERSON(a); Person *p2 = PERSON(b); return g_strcmp0(p1->name, p2->name); } static gint compare_age(gconstpointer a, gconstpointer b, gpointer data) { Person *p1 = PERSON(a); Person *p2 = PERSON(b); return p1->age - p2->age; } // 3. 设置默认排序(按年龄升序) GtkSortDescriptor *age_desc = gtk_sort_descriptor_new(NULL, compare_age, GTK_SORT_ASCENDING, NULL); gtk_sort_list_model_set_sort_descriptors(sort_model, g_list_append(NULL, age_desc));
3. 配置列与排序触发
给每个ColumnViewColumn绑定对应的排序描述符,实现点击列头切换排序:
// 创建列表项工厂(用于渲染数据) static void setup_label(GtkSignalListItemFactory *factory, GtkListItem *item) { gtk_list_item_set_child(item, gtk_label_new(NULL)); } static void bind_name(GtkSignalListItemFactory *factory, GtkListItem *item) { Person *p = gtk_list_item_get_item(item); gtk_label_set_text(GTK_LABEL(gtk_list_item_get_child(item)), p->name); } static void bind_age(GtkSignalListItemFactory *factory, GtkListItem *item) { Person *p = gtk_list_item_get_item(item); gchar *age_str = g_strdup_printf("%d", p->age); gtk_label_set_text(GTK_LABEL(gtk_list_item_get_child(item)), age_str); g_free(age_str); } // 名字列 GtkListItemFactory *name_factory = gtk_signal_list_item_factory_new(); g_signal_connect(name_factory, "setup", G_CALLBACK(setup_label), NULL); g_signal_connect(name_factory, "bind", G_CALLBACK(bind_name), NULL); GtkColumnViewColumn *name_col = gtk_column_view_column_new("Name", name_factory); GtkSortDescriptor *name_desc = gtk_sort_descriptor_new(NULL, compare_name, GTK_SORT_ASCENDING, NULL); gtk_column_view_column_set_sort_descriptor(name_col, name_desc); gtk_column_view_append_column(GTK_COLUMN_VIEW(column_view), name_col); // 年龄列 GtkListItemFactory *age_factory = gtk_signal_list_item_factory_new(); g_signal_connect(age_factory, "setup", G_CALLBACK(setup_label), NULL); g_signal_connect(age_factory, "bind", G_CALLBACK(bind_age), NULL); GtkColumnViewColumn *age_col = gtk_column_view_column_new("Age", age_factory); gtk_column_view_column_set_sort_descriptor(age_col, age_desc); gtk_column_view_append_column(GTK_COLUMN_VIEW(column_view), age_col); // 4. 将排序模型绑定到ColumnView(关键:不能直接绑定原始store) gtk_column_view_set_model(GTK_COLUMN_VIEW(column_view), G_LIST_MODEL(sort_model)); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_present(GTK_WINDOW(window)); gtk_main(); g_object_unref(store); return 0; }
关键注意事项
- 禁止直接将
GListStore等原始模型绑定到ColumnView,必须通过GtkSortListModel中转 - 确保
GtkSortListModel的source模型不为空且未被提前释放 - 比较函数中必须正确转换数据类型,避免空指针访问
- 每个可排序的列必须设置
sort_descriptor,否则点击列头会无响应或触发错误
内容的提问来源于stack exchange,提问作者dhugh
相关产品推荐
相关产品推荐

