【问题标题】:How to connect the "clicked" signal and "key_press_event" to the same callback function?如何将“clicked”信号和“key_press_event”连接到同一个回调函数?
【发布时间】:2013-04-14 04:01:50
【问题描述】:

我想做的是将鼠标点击“clicked”信号和keypress“key_press_event”信号连接到同一个回调函数。代码是这样开始的:

static void s_up(GtkWidget *btn,
                 gpointer  data)
{
    code ...
}

...

int main(int argc, char **argv)
{
    ...
    g_signal_connect(button, "clicked", G_CALLBACK(s_up), NULL);
}

它可以很好地处理鼠标点击。然后我想向它添加键盘按键。所以我把代码改成了

static void s_up(GtkWidget   *btn,
                 GdkEventKey *event
                 gpointer    data)
{
    if(event->keyval == 's')
        more code ...
}

...

int main(int argc, char **argv)
{
    ...

    g_signal_connect(button, "key_press_event", G_CALLBACK(s_up), NULL);
}

当我按键盘上的“s”时它起作用了。

我的问题是如何将两个信号连接到同一个s_up 回调函数?除了if(event->keyval == 's') 的明显问题外,我尝试同时调用gtk_signal_connect,当我点击按钮时,我得到指向s_up 的SegFault。按“s”没有任何作用。任何帮助表示赞赏。

【问题讨论】:

    标签: c gtk


    【解决方案1】:

    您不能将两个信号直接连接到同一个信号处理程序,因为它们需要不同的参数。

    您收到分段错误的原因是,event->keyval 仅在您收到 key-press-event 时才有意义。当您收到clicked 事件时,第二个参数将是NULL,因为它映射到随clicked 事件提供的gpointer 参数,并且您在安装信号处理程序时将其设置为NULL,所以event 将是 NULL

    如果您想将两个信号连接到同一个处理程序的原因是您有通用代码,无论哪个信号触发它都应该运行,那么解决方案是为每个信号设置一个处理程序,并使用第三个函数他们都可以调用的代码。

    【讨论】:

    • 我要补充一点,gtk_signal_connect 已经过时多年了,他应该改用g_signal_connect
    【解决方案2】:

    使用包装函数间接调用相同的回调:

    static void
    callback(GtkWidget *button, gpointer data)
    {
        /* TODO */
    }
    
    static gboolean
    wrapper(GtkWidget *button, GdkEventKey *event, gpointer data)
    {
        if (event->keyval == 's')
            callback(button, data);
        return FALSE;
    }
    
    int
    main(int argc, char **argv)
    {
        /* TODO */
        g_signal_connect(button, "clicked", G_CALLBACK(callback), NULL);
        g_signal_connect(button, "key-press-event", G_CALLBACK(wrapper), NULL);
        /* TODO */
    }
    

    如果你不使用data,你也可以使用单个函数,但在我看来,引入的复杂性不值得努力:

    static gboolean
    callback(GtkWidget *button, GdkEventKey *event)
    {
        if (event != NULL && event->keyval == 's')
            callback(button, data);
        return FALSE;
    }
    
    int
    main(int argc, char **argv)
    {
        /* TODO */
        g_signal_connect(button, "clicked", G_CALLBACK(callback), NULL);
        g_signal_connect(button, "key-press-event", G_CALLBACK(callback), NULL);
        /* TODO */
    }
    

    为了能够理解后一个示例,您必须知道:

    1. 如果不使用返回值将被丢弃(如果您不想停止事件处理,则必须从按键事件中返回FALSE);
    2. 回调中的额外参数被静默丢弃。

    这意味着当callback()被点击调用时,你在事件中拥有数据值(NULL),而当它被一个键调用时按下event 已正确设置,data 会被静默丢弃。

    这反过来意味着,如果您在第二个示例中添加对 event != NULL 的检查,事情就会开始工作。

    【讨论】:

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