如何在GtkStackSwitcher页面中添加带关闭图标的GtkLabel?
在GTK4的GtkStackSwitcher中为页面添加自定义标签与关闭按钮
问题描述
我正在使用GTK4的GtkStackSwitcher与GtkStack组件,想要在GtkStackSwitcher的每个页面项中同时显示标签文本和关闭图标/按钮,但目前只能设置页面标题,无法实现两者共存。以下是我的演示代码:
#include <gtk/gtk.h> static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window; GtkWidget *switcher; GtkWidget *stack; GtkWidget *box; GtkWidget *widget; window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Window"); gtk_window_set_default_size (GTK_WINDOW (window), 100, 200); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); switcher = gtk_stack_switcher_new (); gtk_box_append (GTK_BOX (box), switcher); stack = gtk_stack_new (); gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE); gtk_stack_switcher_set_stack ((GtkStackSwitcher *)switcher, GTK_STACK (stack)); gtk_widget_set_hexpand (stack, TRUE); gtk_box_append (GTK_BOX (box), stack); /**make box with label and close icon or exit button**/ GtkWidget *pBox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); GtkWidget *label = gtk_label_new ("Unlimited"); GtkWidget *c_btn = gtk_image_new_from_icon_name ("window-close-symbolic"); gtk_image_set_icon_size (GTK_IMAGE (c_btn), GTK_ICON_SIZE_INHERIT); /*or use button */ //GtkWidget *c_btn = gtk_button_new_with_label("X"); gtk_box_append ((GtkBox *)pBox, label); gtk_box_append ((GtkBox *)pBox, c_btn); /**add page**/ widget = gtk_image_new_from_icon_name ("org.gtk.Demo4"); gtk_widget_add_css_class (widget, "icon-dropshadow"); gtk_image_set_pixel_size (GTK_IMAGE (widget), 256); gtk_stack_add_named (GTK_STACK (stack), widget, "page1"); g_object_set (gtk_stack_get_page (GTK_STACK (stack), widget), "title", "page1", NULL); widget = gtk_label_new ("Welcome"); gtk_stack_add_named (GTK_STACK (stack), widget, "page2"); g_object_set (gtk_stack_get_page (GTK_STACK (stack), widget), "title", "page2", NULL); /*HOW TO ADD the pBox Widget on GtkStackPage? */ gtk_window_set_child (GTK_WINDOW (window), box); gtk_window_present (GTK_WINDOW (window)); } int main (int argc, char **argv) { GtkApplication *app; int status; #if GLIB_CHECK_VERSION(2, 74, 0) app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); #else app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); #endif g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }
解决方案
要实现自定义GtkStackSwitcher的页面项内容,需使用gtk_stack_switcher_set_child_func()函数定义每个页面项的UI结构,替代默认的标题文本。以下是修改后的完整代码:
#include <gtk/gtk.h> // 自定义StackSwitcher项的创建回调 static void create_switcher_child (GtkStackSwitcher *switcher, GtkStackPage *page, GtkWidget *child, gpointer user_data) { // 创建水平容器,用于放置标签和关闭按钮 GtkWidget *item_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); // 创建页面标签,使用StackPage的title属性 GtkWidget *label = gtk_label_new (gtk_stack_page_get_title (page)); // 创建关闭按钮,使用系统图标 GtkWidget *close_btn = gtk_button_new_from_icon_name ("window-close-symbolic"); // 设置按钮为扁平样式,贴合切换器视觉风格 gtk_widget_add_css_class (close_btn, "flat"); // 调整图标大小 gtk_image_set_icon_size (GTK_IMAGE (gtk_button_get_child (GTK_BUTTON (close_btn))), GTK_ICON_SIZE_SMALL_TOOLBAR); // 绑定关闭按钮点击事件:移除对应页面 g_signal_connect_swapped (close_btn, "clicked", G_CALLBACK (gtk_stack_remove), gtk_stack_page_get_stack (page), page); // 将标签和按钮添加到容器 gtk_box_append (GTK_BOX (item_box), label); gtk_box_append (GTK_BOX (item_box), close_btn); // 将自定义容器设置为当前页面的切换项 gtk_stack_switcher_set_child (switcher, page, item_box); } static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window; GtkWidget *switcher; GtkWidget *stack; GtkWidget *box; GtkWidget *widget; window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Window"); gtk_window_set_default_size (GTK_WINDOW (window), 400, 300); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); switcher = gtk_stack_switcher_new (); gtk_box_append (GTK_BOX (box), switcher); stack = gtk_stack_new (); gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE); gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (stack)); gtk_widget_set_hexpand (stack, TRUE); gtk_widget_set_vexpand (stack, TRUE); gtk_box_append (GTK_BOX (box), stack); // 设置自定义切换项的创建回调 gtk_stack_switcher_set_child_func (GTK_STACK_SWITCHER (switcher), create_switcher_child, NULL, NULL); /**添加页面**/ widget = gtk_image_new_from_icon_name ("org.gtk.Demo4"); gtk_widget_add_css_class (widget, "icon-dropshadow"); gtk_image_set_pixel_size (GTK_IMAGE (widget), 256); gtk_stack_add_named (GTK_STACK (stack), widget, "page1"); g_object_set (gtk_stack_get_page (GTK_STACK (stack), widget), "title", "page1", NULL); widget = gtk_label_new ("Welcome"); gtk_stack_add_named (GTK_STACK (stack), widget, "page2"); g_object_set (gtk_stack_get_page (GTK_STACK (stack), widget), "title", "page2", NULL); gtk_window_set_child (GTK_WINDOW (window), box); gtk_window_present (GTK_WINDOW (window)); } int main (int argc, char **argv) { GtkApplication *app; int status; #if GLIB_CHECK_VERSION(2, 74, 0) app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); #else app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); #endif g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }
关键说明
- 自定义切换项回调:
create_switcher_child函数会为每个GtkStackPage生成自定义的UI结构,这里用水平GtkBox组合标签和关闭按钮,替代默认的纯文本标题。 - 按钮样式优化:给关闭按钮添加
flat样式类,去除默认按钮的边框和背景,让它更贴合GtkStackSwitcher的视觉风格。 - 关闭逻辑实现:通过
g_signal_connect_swapped将关闭按钮的点击事件绑定到gtk_stack_remove,点击后直接移除对应的页面。 - 绑定回调:在创建
GtkStackSwitcher后,调用gtk_stack_switcher_set_child_func将自定义回调绑定到切换器上,确保每个页面都使用自定义的切换项。
内容的提问来源于stack exchange,提问作者dibyendu
相关产品推荐
相关产品推荐

