You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 17:44:53