C:使用GTk+跟踪鼠标移动;

C:使用GTk+跟踪鼠标移动;,c,gtk,C,Gtk,考虑以下代码: #include<gtk/gtk.h> #include<stdio.h> static void destroy(GtkWidget*, gpointer); static gboolean mouse_moved(GtkWidget *widget,GdkEvent *event,gpointer user_data); int main(int argc, char* argv[]) { GtkWidget *main_window;

考虑以下代码:

#include<gtk/gtk.h>
#include<stdio.h>


static void destroy(GtkWidget*, gpointer);
static gboolean mouse_moved(GtkWidget *widget,GdkEvent *event,gpointer user_data);

int main(int argc, char* argv[]) {

    GtkWidget *main_window;

    // initializing
    gtk_init(&argc, &argv);

    main_window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(main_window),"Test");
    gtk_widget_set_size_request (main_window, 500, 300);

    // connect the window with signals
    g_signal_connect (G_OBJECT (main_window), "destroy",G_CALLBACK (destroy), NULL);
    g_signal_connect (G_OBJECT (main_window), "motion-notify-event",G_CALLBACK (mouse_moved), NULL);

    gtk_widget_set_events(main_window, GDK_POINTER_MOTION_MASK);

    // show window
    gtk_widget_show_all (main_window);

    gtk_main();
    return 0;
}


static void destroy(GtkWidget *window,gpointer data) {
    gtk_main_quit ();
}


static gboolean mouse_moved(GtkWidget *widget,GdkEvent *event, gpointer user_data) {

    if (event->type==GDK_MOTION_NOTIFY) {
        GdkEventMotion* e=(GdkEventMotion*)event;
        printf("Coordinates: (%u,%u)\n", (guint)e->x,(guint)e->y);
    }
}
等等

让我困惑的是:怎么会有两个连续的事件保持相同的坐标?例如,以这两行为例:

Coordinates: (380,44)
Coordinates: (380,44)  
这基本上是说鼠标没有移动(它从(380,44)移动到(380,44)),那么怎么可能有移动事件来启动第二行输入的处理程序呢


另一个不太重要且(可能)不相关的问题:
为什么这条线是必要的

gtk_widget_set_events(main_window, GDK_POINTER_MOTION_MASK);

在GTK+发展的图书基础上,它说:

接下来,您需要向事件框添加事件掩码,以便它知道 小部件将接收什么类型的事件。价值观 表中显示了指定事件掩码的GDKEVENTMAK枚举 3-3. GDKEVENTMAK值的按位列表可以传递给 gtk_widget_set_events(),如果需要设置多个事件

但考虑到我们已经有了g_signal_connect(),这个调用不是多余的吗?也就是说,根据文件:

将GCallback函数连接到特定对象的信号

处理程序将在信号的默认处理程序之前调用

为什么我需要注册两次信号?

一次是使用
gtk\u widget\u set\u events()
,第二次是使用
g\u signal\u connect()

我尝试直接使用xev监控X服务器中的鼠标移动,似乎xorg报告了具有相同坐标但不同时间戳的多个鼠标事件。然而,当使用键盘上的指向棒时,它并没有这样做,只有使用触控板或外部鼠标

我的猜测是,精度实际上更高,但事件是以屏幕上的一个像素为单位报告的。这可能会导致驱动程序报告更多需要的鼠标事件

为什么这条线是必要的

gtk_小部件设置_事件(主窗口、GDK_指针、运动)
MASK)

但考虑到我们已经有了g_signal_connect(),这个调用不是多余的吗?也就是说,根据文件:

例如,考虑一个例子。 如果单击,您将注意到有6个可用信号:

Signals
    void    activate    Action
    void    clicked     Action
    void    enter       Run First
    void    leave       Run First
    void    pressed     Run First
    void    released    Run First
它们中没有一个是来自的
scroll\u event
,这意味着以下程序(可能)无法按规定工作:

#include <gtk/gtk.h>

gboolean scroll_callback        ( GtkWidget *widget, GdkEvent  *event, gpointer   user_data );

int main ( void )
{
    GtkWidget *window;
    GtkWidget *button;
    gtk_init( NULL, NULL );
    /// ***
    window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
    gtk_window_set_default_size( GTK_WINDOW( window ), 300, 250 );
    g_signal_connect( window, "destroy", gtk_main_quit, NULL );
    gtk_container_set_border_width( GTK_CONTAINER( window ), 25 );
    /// ***
    button = gtk_button_new_with_mnemonic( "_Click me" );
    g_signal_connect( button, "clicked", gtk_main_quit, NULL );
    gtk_container_add( GTK_CONTAINER( window ), button );
    /// ***
    g_signal_connect( button, "scroll_event", G_CALLBACK( scroll_callback ), window );
    /// ***
    gtk_widget_show_all( window );
    gtk_main();
}

gboolean scroll_callback      ( GtkWidget *widget, GdkEvent  *event, gpointer data )
{
    (void)widget;
    if ( event->type == GDK_SCROLL ) /// Scroll the was Catched
    {
        if ( event->scroll.direction == GDK_SCROLL_DOWN )
        {
            g_print( "Scroll-Down Detected\n" );
            gtk_window_set_title( GTK_WINDOW( data ), "Scroll-Down Detected" );
        }

        if ( event->scroll.direction == GDK_SCROLL_UP )
        {
            g_print( "Scroll-UP Detected\n" );
            gtk_window_set_title( GTK_WINDOW( data ), "Scroll-UP Detected" );
        }
        return FALSE;
    }
    return TRUE;
}
程序运行良好:

Scroll-Down Detected
Scroll-Down Detected
Scroll-Down Detected
Scroll-UP Detected
Scroll-UP Detected
Scroll-UP Detected

这不是一个完整的答案,但是:
gtk\u小部件\u set\u events()
g\u signal\u connect()
不是“为信号注册两次”。
gtk\u widget\u set\u events()
调用是您请求接收GK事件,这些事件作为您使用
g\u signal\u connect()连接的信号传递。然而,我不知道为什么必须明确要求GDK事件。(也可以考虑<代码> GtkWiWigGeDigAdGyAdvsId)(),这就避免了在默认情况下跟踪您所添加的事件的需要,作为对“代码> GTKKWIDGETSITS事件()/代码>的替代方案。)我也不确定,但我相信<代码> GTKYWIDGETSETSyEngEvsServer()的原因。
是由于性能原因,某些事件默认情况下不会发出。(如果没有人想要它们,那么你最好避免发射它们的性能开销,特别是如果它们像指针运动事件一样非常频繁。)@ptomato我认为你是对的。。。当我注释掉
gtk\u widget\u set\u events()
时,我再也不会收到鼠标移动的通知了……这很有趣。。。我应该用一个外部鼠标测试它(因为这是一台笔记本电脑,我只在面板上的跟踪板上试过),然后我会报告。好的,我又试了一次,使用外部鼠标的频率似乎比笔记本电脑的跟踪板要低。是的。当我使用指针板时,上面的输出显示有很多重复项,但当我使用外部USB鼠标时,根本没有重复项。。。这可能是驱动程序相关的问题。。。谢谢你的帮助。
button = gtk_button_new_with_mnemonic( "_Click me" );
gtk_widget_set_events( button, GDK_SCROLL_MASK );
Scroll-Down Detected
Scroll-Down Detected
Scroll-Down Detected
Scroll-UP Detected
Scroll-UP Detected
Scroll-UP Detected