GTK应用程序是基于事件触发机制的。
我们使用g_signal_connect()将事件和对事件的处理函数(回调函数)联系在一起。
但是有时候是信号处理函数,有时候又说事件处理函数,都把人弄晕了。
事件的叫法是比较底层的说法,当我们按了一个按钮,在GDK层看来就是一个事件发生了,所谓的GDKEvent;当然事件还有一个更低层的说法,就是X事件。
按下按钮,Xserver发出事件消息,GDK层收到后发出GDKEvent给GTK,
GTK收到这个GDKEvent后,将GDK事件关联到Gtk自身定义的信号上,并将信号发出。
一层层推进:X事件->GDKEvent->信号
其实可以从网络协议理解,收到http报文的同时,肯定会收到tcp报文和ip报文啦。
GTK本身就是建立在GDK库和Xlib的基础上的。
再多扯一下,信号比较高级的,事件是比较低级的,在没有GTK库的时候,我们可以只用GDK进行编程,那时候就是处理事件了,但是会编程会变得复杂。
那么我们再来具体看看,事件回调函数和信号回调函数的差异
首先,使用g_signal_connect()可以将回调函数和相关的信号/事件联系起来
但是,这两者的回调函数在书写的时候是不一样的,
信号回调函数,属于GTK层,抽象级别较高,比较简单
void calback_func(GtkWidget *widget,gpointer callback_data)
信号回调函数中的两个参数的作用在于,但该函数执行时,通过他们可以知道外界的信息,比如是哪个构件发的信号,导致该函数被叫出来跑,或者跑的时候需要事先交代点什么data。毕竟对于信号回调函数自己来说,它可能在g_signal_connect的安排下,因为多个不同构件收到多个不同信号,就被叫出来了。
那么事件回调函数呢,属于GDK层,相比较与信号回调函数的参数多了一个,另外返回值也起作用。
gboolean callback_func(GtkWidget *widget,GdkEvent *event,gpointer callback_data);
关于返回值
返回值,如果是TRUE的话,说明事件已经处理完了,不用再进一步传播了(在GDK层解决问题),比如说不用发信号告诉他人了(转移到GTK层)。
返回值,如果是FALSE的话,继续处理。
关于返回值的意思,思考下“delete_event”事件和“destroy”信号
当我们点击窗口的X按钮(记住只是点击,不代表已经关了,能不能关还要看我们怎么处理该事件),GDK层发出“delete_event”事件的通知,我们去捕获该事件,对其处理,编写delete_event事件回调函数,在函数中直接调用gtk_main_quit();(这样非常坑爹,因为GDK只是告诉你有人点击关闭了,你二话不说,直接终止gtk_main()),当然这样的做法,确实是可以达到关闭窗口的同时结束进程的效果。因为连gtk_main()都结束了,还谈什么后续处理,直接整个窗口关闭,结束战斗。
但是如果我们想要,点击关闭按钮然后一直都关不掉呢?
编写delete_event事件回调函数,在函数中什么也不做,返回TRUE。这么做,等于说,当用户点击关闭窗口时,GDK提醒你这个事件,然后你去处理,可是坑爹的是,你什么也不做,然后还告诉GDK这个事啊我已经办妥了(返回TRUE)。结果是,用户不停地点击关闭按钮,却发现什么事也没有,这个行为比上一行为更加坑爹。
正常的做法呢,收到“delete_event”,我们去执行关闭窗口并返回FALSE,GTK发出“destroy”信号(此时窗口已关闭),destroy处理函数,执行gtk_main_quit();
默认行为时怎样的呢?如果我们不处理“delete_event”事件,GDK会默默关掉窗口(这个就是上面的“正常的做法”),然互GTK发出“destroy”,GTK告诉进程我们的窗口让人给关了,此时进程还在gtk_main()里,如果这个时候进程说不管它,什么处理也没有,那么就是常见的窗口已关,进程仍在。
所以说呢 ,一般编程中,处理“destroy”信号就行了,窗口都让人关了,对于一个GUI程序来说,还有多少活着的意义,直接gtk_main_quit();