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

时间:2013-10-31 13:25:22

标签: gtk gtk3 glade gtkbuilder

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

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

2 个答案:

答案 0 :(得分:1)

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

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));

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

这对你有帮助吗?

答案 1 :(得分:0)

这是我对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);
}