c - 自定义 gtk3 小部件中未执行事件回调

标签 c gtk mouseevent gtk3 custom-widgets

当前正在尝试创建一个直接基于GtkWidget的自定义小部件,将其标记为可绘制并使用 cairo 绘制内容。上下文就这么多。

一旦我尝试处理事件(这样我就可以实现缩放) - 特别是滚动事件 - 只是不起作用,我不确定为什么.

回调确实在焦点进入/焦点离开时执行(很好的旧打印语句证明了这一点),但我从未检测到任何滚轮事件该回调(按钮点击和按键按下/释放也不起作用)。

我尝试通过以下方式连接到事件信号

  • 使用函数指针并分配回调函数(我认为这是正确的做法)
  • 使用 foo_newfoo_init 中的 g_signal_connect (mywidget, "event",..)

都不起作用。


Foo 初始化:

foo_init (Foo *self)
{
    GtkWidget *widget = GTK_WIDGET (self);
    gtk_widget_set_has_window (widget, FALSE);

    self->priv = FOO_GET_PRIVATE (self);

    gtk_widget_add_events (widget, GDK_ALL_EVENTS_MASK);
    g_assert ((gtk_widget_get_events (widget) & GDK_SCROLL_MASK) != 0); //just fine

    /* added some stuff I also tried but did not work */
    gtk_widget_set_sensitive (widget, TRUE);
    gtk_widget_set_can_focus (widget, TRUE);
    gtk_widget_grab_focus (widget);
    ...

如何获取我的小部件的所有事件?


分配 widget_class->key_press_event = my_handler_callback; 实际上按预期工作,我得到了按下的键,但完全相同的 widget_class->button_press_event = my_handler_callback;widget_class->scroll_event = my_handler_callback; 赋值不起作用!

widget_class->key_press_event = my_handler_callback; // works
widget_class->key_release_event = my_handler_callback; // works
widget_class->button_press_event = my_handler_callback; // NOT
widget_class->button_release_event = my_handler_callback; // NOT
widget_class->scroll_event = my_handler_callback; // NOT

这让我产生了怀疑。

To receive this signal, the GdkWindow associated to the widget needs to enable the GDK_BUTTON_PRESS_MASK mask.

gtk_widget_add_events“工作”之前是否有必要实现小部件...?


更新:尝试在 gtk_widget_show_all 之后调用 gtk_widget_add_events。没有变化。


更新:完全可编译的示例

#ifndef __FOO_H__
#define __FOO_H__

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define FOO_TYPE            (foo_get_type ())
#define FOO(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE, Foo))
#define FOO_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE, Foo const))
#define FOO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE, FooClass))
#define FOO_IS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE))
#define FOO_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE))
#define FOO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE, FooClass))

typedef struct _Foo         Foo;
typedef struct _FooClass    FooClass;
typedef struct _FooPrivate  FooPrivate;

struct _Foo
{
    GtkWidget parent;

    FooPrivate *priv;
};

struct _FooClass
{
    GtkWidgetClass parent_class;
};

GType foo_get_type (void) G_GNUC_CONST;
Foo *foo_new (void);


G_END_DECLS

#endif /* __FOO_H__ */

#include "foo.h"


gboolean
scroll_hook (GtkWidget *widget, GdkEventScroll *event)
{
    g_print ("%p registered a scroll event\n");
    return TRUE;
}


#define FOO_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), FOO_TYPE, FooPrivate))

struct _FooPrivate
{
    char to_silence_warning;
};

G_DEFINE_TYPE (Foo, foo, GTK_TYPE_WIDGET)

static void
foo_finalize (GObject *object)
{
    G_OBJECT_CLASS (foo_parent_class)->finalize (object);
}

static void
foo_class_init (FooClass *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
    object_class->finalize = foo_finalize;

    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
    widget_class->scroll_event = scroll_hook;
    g_type_class_add_private (object_class, sizeof (FooPrivate));
}

static void
foo_init (Foo *self)
{
    self->priv = FOO_GET_PRIVATE (self);
    gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
}

Foo *
foo_new ()
{
    return g_object_new (FOO_TYPE, NULL);
}

#include <gtk/gtk.h>
#include "foo.h"
#include <stdlib.h>

gboolean
chicken_out (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
    g_print ("bye");
    gtk_main_quit();
    return TRUE;
}

int
main (int argc, char *argv[])
{
    GtkWidget *window;
    Foo *my;
    int i;

    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    my = foo_new ();

    gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (my));
    gtk_widget_show_all (window);

    gtk_widget_add_events (GTK_WIDGET (my), GDK_ALL_EVENTS_MASK);
    g_assert ((gtk_widget_get_events (GTK_WIDGET (my)) & GDK_SCROLL_MASK) != 0);

    g_signal_connect (window, "delete-event", G_CALLBACK(chicken_out), NULL);
    gtk_main ();

    return EXIT_SUCCESS;
}

使用

gcc `pkg-config --cflags --libs gtk+-3.0` -I. ./foo.c ./foo_test.c  -o foo.bin

编译(当然,所有文件都在你的cwd中)

最佳答案

需要从GtkWidget移动到GtkDrawingArea,否则就会崩溃。根本原因是,如果没有正确的 realize 默认回调,则不会填充小部件的 ->window 私有(private)变量 - 我没有实现该回调。

关于c - 自定义 gtk3 小部件中未执行事件回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22738105/

相关文章:

Emacs 在 dired 中禁用 mouse-1

C: 我无法显示数组的内容 [CodeBlocks]

c - 在 Mint 中运行 Clutter 示例代码时出错

Python Tkinter : Canvas scrolling with MouseWheel

java - 如何验证 selenium webdriver 中的文本颜色?

python - 没有名为 gtk 的模块

c - xmalloc毒药的目的是什么

C 指针算术 sizeof(struct)

c - 关于C构造的问题

c++ - 需要调用 gtk_init 函数,但不是从主函数调用 - C++