最近在工程实践的过程中遇到许多关于图形界面设计方面的内容,特别是关于gtk库的调用,所以通过多方面的学习,终于弄清楚gtk+的用处,以及整个X系统的分层情况。
1,首先来介绍几个概念,以及他们之间的区别:
X Window 系统
在最底层,X包括一种存在与客户端和服务器间的协议。X服务器是响应客户端请求并向用户提供可交互桌面的软件。客户端可以发送请求来创建窗口,绘制文本和图形,这些窗口、文本和图形都会显示在服务器上。一旦用户移动鼠标、按下按键或者单击鼠标,X服务器就会向客户端发送事件通知客户端。X协议只支持所有GUI应用程序所需的最基本的元素。X协议的应用程序编程接口Xlib在该协议上提供了非常简洁的一层。客户就是通过Xlib提供的API向X服务器发送请求,并从X服务器那里接受错误消息和事件。客户端和X服务器可以存在于一台计算机上,也可以在网络上的不同计算机上运行。
GDK
GDK是标准Xlib函数调用的一个基本封装(wrapper),如果你对Xlib很熟悉,就不需要来重新熟悉绝大多数的GDK函数。所有的函数都是为了提供一个方便直观的风格来访问Xlib函数库。另外,自从GDK使用GLib,在多平台上使用时,GDK变得更加的方便和安全。
Glib
Glib库提供了一系列函数(functions)和定义(definitions),在设计GDK和GTK程序时很有用。它提供了一些标准c函数库(standard libc)的替代函数,比如malloc,但在其他的系统上使用时有很多问题。
GTK+ GTK+是一个小型而高效的控件库,具有Motif的外观和风格。实际上,它比Motif看起来好多了,它包含有基本的控件和一些很复杂的的控件:例如文件选择、控件和颜色选择控件。 GTK+提供了一些独特的特性,(至少,我知道其他的控件库不提供他们),例如,按钮不提供标签,它包含了一个子控件,在很多的时候是一个标签,但是,这个子控件也可以是一个映射,图像或者任何其他的程序员想要的集合。在整个的库中,你随处可见这种伸缩性。 GTK+由两部分组成,GTK和GDK。 GTK层为C语言提供了一个对象模型,并为UI工具包提供了最基本的widget,它是上层GUI派生的基础。 GTK是依赖于GDK的,GDK是Xlib的一个底层包装,Xlib库直接与X服务器对话。除了Xlib以外的任何部分都是基于GLib的,它是一个有用的C函数库,提供了很多实用程序和可移植的功能以及一组容易被C语言使用的容器。
2,然后再介绍两种层次结构
Gnome程序的层次结构
Gnome的开发基础结构是围绕一组函数库的,所有的内容都是用可移植的ANSI C语言写成的,可以用于所有类UNIX系统,与图形相关的函数库依赖于X Window系统。
一个Gnome程序使用多个库组成的层次结构: Gnome库在最高层,包括帮助例程,类和特殊的widget,并为应用程序提供一个基础架构。第二层是GTK,它是GTK+库的一部分。这个库提供了基本的工具包和widget来创建GUI应用程序。大多数GUI是直接用GTK编写的。GTK同时为Gnome库提供了一个功能强大的对象系统。 再下一层是GDK,它简单的对X函数库进行了包装,只有在我们进行特殊绘画或设置窗口的特殊属性的时候才会用到它。 最下面一层是Glib,它是C的一个实用程序库,包括可移植性和一些实用程序功能,以及一些容器类,例如:链表,可变数组,变长字符串,HASH(貌似是哈西表),缓存,一个事件循环和其他有用的结构
X系统的分层
在X系统中,由下而上关系是Xlib-->GDK-->GTK。我们先看GDK,大家知道,X和GDK都是一个事件驱动系统,也就是说,它们 的工作方式就是从底层系统的事件队列中不停取事件,然后进行相应的处理。当然,这个事件队列是更底层的系统产生的(比如GDK的事件队列是从X中取得,X 又从。。。。)。
这里,事件是什么?是一种结构(一种带有信息的机械动作),这个结构包括许多要素,比如(鼠标单击,在窗口A上,坐标为X,Y)就是一个事件,可见,事件是自包含的,它含有你所想要的全部信息,根据这些信息,你就可以做许多事。比如,在GDK的基础上你可以设计一个主循环,假设你有两个小部件A,B,你想在当鼠标 在A上单击时(一个事件)在B上显示“saga"。你可以这样做你的主循环:1。初始化,做一个表,表中有两项,分别为A,B。A为空,B中放两项 clicked-->display表示当B收到clicked时display(显示saga)。2。循环:取事件,若a。单击事件发生的地点在 A上(看事件这个结构中的位置项,可以是坐标,也可以是对应的窗口),则A向B发出一个"clicked"(记住这句话,但是怎么发出的呢,是通过底层的事件机制告诉给b么?),B收到"clicked"就 display,b。单击不发生在A上,丢掉这个事件,再取下一个事件进行判断,周而复始。看到吗?假设屏幕上有几十个小部件,每个小部件就如A,B那样 做一些表,放入自己收到"clicked"(或其它的什么)时要做的事(一个函数),在主循环中查到(根据位置)在某个小部件上发生"clicked"就 查表并做相应的事件(函数),它的功能就如同GTK一样强大了。把这当成一个框架,任何人用它,只要填好那个表,再写好收到"clicked"后要执行的 函数就可以了,很方便吧,你都可以做系统架构师了。GTK就是这样做的!(当然GTK还做了太多的其它的事,看它的名字"Gimp ToolKit"--画好小部件是它要做的正事) 将一些词用正式术语替换,这个过程就是这样:主循环收到一个事件(鼠标单击,在窗口A),便由窗口A向B发出一个信号"clicked",B看(在这儿就 是查表了)有没有注册了的回调函数(注册--就是那个g_connect_signal的作用了),有一个注册了的函数,就是display(。。。), 便去执行这个函数(在B上显示saga)。
大家看到A是向B发一个信号,其实也可以向自己发一个信号,就是这样描述:当有一个发生在A上的单击事件时,A向A发出一个"clicked"信号,A收 到后在A上显示"saga"!而且大多数编程人员的实现中,A就是向自己发一个信号,也就是说,常常是经历了某个事件(A经历了单击这个事件,说经历,是 因为发生在自己身上)的小部件发出一个给自己的信号并处理这个信号,有点晕?这正是常常把事件与信号混淆的原因!!!(because the the one who generates event is the one who send the msg and deal the msg itself)
3,最后是信号与事件的区别
信号与事件
——事件Events是从X server收到的消息流。事件(Event)是一个Gdk/Xlib概念。
——信号是GtkObject和它的子集(subclasses)的特性,他们和任何的输入流都没有关系。信号是对象(object)发出的。只是为了调用回调函数(就是发出信号时调用)
“信号(Signals)和事件(events)有关是因为GTK控件 (GtkWidget)通常收到一个事件的时候发出一个信号。这纯粹是为了方便,所以你可以在控件收到一个事件的时候调用一个回调函数。当你按下一个按钮 的时候会发出一个信号,所以才让人认为信号和事件有天生的联系。
1,事件驱动着Gtk的主循环,”等待事件,然后处理它”。GTK 是一个事件驱动的工具包,意味着它会等在 gtk_main() 那里,直到下一个事件发生,才把控制权传给适当的函数。
2,信号只是保持了一个回调函数列表,然后调用回调函数(就是发出信号)。这样的作用是:控制权的传递是使用“信号”的办法来完成的。
(ps:在这里是否可以理解事件是源,事件驱动信号发生。所以事件是底层的X,信号是上层的Gtk)
这样我们就可以总结一些区别了:
1.信号总是由一个小部件发出的。而事件是下层驱动产生的(当然,大多数情况是由人发出再经过系统、X的包装,传到GDK),它自身带有事件产生的位置信息。
2.它们之间有许多相似的函数,比如你可以用gtk_widget_set(add)_events,让一个小部件监听一个事件(比如你可以偷听在不同小 部件上发生的鼠标单击),就象听一个信号一样,不同的是你可以听到在其它部件上发生的事件,却不能听到不是发给你的信号。
3.信号有一个传递机制,比如A并没有处理这个信号的回调函数,就会把这个信号向父类传,直到有人处理或到最顶层。而事件始终在事件队列中,你可以向操作系统说(术语就是注册)我关心鼠标单击事件,有了告诉我,你不说,它就不告诉你!
4.还有许多细节上的差异。
阅读(1540) | 评论(0) | 转发(0) |