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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:14:52