如何让GListStore在GTK4的GtkColumnView指定列追加字符串?
解决GtkColumnView多列数据绑定问题
你当前的问题核心在于:GtkColumnView的每一行对应模型里的一个条目,每个条目需要包含该行所有列的数据,而你现在用GtkStringObject只能存单个字符串,两次g_list_store_append会生成两行,而不是同一行的两列。要实现多列,需要自定义一个包含多字段的GObject类,让模型存储这个自定义对象,再让不同列绑定对象的不同属性。
步骤1:定义自定义GObject类
创建一个包含两个字符串属性的类,比如FileInfo,用来存储文件名和格式:
#include <gtk/gtk.h> #define TYPE_FILE_INFO (file_info_get_type()) G_DECLARE_FINAL_TYPE(FileInfo, file_info, FILE, INFO, GObject) struct _FileInfo { GObject parent_instance; char *filename; char *format; }; G_DEFINE_TYPE(FileInfo, file_info, G_TYPE_OBJECT) enum { PROP_0, PROP_FILENAME, PROP_FORMAT, N_PROPS }; static GParamSpec *properties[N_PROPS]; static void file_info_dispose(GObject *object) { FileInfo *info = FILE_INFO(object); g_free(info->filename); g_free(info->format); G_OBJECT_CLASS(file_info_parent_class)->dispose(object); } static void file_info_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { FileInfo *info = FILE_INFO(object); switch (prop_id) { case PROP_FILENAME: g_value_set_string(value, info->filename); break; case PROP_FORMAT: g_value_set_string(value, info->format); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } } static void file_info_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FileInfo *info = FILE_INFO(object); switch (prop_id) { case PROP_FILENAME: g_free(info->filename); info->filename = g_value_dup_string(value); break; case PROP_FORMAT: g_free(info->format); info->format = g_value_dup_string(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } } static void file_info_class_init(FileInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->dispose = file_info_dispose; object_class->get_property = file_info_get_property; object_class->set_property = file_info_set_property; properties[PROP_FILENAME] = g_param_spec_string("filename", "Filename", "The file name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_FORMAT] = g_param_spec_string("format", "Format", "The file format", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties(object_class, N_PROPS, properties); } static void file_info_init(FileInfo *info) { } // 快捷创建函数 FileInfo * file_info_new(const char *filename, const char *format) { return g_object_new(TYPE_FILE_INFO, "filename", filename, "format", format, NULL); }
步骤2:修改模型和列视图代码
把原来用GtkStringObject的地方换成自定义的FileInfo,并为不同列设置对应的绑定回调:
int main(int argc, char *argv[]) { gtk_init(); // 创建存储FileInfo的模型 GListStore *store = g_list_store_new(TYPE_FILE_INFO); GtkSelectionModel *selection = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(store))); GtkWidget *view = gtk_column_view_new(selection); // 第一列:文件名 GtkListItemFactory *factory_col1 = gtk_signal_list_item_factory_new(); g_signal_connect(factory_col1, "setup", G_CALLBACK(cb_setup_label), NULL); g_signal_connect(factory_col1, "bind", G_CALLBACK(cb_bind_filename), NULL); GtkColumnViewColumn *column1 = gtk_column_view_column_new("Archivo", factory_col1); gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column1); // 第二列:格式 GtkListItemFactory *factory_col2 = gtk_signal_list_item_factory_new(); g_signal_connect(factory_col2, "setup", G_CALLBACK(cb_setup_label), NULL); g_signal_connect(factory_col2, "bind", G_CALLBACK(cb_bind_format), NULL); GtkColumnViewColumn *column2 = gtk_column_view_column_new("Formato", factory_col2); gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column2); // 添加一行数据(包含两列内容) FileInfo *info = file_info_new("str_for_col1", "str_for_col2"); g_list_store_append(store, info); g_object_unref(info); // 模型会持有引用,这里可以释放 // 后续窗口代码 GtkWidget *window = gtk_window_new(); gtk_window_set_child(GTK_WINDOW(window), view); gtk_window_present(GTK_WINDOW(window)); gtk_main(); return 0; } // 通用的setup回调,创建label void cb_setup_label(GtkSignalListItemFactory *self, GtkListItem *list_item, gpointer user_data) { GtkWidget *label = gtk_label_new(""); gtk_list_item_set_child(list_item, label); } // 绑定文件名属性 void cb_bind_filename(GtkSignalListItemFactory *self, GtkListItem *list_item, gpointer user_data) { FileInfo *info = FILE_INFO(gtk_list_item_get_item(list_item)); GtkWidget *label = gtk_list_item_get_child(list_item); gtk_label_set_text(GTK_LABEL(label), info->filename); } // 绑定格式属性 void cb_bind_format(GtkSignalListItemFactory *self, GtkListItem *list_item, gpointer user_data) { FileInfo *info = FILE_INFO(gtk_list_item_get_item(list_item)); GtkWidget *label = gtk_list_item_get_child(list_item); gtk_label_set_text(GTK_LABEL(label), info->format); }
关键说明
- 自定义
FileInfo类包含了一行所需的所有数据,模型里的每个条目对应一行,而不是一列。 - 每列使用独立的工厂(也可以给工厂传递用户数据区分列),绑定回调时读取对应属性。
- 如果需要动态修改数据,可以给
FileInfo添加notify信号,或者直接修改属性后调用g_object_notify,GtkColumnView会自动更新视图。
内容的提问来源于stack exchange,提问作者Joel
相关产品推荐
相关产品推荐

