【问题标题】:GTK 4 Key Press Event HandlerGTK 4 按键事件处理程序
【发布时间】:2022-11-28 14:33:51
【问题描述】:

我正在尝试使用 c 中的 gtk 4 处理按键事件(具体来说是箭头键)。每当我使用here(stackoverflow)和here(stackoverflow)等地方的一些答案时,它们似乎都不起作用。

相反,我收到以下错误:

(<unknown>:10924): GLib-GObject-WARNING **: 15:26:27.129: ../gobject/gsignal.c:2613: signal 'key-press-event' is invalid for instance '0x7faa268722f0' of type 'GtkApplicationWindow'

我也尝试过使用“key_pressed”等无济于事。

以下项目的总体目标是能够在按下/按下箭头键的方向上移动一个方格,但是由于小问题我还没有走那么远。

有什么建议吗?

#include <gtk/gtk.h>

static void
draw_function
(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data)
{
   // int square_size = 80.0;
   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
   cairo_paint (cr);

   cairo_set_source_rgb(cr, 0.2, 0.3, 0.8);
   cairo_rectangle(cr, 10, 10, 90, 90);
   cairo_fill(cr);
   cairo_save(cr);

   cairo_scale(cr, 0.6, 0.6);
   cairo_set_source_rgb(cr, 0.8, 0.3, 0.2);
   cairo_rectangle(cr, 30, 30, 90, 90);
   cairo_fill(cr);
   cairo_restore(cr);
   cairo_save(cr);

   cairo_scale(cr, 0.8, 0.8);
   cairo_set_source_rgb(cr, 0.8, 0.8, 0.2);
   cairo_rectangle(cr, 50, 50, 90, 90);
   cairo_fill(cr);
   cairo_restore(cr);
}

// Need to keep track of both key press and key release to distinguish unwanted terminal Return from others.
// The terminal Return that started the app won't have a key press event.
static gboolean key_press_event_cb (GtkWidget *widget,GdkEvent *event,gpointer data)
{
   g_print("GTK Application is activated\n");
  return FALSE; //keep processing event
}

static void
activate
(GtkApplication *app, gpointer user_data)
{
   GtkWidget *window;
   GtkWidget *drawingarea;
   static gboolean key_pressed = FALSE, *p_key_pressed = &key_pressed;

   window = gtk_application_window_new(app);

   drawingarea = gtk_drawing_area_new();
   button = gtk_button_new_with_label("Hello World");

   gtk_window_set_title (GTK_WINDOW(window), "Window");
   gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
   // gtk_widget_set_events(window, GDK_KEY_PRESS);
   gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawingarea), draw_function, NULL, NULL);

   g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK (key_press_event_cb), p_key_pressed); // p_key_pressed will be the "data" in cb function
   // g_signal_connect(button, "clicked", G_CALLBACK (print_hello), NULL);
   gtk_window_set_child(GTK_WINDOW(window), drawingarea);
   gtk_widget_show (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), 0, NULL);
    g_object_unref (app);

    return status;
}

【问题讨论】:

    标签: c gtk gtk4


    【解决方案1】:

    正如链接中所建议的那样,您应该使用GtkEventControllerKey 来处理按键/释放事件。下面是一个使用箭头键移动方框的示例:

    /* event-controller.c
     *
     * Compile: cc -ggdb event-controller.c -o event-controller $(pkg-config --cflags --libs gtk4) -o event-controller
     * Run: ./event-controller
     *
     * Author: Mohammed Sadiq <www.sadiqpk.org>
     *
     * SPDX-License-Identifier: LGPL-2.1-or-later OR CC0-1.0
     */
    
    #include <gtk/gtk.h>
    
    #define REPEAT_MS 100
    
    int x_offset, y_offset;
    guint key_repeat_id;
    guint key_val;
    
    gboolean
    update_square (gpointer user_data)
    {
      GtkWidget *drawing_area = user_data;
    
      g_assert (GTK_IS_DRAWING_AREA (drawing_area));
    
      if (key_val == GDK_KEY_Left)
        x_offset--;
      else if (key_val == GDK_KEY_Right)
        x_offset++;
      else if (key_val == GDK_KEY_Up)
        y_offset--;
      else if (key_val == GDK_KEY_Down)
        y_offset++;
    
      /* Request to redraw */
      gtk_widget_queue_draw (drawing_area);
    
      return G_SOURCE_CONTINUE;
    }
    
    static gboolean
    event_key_pressed_cb (GtkWidget             *drawing_area,
                          guint                  keyval,
                          guint                  keycode,
                          GdkModifierType        state,
                          GtkEventControllerKey *event_controller)
    {
      g_assert (GTK_IS_DRAWING_AREA (drawing_area));
    
      if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_ALT_MASK))
          return FALSE;
    
      key_val = keyval;
    
      g_clear_handle_id (&key_repeat_id, g_source_remove);
      key_repeat_id = g_timeout_add (REPEAT_MS, update_square, drawing_area);
      update_square (drawing_area);
    
      return TRUE;
    }
    
    static gboolean
    event_key_released_cb (GtkWidget *drawing_area)
    {
      /* Stop moving the square regardless of which key was released */
      g_clear_handle_id (&key_repeat_id, g_source_remove);
    
      return FALSE;
    
    }
    
    static void
    draw_func (GtkDrawingArea *drawing_area,
               cairo_t        *cr,
               int             width,
               int             height,
               gpointer        user_data)
    {
      int x, y;
    
      cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
      cairo_paint (cr);
    
    
      x = CLAMP (10 + x_offset, 0, width - 90);
      y = CLAMP (10 + y_offset, 0, height - 90);
    
      cairo_set_source_rgb (cr, 0.2, 0.3, 0.8);
      cairo_rectangle (cr, x, y, 90, 90);
      cairo_fill (cr);
      cairo_save (cr);
    }
    
    static void
    app_activated_cb (GtkApplication *app)
    {
      GtkEventController *event_controller;
      GtkWindow *window;
      GtkWidget *child;
    
      window = GTK_WINDOW (gtk_application_window_new (app));
      gtk_window_set_default_size (window, 360, 540);
    
      child = gtk_drawing_area_new ();
      gtk_window_set_child (window, child);
      gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
                                      draw_func,
                                      app, NULL);
    
      event_controller = gtk_event_controller_key_new ();
    
      g_signal_connect_object (event_controller, "key-pressed",
                               G_CALLBACK (event_key_pressed_cb),
                               child, G_CONNECT_SWAPPED);
      g_signal_connect_object (event_controller, "key-released",
                               G_CALLBACK (event_key_released_cb),
                               child, G_CONNECT_SWAPPED);
      gtk_widget_add_controller (GTK_WIDGET (window), event_controller);
    
      gtk_window_present (window);
    }
    
    int
    main (int   argc,
          char *argv[])
    {
      g_autoptr(GtkApplication) app = gtk_application_new (NULL, 0);
    
      g_signal_connect (app, "activate", G_CALLBACK (app_activated_cb), NULL);
    
      return g_application_run (G_APPLICATION (app), argc, argv);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多