【问题标题】:C: Tracking mouse movement with GTk+C: 使用 GTk+ 跟踪鼠标移动
【发布时间】:2015-03-16 17:37:15
【问题描述】:

考虑以下代码:

#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()

【问题讨论】:

  • 不是一个完整的答案,但是:gtk_widget_set_events()g_signal_connect() 不是“两次注册信号”。 gtk_widget_set_events() 呼叫是您要求接收 GK 事件,这些事件作为您与 g_signal_connect() 连接的信号传递。 为什么您必须明确要求 GDK 事件,但是,我不知道。 (您也可以考虑使用gtk_widget_add_events(),这样就无需知道默认情况下会收到哪些事件/跟踪您添加的事件,作为gtk_widget_set_events() 的替代方案。)
  • 我也不确定,但我相信gtk_widget_set_events() 的原因是出于性能原因默认不发出某些事件。 (如果没有人想要它们,那么您最好避免发出它们的性能开销,特别是如果它们像指针运动事件一样非常频繁。)
  • @ptomato 我认为你是对的...当我注释掉 gtk_widget_set_events() 时,我不再收到有关鼠标移动的通知...

标签: c gtk


【解决方案1】:

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

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

【讨论】:

  • 嗯,这很有趣......我应该用外接鼠标测试它(因为这是一台笔记本电脑,我只用面板上的跟踪板试过),然后会报告。跨度>
  • 好的,我又试了一次,实际上使用外接鼠标的频率似乎比笔记本电脑的触控板少。
  • 是的。当我使用指点板时,上面的输出显示有很多重复项,但是当我使用外接 USB 鼠标时,根本没有重复项……这可能是驱动程序相关的问题……感谢您的帮助。
【解决方案2】:

为什么需要这条线?

gtk_widget_set_events(main_window, GDK_POINTER_MOTION_MASK);

但是考虑到我们已经有了 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

它们都不是来自GdkEventScrollscroll_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

【讨论】:

    猜你喜欢
    • 2022-06-22
    • 2013-08-21
    • 2011-07-24
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多