GTK之信号和回调函数

描述

     在 2.0 版,信号系统已从 GTK 移到 GLib,因此在函数和类型的说明中有前缀 “g_” 而不是 “gtk_”。

       GTK 是一个事件驱动的工具包,意味着它会等在gtk_main() 那里, 直到下一个事件发生, 才把控制权传给适当 的函数。控制权的传递是使用“信号”的办法来完成的。(注意这里的信号并不等同于Unix 系统里的信号,并且也不是用它们实现的,虽然使用的术语是一样的。)

1.常用信号

  构件能够发送各种信号,信号可以由用户操作而引起,也可以由函数模拟事件产生,常见信号如下。

构件 信号 意义 产生信号函数
windows “destroy” 关闭窗口时发出该信号  
button “clicked” 点击按钮,这是按下和释放操作的组合 gtk_button_clicked(button)
  “clicked” 点击按钮,这是按下和释放操作的组合 gtk_button_clicked(button)
  “clicked” 点击按钮,这是按下和释放操作的组合 gtk_button_clicked(button)
  “pressed” 按下按钮 gtk_button_pressed(button)
  “released” 释放按钮 gtk_button_released(button)
toggle_button “toggled” 开关按钮  
listbox “select” 列表框被选择  
  “selection_changed” 列表框选择被更改  
GTKRadioMenuItem “activate” 菜单选项被选择  

    GTK+的两个基本机制是delete_event事件和destroy信号,当将要关闭窗口时,出现delete_event事件。当关闭窗口时,发出destroy信号。对于delete_event事件,顶层窗口应该设有相应的回呼函数。因为delete_event表示用户需要关闭应用软件。对于delete_event信号增加回呼函数包括两个步骤。

      delete_event的回呼函数应该返回布尔值,用以表示是否允许关闭窗口。返回TRUR值保持窗口打开,返回FALSE值表示窗口可以关闭。如果关闭窗口,接着发出destroy信号告诉应用程序就要关闭窗口。

2.信号连接和处理函数

2.1 信号连接函数 g_signal_connect

  每个信号和每个对象可以有多个回调函数,并且它们会按设置的顺序依次运行。

 

 /* 信号连接函数*/
#define g_signal_connect(instance, detailed_signal, c_handler, data)
形参:instance  --void*指针,要发出信号的构件
detailed_signal  -- char *指针,连接的信号的名称
      c_handler  --信号被捕获时所要调用的函数
      data   -- void*指针,传递给信号处理函数(回调函数)的数据
返回值:gulong类型,返回识别回调函数的标识
第三个参数即回调函数一般形式如下:
void callback_func( GtkWidget *widget,gpointer callback_data );
形参:widget -- 指向发出信号的构件的指针
      callback_data  --g_signal_connect传入的参数
注意:上面回调函数的声明只是一般的形式, 有些构件的特殊信号会用不同的调用参数。

 

2.2 g_signal_connect返回值

      信号连接函数g_signal_connect返回值为glong类型,返回一个识别回调函数的标志。因为每个信号和每个对象可以有多个回调函数,并且它们会按设置的顺序依次运行。所以可以通过这个返回标志,可通过下面函数将实现的回调函数删除:

 

g_signal_handler_disconnect(gpointer instance, gulong handler_id)

 

  所以,通过传递你想在上面删除处理函数的构件,以及某个signal_connect函数返回的标识,你就可以中断一个信号处理函数的连接。
 也可以使用g_signal_handler_block() 和 g_signal_handler_unblock() 这类函数来暂时断开信号处理函数的连接。

 

void g_signal_handler_block (gpointer instance, gulong handler_id);
void g_signal_handlers_block_by_func( gpointer object,GCallback func,gpointer data );
void g_signal_handler_unblock (gpointer instance,gulong   handler_id);
void g_signal_handlers_unblock_by_func( gpointer object,GCallback func,gpointer data );

 

2.3 信号连接函数 g_signal_connect_swapped

 

/*信号连接函数*/
#define g_signal_connect_swapped(instance, detailed_signal, c_handler, data)
g_signal_connect_swapped()和g_signal_connect() 相同,只是回调函数只用一个参数,一个指向GTK对象的指针。所以当使用这个函数连接信号时,回调函数应该是这样的形式:
	void callback_func( GtkObject *object );

 

  拥有两个函数来设置信号连接的目的只是为了允许回调函数有不同数目的参数。GTK 库中许多函数仅接受一个单独的构件指针作为其参数,所以对于这些函数你要用 g_signal_connect_swapped(),然而对你自己定义的函数,你可能需要附加的数据提供给你的回调函数。

