GTK4使用GtkColumnView最佳实践
gtk4丢弃很多gtk3的类,GtkColumnView是新版本的其中之一,今天就用GtkColumnView实现常用的操作。
以下示例代码实现了动态增加列表数据,一行用多个控件,双击响应事件,以及单选和多选处理逻辑
#define ELEM_NUM 2
#define G_UTF8(s) g_locale_to_utf8(s, -1, 0, 0, 0)
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)
{
if (n_press == 2) {
GtkColumnView* columnview = GTK_COLUMN_VIEW(user_data);
//单选/多选通用方法
GtkSelectionModel* selectionmodel = gtk_column_view_get_model(columnview);
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; 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));
}
}
}
}
//若单选可如此
GListStore* _liststore = G_LIST_STORE(gtk_single_selection_get_selected_item(GTK_SINGLE_SELECTION(selectionmodel)));
g_print("Double-clicked on item: \n");
for (int i = 0; i < ELEM_NUM; 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));
}
}
{
GListStore* liststore = G_LIST_STORE(gtk_single_selection_get_model(GTK_SINGLE_SELECTION(selectionmodel)));
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);
}
}
}
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);
GtkWidget* scrolledwindow = gtk_scrolled_window_new();
gtk_window_set_child(GTK_WINDOW(win), scrolledwindow);
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("bbb"),G_UTF8("ccc"),},{G_UTF8("bbb"),G_UTF8("ccc"),},},
{{G_UTF8("eee"),G_UTF8("fff"),}, {G_UTF8("vvv"),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);
}
//GtkTreeSelection;
GtkSelectionModel* selectionmodel = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(liststore)));
GtkWidget* columnview = gtk_column_view_new(selectionmodel);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolledwindow), columnview);
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);
gtk_column_view_column_set_expand(columnviewcolumn, TRUE);
gtk_column_view_column_set_resizable(columnviewcolumn, TRUE);
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));
{
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);
}
}
static void
activate(GtkApplication* app, gpointer user_data)
{
columnview_test(app);
return;
}