我有一个用于 gtk3 的基于林间空地的 UI,并且我为几个菜单项设置了加速器字段。我不确定 GtkBuilder 在加载 glade 文件时究竟在幕后做了什么(使用全局 GtkAccelGroup?),但最终结果是,当我隐藏菜单栏时,加速器快捷键停止工作。
我想知道是否有一种方法可以让加速器即使在菜单不可见的情况下也能正常工作,同时仍然尽可能地坚持空地。
我有一个用于 gtk3 的基于林间空地的 UI,并且我为几个菜单项设置了加速器字段。我不确定 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);
}