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

时间:2015-03-16 17:37:16

标签: 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;

    // 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: (390,17)
Coordinates: (390,18)
Coordinates: (390,18)
Coordinates: (390,18)
Coordinates: (390,18)
Coordinates: (390,19)
Coordinates: (390,19)
Coordinates: (390,19)
Coordinates: (391,22)
Coordinates: (391,22)
Coordinates: (391,22)
Coordinates: (391,22)
Coordinates: (391,22)
Coordinates: (391,22)
Coordinates: (391,22)
Coordinates: (391,23)
Coordinates: (391,23)
Coordinates: (391,23)
Coordinates: (390,23)
Coordinates: (390,23)
Coordinates: (390,23)
Coordinates: (390,23)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,24)
Coordinates: (390,25)
Coordinates: (390,25)
Coordinates: (390,25)
Coordinates: (390,25)
Coordinates: (390,25)
Coordinates: (390,25)
Coordinates: (390,26)
Coordinates: (390,26)
Coordinates: (390,26)
Coordinates: (390,26)
Coordinates: (390,26)
Coordinates: (390,26)
Coordinates: (390,26)
Coordinates: (390,27)
Coordinates: (390,27)
Coordinates: (390,27)
Coordinates: (390,27)
Coordinates: (390,27)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,28)
Coordinates: (390,29)
Coordinates: (390,29)
Coordinates: (390,29)
Coordinates: (390,30)
Coordinates: (390,30)
Coordinates: (390,30)
Coordinates: (390,30)
Coordinates: (390,31)
Coordinates: (390,31)
Coordinates: (390,32)
Coordinates: (390,32)
Coordinates: (390,32)
Coordinates: (390,33)
Coordinates: (390,33)
Coordinates: (390,33)
Coordinates: (390,33)
Coordinates: (390,33)
Coordinates: (390,34)
Coordinates: (390,34)
Coordinates: (390,34)
Coordinates: (389,34)
Coordinates: (389,35)
Coordinates: (389,36)
Coordinates: (389,36)
Coordinates: (389,36)
Coordinates: (389,37)
Coordinates: (389,36)
Coordinates: (389,37)
Coordinates: (389,37)
Coordinates: (389,37)
Coordinates: (389,37)
Coordinates: (389,38)
Coordinates: (389,38)
Coordinates: (388,38)
Coordinates: (388,38)
Coordinates: (388,38)
Coordinates: (388,38)
Coordinates: (388,39)
Coordinates: (388,39)
Coordinates: (388,39)
Coordinates: (388,39)
Coordinates: (388,39)
Coordinates: (388,40)
Coordinates: (387,40)
Coordinates: (387,40)
Coordinates: (387,40)
Coordinates: (387,40)
Coordinates: (387,40)
Coordinates: (387,40)
Coordinates: (387,40)
Coordinates: (386,41)
Coordinates: (386,41)
Coordinates: (386,41)
Coordinates: (386,41)
Coordinates: (386,41)
Coordinates: (386,41)
Coordinates: (385,41)
Coordinates: (385,41)
Coordinates: (385,41)
Coordinates: (385,41)
Coordinates: (384,42)
Coordinates: (384,42)
Coordinates: (384,42)
Coordinates: (384,42)
Coordinates: (384,42)
Coordinates: (384,42)
Coordinates: (384,42)
Coordinates: (383,42)
Coordinates: (383,42)
Coordinates: (383,42)
Coordinates: (383,42)
Coordinates: (383,43)
Coordinates: (382,43)
Coordinates: (382,43)
Coordinates: (382,43)
Coordinates: (382,43)
Coordinates: (381,43)
Coordinates: (381,43)
Coordinates: (381,43)
Coordinates: (380,43)
Coordinates: (380,44)
Coordinates: (380,44)
Coordinates: (380,44)
Coordinates: (380,44)
Coordinates: (379,44)
Coordinates: (378,44)
Coordinates: (378,44)
Coordinates: (377,44)
Coordinates: (377,44)

依旧......

令我困惑的是:怎样才能有两个连续的事件保持相同的坐标?例如,请使用以下两行:

Coordinates: (380,44)
Coordinates: (380,44)  

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


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

gtk_widget_set_events(main_window, GDK_POINTER_MOTION_MASK);

在“Gtk +开发基金会”一书中,它说:

  

接下来,您需要向事件框添加一个事件掩码,以便它知道   小部件将接收哪种类型的事件。的价值观   指定事件掩码的GdkEventMask枚举如表所示   3-3。可以传递GdkEventMask值的按位列表   gtk_widget_set_events()如果你需要设置多个。

但鉴于我们已经拥有g_signal_connect(),这个调用是不是多余的?这是根据文件:

  

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

     

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

为什么我需要两次注册信号? 一次使用gtk_widget_set_events(),第二次使用g_signal_connect()

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

  

为什么需要此行?

gtk_widget_set_events(main_window, GDK_POINTER_MOTION_蒙版);

  

但是,鉴于我们已经有了g_signal_connect(),因此此调用是否多余?根据文档:

例如,考虑一个GtkButton like this one。 如果您点击Signals Link,则会注意到有6种信号可用:

Signals
    void    activate    Action
    void    clicked     Action
    void    enter       Run First
    void    leave       Run First
    void    pressed     Run First
    void    released    Run First

它们都不是GdkEventScroll中的scroll_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_event信号事件,但是它本身的小部件(按钮)没有这种类型的信号。

要修复它,我们在创建按钮后立即将事件设置/添加到按钮:

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