【问题标题】:Ignore keyboard cursor in GTK3 C在 GTK3 C 中忽略键盘光标
【发布时间】:2020-04-03 23:14:12
【问题描述】:

在 C 中使用 GTK3,我有一个带有按钮的界面。我希望使用鼠标的用户能够按下按钮或使用键盘上的单个按钮来执行相同的操作。

MWE(根据 GTK3 Hello World 示例修改):

/*
 * Ignore keyboard cursor in GTK3 C
 */

#include <gtk/gtk.h>

void thing() {
    printf("did a thing\n");
}

void otherthing() {
    printf("did something different\n");
}

static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
    gchar* val = gdk_keyval_name (event->keyval);

    if (strcmp(val, "Left") == 0) {
        thing();
    }
    return 0;
}

static void activate (GtkApplication *app, gpointer user_data) {
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *button2;
    GtkWidget *button_box;

    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window");
    gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

    button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
    gtk_container_add (GTK_CONTAINER (window), button_box);

    button = gtk_button_new_with_label ("Do the thing");
    button2 = gtk_button_new_with_label ("xxx");
    g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
    g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
    g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
    gtk_container_add (GTK_CONTAINER (button_box), button2);
    gtk_container_add (GTK_CONTAINER (button_box), button);

    gtk_widget_show_all (window);
}

int main (int argc, char **argv) {
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}

在这个程序中,用户可以按左箭头键来执行thing。用户也可以点击gui按钮执行thing。但是,敲击某些键盘键(例如空格键或回车键)将“单击”gui 按钮以执行thing

在这种情况下,如何防止键盘“点击”键盘光标所在的按钮?

【问题讨论】:

  • 我认为您需要Accelerator Groups 来完成这项工作。无论如何,你确定mnemonics 不是你需要的吗?
  • 很难理解只是因为您显示了带有按钮的代码,因为您可能在这里谈论焦点,如果您有多个小部件(例如 2 个按钮)。默认情况下,GTK 使用焦点在您的案例中的按钮等小部件上。在 therms 中,当您单击一个按钮时,该按钮具有焦点,这就是 space 和 enter 键调用您的功能(激活)的原因。您应该阅读更多关于 set-focus、active-focus 和 default-focus 的信息。
  • 根据@Michi 评论使用第二个按钮更新了有问题的 MWE。
  • @Michi 根据我的阅读,加速器和助记符似乎都不适合我想要实现的目标。我想做的是一个“视频游戏”类型的界面,其中像箭头键这样的按钮完全可以控制某些功能。除了包括触摸屏在内的硬件的“视频游戏控制”方案之外,我还希望有 gui 按钮。换句话说,我希望窗口有焦点,但我不希望 gui 元素获得单独的焦点。

标签: c gtk3 key-bindings


【解决方案1】:

假按钮黑客

我现在使用一个无用的按钮在我的代码中破解了一个解决方法。我不会将此答案标记为已解决,因为它非常草率,但它可以完成工作,直到有更好的可用为止。

说明

此 hack 添加了另一个未分配功能的按钮。使用gtk_widget_grab_focus,我们强制这个无用的“假按钮”保持键盘焦点。每次按下按钮时,我们都会重新发出此命令。

问题

将焦点重新拉回 fakebutton 很慢。用户可以快速发出一系列命令(在 MWE 的情况下,通过按 LeftSpace 来错误地发出 otherthing 函数)。

MWE

/*
 * Ignore keyboard cursor in GTK3 C
 */

#include <gtk/gtk.h>

GtkWidget *fakebutton;

void thing() {
    printf("did a thing\n");
}

void otherthing() {
    printf("did something different\n");
}

static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
    gchar* val = gdk_keyval_name (event->keyval);

    if (strcmp(val, "Left") == 0) {
        thing();
        gtk_widget_grab_focus(fakebutton);
    } else {
        gtk_widget_grab_focus(fakebutton);
    }
    return 0;
}

static void activate (GtkApplication *app, gpointer user_data) {
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *button2;
    GtkWidget *button_box;

    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window");
    gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

    button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
    gtk_container_add (GTK_CONTAINER (window), button_box);

    button = gtk_button_new_with_label ("Do the thing");
    button2 = gtk_button_new_with_label ("xxx");
    fakebutton = gtk_button_new();
    g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
    g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
    g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
    gtk_container_add (GTK_CONTAINER (button_box), button2);
    gtk_container_add (GTK_CONTAINER (button_box), fakebutton);
    gtk_container_add (GTK_CONTAINER (button_box), button);


    gtk_widget_show_all (window);
}

int main (int argc, char **argv) {
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-24
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    相关资源
    最近更新 更多