3 事件

  除有信号机制外,还有一套 events 反映 X 事件机制。回调函数可以与这些事件连接。

 

GDK_NOTHING
GDK_DELETE
GDK_DESTROY
GDK_EXPOSE
GDK_MOTION_NOTIFY
GDK_BUTTON_PRESS
GDK_2BUTTON_PRESS
GDK_3BUTTON_PRESS
GDK_BUTTON_RELEASE
GDK_KEY_PRESS
GDK_KEY_RELEASE
GDK_ENTER_NOTIFY
GDK_LEAVE_NOTIFY
GDK_FOCUS_CHANGE
GDK_CONFIGURE
GDK_MAP
GDK_UNMAP
GDK_PROPERTY_NOTIFY
GDK_SELECTION_CLEAR
GDK_SELECTION_REQUEST
GDK_SELECTION_NOTIFY
GDK_PROXIMITY_IN
GDK_PROXIMITY_OUT
GDK_DRAG_ENTER
GDK_DRAG_LEAVE
GDK_DRAG_MOTION
GDK_DRAG_STATUS
GDK_DROP_START
GDK_DROP_FINISHED
GDK_CLIENT_EVENT
GDK_VISIBILITY_NOTIFY
GDK_NO_EXPOSE
GDK_SCROLL
GDK_WINDOW_STATE
GDK_SETTING

 

  所以, 连接一个回调函数到这些事件之一,我们会这样用:

 

g_signal_connect (G_OBJECT (button), "button_press_event",G_CALLBACK (button_press_callback), NULL);

 

  这里假定button是一个按钮构件。现在,当鼠标位于按钮上并按一下鼠标时,函数 button_press_callback() 会被调用。这个函数应该声明为:

 

static gint button_press_callback( GtkWidget *widget,
						GdkEventButton *event,
						gpointer data );

 

  注意,我们可以把第二个参数类型声明为 GdkEventButton,因为我们知道哪个类型的事件会发生。
 这个函数的返回值指示这个事件是否应该由 GTK 事件处理机制做进一步的传播。 返回 TRUE 指示这个事件已经处理了,且不应该做进一步传播。 返回 FALSE 继续正常的事件处理。

3.1 按键连接信号关闭窗口示例

 

#include 
void hello(GtkWidget *widget,gpointer data)
{
	g_print("按键信号触发成功n");
}
/*事件处理回调函数*/
gint delete_event(GtkWidget *widget,GdkEvent *evnet,gpointer data)
{
	g_print("事件处理回调函数调用成功n");
	return TRUE;//TRUE表示继续,FALSE表示关闭
}

void destroy(GtkWidget *widget,gpointer data)
{
	g_print("销毁窗口n");
	gtk_main_quit();//退出程序
}
int main(int argc,char *argv[])
{
	GtkWidget *window;
	GtkWidget *button;
	/*gtk初始化*/
	gtk_init(&argc, &argv);
	/*创建窗口*/
	window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(window),"GTK");/*设置窗口标题*/
	/*信号连接函数*/
	g_signal_connect(GTK_OBJECT(window),"delete_event",G_CALLBACK(delete_event),NULL);
	g_signal_connect(GTK_OBJECT(window),"destroy", G_CALLBACK(destroy), NULL);
	/*设置容器对象属性:设置窗口边框宽度为100*/
	gtk_container_set_border_width(GTK_CONTAINER(window),100);
	/*创建新的按钮,设置按钮信息为hello*/
	button=gtk_button_new_with_label("hello");
	g_signal_connect(GTK_OBJECT(button),"clicked",G_CALLBACK(hello),NULL);
	g_signal_connect_swapped(GTK_OBJECT(button),"clicked",G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(window));
	/*将按钮放入窗口中*/
	gtk_container_add(GTK_CONTAINER(window),button);
	/*显示控件*/
	gtk_widget_show_all(window);
	/*等待事件*/
	gtk_main();
	return 0;
}
信号

 

 程序运行效果:

      当我们用鼠标按下hello按钮,按键发出clicked信号,触发hello回调函数,接着调用下一个信号处理函数gtk_widget_destroy(),将窗口构件参数传递给该函数,销毁窗口,从而窗口发出destroy信号,然后调用我们实现号的回调函数destroy(),实现程序退出。
  审核编辑:汤梓红
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分