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

在GtkPopover中嵌入GtkText后自动隐藏失效等问题求助

在GtkPopover中使用GtkText组件的问题解决方法

问题描述

在GtkPopover中嵌入GtkText组件时遇到两个异常:

  • 右键点击GtkText调用默认上下文菜单复制文本后,GtkPopover的自动隐藏功能失效,只能通过关闭父窗口来关闭弹窗;
  • 当父窗口被其他应用窗口遮挡时,GtkText组件仍会显示在所有窗口最上层。

环境:Linux Lite 7.0(Xfce桌面)

问题原因

  1. GtkText的默认上下文菜单是独立顶层窗口,会干扰Popover的自动隐藏逻辑——点击菜单时Popover判定焦点仍在关联窗口内,不会触发隐藏;菜单关闭后,Popover也不会主动重新检查隐藏条件。
  2. 原代码中Popover与按钮的关联方式错误,导致GtkText的窗口层级没有正确继承Popover的属性,出现层级异常。

解决方案代码

#include <gtk/gtk.h>

static void popup_cb (GtkButton *click, gpointer user_data)
{
  if (GTK_IS_POPOVER(user_data))
      gtk_popover_popup ((GtkPopover*)user_data);
}

static void on_text_menu_hide(GtkWidget *menu, gpointer popover)
{
  // 菜单关闭后强制Popover重新检查自动隐藏条件
  gtk_popover_set_autohide(GTK_POPOVER(popover), FALSE);
  gtk_popover_set_autohide(GTK_POPOVER(popover), TRUE);
}

static void activate (GtkApplication* app, gpointer user_data)
{
  GtkWidget *window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Window");
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

  GtkWidget *fixed = gtk_fixed_new ();
  gtk_window_set_child (GTK_WINDOW (window), fixed);

  GtkWidget *fsBtn = gtk_button_new ();
  gtk_fixed_put ((GtkFixed *)fixed, fsBtn, 10, 10);
  gtk_widget_set_size_request(fsBtn, 30, 30);

  GtkWidget *grid = gtk_grid_new ();
  gtk_grid_set_row_spacing ((GtkGrid *)grid, 15);
  gtk_grid_set_column_homogeneous ((GtkGrid *)grid, FALSE);

  // 正确关联Popover到目标按钮,确保层级继承正确
  GtkWidget *popover = gtk_popover_new ();
  gtk_popover_set_autohide ((GtkPopover *)popover, TRUE);
  gtk_popover_set_child ((GtkPopover*)popover, grid);
  gtk_popover_set_relative_to(GTK_POPOVER(popover), fsBtn);

  GtkWidget *preview_text = gtk_text_new();
  gtk_editable_set_text ((GtkEditable *)preview_text, "Right Click & Copy text from GtkText");
  gtk_widget_set_size_request(preview_text, 245, 50);
  gtk_grid_attach ((GtkGrid *)grid, preview_text, 0, 0, 1, 1);

  // 拦截默认菜单创建,手动绑定菜单关闭事件
  g_signal_connect(preview_text, "popup-menu", G_CALLBACK(+[](GtkWidget *text, gint x, gint y, gboolean trigger, gpointer user_data) -> gboolean {
    GtkWidget *menu = gtk_text_create_context_menu(GTK_TEXT(text));
    g_signal_connect(menu, "hide", G_CALLBACK(on_text_menu_hide), user_data);
    gtk_menu_popup_at_widget(GTK_MENU(menu), text, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    return TRUE; // 阻止默认菜单流程
  }), popover);

  g_signal_connect (fsBtn, "clicked", G_CALLBACK(popup_cb), popover);
  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;
}

修改说明

  1. 修复Popover关联方式:用gtk_popover_set_relative_to替代gtk_widget_set_parent,让Popover正确绑定到按钮,确保内部GtkText组件继承Popover的窗口层级,解决父窗口被遮挡时GtkText仍顶层显示的问题。
  2. 修复自动隐藏失效:拦截GtkText的popup-menu信号,手动创建上下文菜单并监听其hide事件。菜单关闭时,通过切换Popover的自动隐藏属性,强制它重新检查是否需要隐藏,恢复自动隐藏功能。

内容的提问来源于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 20:54:51