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

Gtk4实现右键上下文菜单及窗口销毁警告修复

Gtk4 右键上下文菜单实现(解决「Finalizing GtkApplicationWindow仍有子控件」警告)

问题根源

出现该警告的核心原因是:Popover未被正确纳入窗口的控件生命周期管理链——要么父控件设置错误,要么未将其挂载到窗口内的容器控件上,导致窗口销毁时无法自动回收Popover资源。

正确实现方案

以下以C语言和Python为例,给出无警告的右键菜单实现,核心要点是使用GtkPopoverMenu(专为菜单场景优化)、正确绑定父控件、用Gtk4官方替代函数弹出菜单。

C语言示例

#include <gtk/gtk.h>

static void on_right_click(GtkGestureClick *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) {
    GtkWidget *popover = GTK_WIDGET(user_data);
    // Gtk4官方替代gtk_menu_popup_at_pointer的弹出函数
    gtk_popover_popup_at_pointer(GTK_POPOVER(popover), NULL);
}

static void activate(GtkApplication *app, gpointer user_data) {
    GtkWidget *window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Gtk4 右键菜单");
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);

    // 创建主容器,作为Popover的父控件(关键:让Popover纳入窗口控件树)
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_window_set_child(GTK_WINDOW(window), box);

    // 构建菜单模型
    GMenu *menu = g_menu_new();
    g_menu_append(menu, "复制", "app.copy");
    g_menu_append(menu, "粘贴", "app.paste");
    g_menu_append(menu, "删除", "app.delete");

    // 创建PopoverMenu并绑定父控件
    GtkWidget *popover = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
    gtk_widget_set_parent(popover, box);

    // 绑定右键手势到主容器,覆盖整个窗口区域
    GtkGesture *gesture = gtk_gesture_click_new();
    gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), GDK_BUTTON_SECONDARY);
    g_signal_connect(gesture, "pressed", G_CALLBACK(on_right_click), popover);
    gtk_widget_add_controller(box, GTK_EVENT_CONTROLLER(gesture));

    gtk_widget_show(window);
}

int main(int argc, char **argv) {
    GtkApplication *app = gtk_application_new("org.example.ContextMenu", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);

    // 注册菜单对应的动作
    g_action_map_add_action_entries(G_ACTION_MAP(app),
        (const GActionEntry[]) {
            { "copy", NULL, NULL, NULL, NULL },
            { "paste", NULL, NULL, NULL, NULL },
            { "delete", NULL, NULL, NULL, NULL }
        },
        3);

    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}

Python语言示例

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio

class AppWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app, title="Gtk4 右键菜单")
        self.set_default_size(400, 300)

        # 主容器,作为Popover的父控件
        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.set_child(self.box)

        # 构建菜单模型
        menu = Gio.Menu()
        menu.append("复制", "app.copy")
        menu.append("粘贴", "app.paste")
        menu.append("删除", "app.delete")

        # 创建PopoverMenu并绑定父控件
        self.popover = Gtk.PopoverMenu.new_from_model(menu)
        self.popover.set_parent(self.box)

        # 绑定右键手势
        gesture = Gtk.GestureClick()
        gesture.set_button(Gdk.BUTTON_SECONDARY)
        gesture.connect("pressed", self.on_right_click)
        self.box.add_controller(gesture)

    def on_right_click(self, gesture, n_press, x, y):
        self.popover.popup_at_pointer(None)

class MyApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="org.example.ContextMenu")

    def do_activate(self):
        win = AppWindow(self)
        win.present()

    def do_startup(self):
        Gtk.Application.do_startup(self)
        # 注册菜单动作
        self.add_action(Gio.SimpleAction.new("copy", None))
        self.add_action(Gio.SimpleAction.new("paste", None))
        self.add_action(Gio.SimpleAction.new("delete", None))

if __name__ == "__main__":
    app = MyApp()
    app.run(None)

关键修正点

  1. 正确设置Popover父控件:将Popover挂载到窗口内的容器(如GtkBox)而非直接绑定到GtkApplicationWindow,确保窗口销毁时容器自动回收所有子控件。
  2. 使用GtkPopoverMenu:它是Gtk4专为菜单场景设计的控件,配合GMenu模型更简洁,生命周期管理更规范。
  3. 官方弹出函数:用gtk_popover_popup_at_pointer替代Gtk3的gtk_menu_popup_at_pointer,适配Gtk4的API规范。

内容的提问来源于stack exchange,提问作者dibyendu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:33:23