当菜单栏被隐藏时,加速器停止响应



我有一个基于 glade 的 gtk3 用户界面,我为几个菜单项设置了加速器字段。我不确定 GtkBuilder 在加载 glade 文件时究竟在幕后做了什么(使用全局 GtkAccelGroup?),但最终结果是,当我隐藏菜单栏时,加速器快捷方式停止工作。

我想知道是否有办法让加速器工作,即使菜单不可见,同时仍然尽可能多地坚持空地。

也许您可以尝试将加速器不粘在菜单上,而是在您的应用程序中更高一层,例如窗口?在我自己的应用程序中,我是这样做的。

accel_group = gtk_accel_group_new ();
gtk_window_add_accel_group (GTK_WINDOW (pad), accel_group);
pad->priv->menu = menu_get_popup_no_highlight (pad, accel_group);
pad->priv->highlight_menu = menu_get_popup_highlight (pad, accel_group);
gtk_accel_group_connect (accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0, g_cclosure_new_swap (G_CALLBACK (xpad_app_quit), pad, NULL));

这两个菜单分配有自己的加速器,即使不可见,这些加速器也能正常工作。

这对你有帮助吗?

这是我对 xournalpp 的解决方案,它遍历菜单栏并将每个加速器重新绑定到主窗口:

页眉

class MainWindow: public GladeGui {
public:
   void rebindMenubarAccelerators();
private:
    static void rebindAcceleratorsMenuItem(GtkWidget* widget, gpointer user_data);
    static void rebindAcceleratorsSubMenu(GtkWidget* widget, gpointer user_data);
    static gboolean isKeyForClosure(GtkAccelKey* key, GClosure* closure, gpointer data);
    static gboolean invokeMenu(GtkWidget* widget);
    GtkAccelGroup* globalAccelGroup;
}

实现

gboolean MainWindow::isKeyForClosure(GtkAccelKey* key, GClosure* closure, gpointer data) { return closure == data; }
gboolean MainWindow::invokeMenu(GtkWidget* widget) {
    // g_warning("invoke_menu %s", gtk_widget_get_name(widget));
    gtk_widget_activate(widget);
    return TRUE;
}
void MainWindow::rebindAcceleratorsMenuItem(GtkWidget* widget, gpointer user_data) {
    if (GTK_IS_MENU_ITEM(widget)) {
        GtkAccelGroup* newAccelGroup = reinterpret_cast<GtkAccelGroup*>(user_data);
        GList* menuAccelClosures = gtk_widget_list_accel_closures(widget);
        for (GList* l = menuAccelClosures; l != NULL; l = l->next) {
            GClosure* closure = reinterpret_cast<GClosure*>(l->data);
            GtkAccelGroup* accelGroup = gtk_accel_group_from_accel_closure(closure);
            GtkAccelKey* key = gtk_accel_group_find(accelGroup, isKeyForClosure, closure);
            // g_warning("Rebind %s : %s", gtk_accelerator_get_label(key->accel_key, key->accel_mods),
            // gtk_widget_get_name(widget));
            gtk_accel_group_connect(newAccelGroup, key->accel_key, key->accel_mods, GtkAccelFlags(0),
                                    g_cclosure_new_swap(G_CALLBACK(MainWindow::invokeMenu), widget, NULL));
        }
        MainWindow::rebindAcceleratorsSubMenu(widget, newAccelGroup);
    }
}
void MainWindow::rebindAcceleratorsSubMenu(GtkWidget* widget, gpointer user_data) {
    if (GTK_IS_MENU_ITEM(widget)) {
        GtkMenuItem* menuItem = reinterpret_cast<GtkMenuItem*>(widget);
        GtkWidget* subMenu = gtk_menu_item_get_submenu(menuItem);
        if (GTK_IS_CONTAINER(subMenu)) {
            gtk_container_foreach(reinterpret_cast<GtkContainer*>(subMenu), rebindAcceleratorsMenuItem, user_data);
        }
    }
}
// When the Menubar is hidden, accelerators no longer work so rebind them to the MainWindow
// It should be called after all plugins have been initialised so that their injected menu items are captured
void MainWindow::rebindMenubarAccelerators() {
    this->globalAccelGroup = gtk_accel_group_new();
    gtk_window_add_accel_group(GTK_WINDOW(this->getWindow()), this->globalAccelGroup);
    GtkMenuBar* menuBar = (GtkMenuBar*)this->get("mainMenubar");
    gtk_container_foreach(reinterpret_cast<GtkContainer*>(menuBar), rebindAcceleratorsSubMenu, this->globalAccelGroup);
}

https://bugzilla.gnome.org/show_bug.cgi?id=129349 中有一个解决方法:

g_signal_connect(menu, "can_activate_accel", G_CALLBACK(gtk_true), NULL);

相关内容

  • 没有找到相关文章

最新更新