关于GTK+构件的设计风格及思想
引言:图形用户界面是用户与仪器的唯一交互方式,也是一个操作系统当中一个尤为重要的方面,GTK+即是一个应用于界面开发的良好图形库。
GTK+概述
一,1 GTK+简介
GTK+(GIMP ToolKit,GIMP工具包)最初用于开发GIMP,是一个用于创建图形用户接口的图形库在功能上类似微软的MFC,即为应用程序提供一套与平台无关的图形用户界面接口GTK+是基于LGPL授权的,因此GTK+在开发开源软件或商业的非自由软件领域中都得到越来越广泛的使用特别在嵌入式应用中,由于GTK+库小,且程序员可以根据自己需要对其进行裁剪,因此其占用资源少并能快速装入,所以基于GTK+开发的图形用户界面适合在内存受限的嵌入式设备上运行
2,GTK+是在GDK的基础上创建的,其软件层次结构如图1所示Glib是Linux系统下最常用的轻量级的C语言函数库,它提供了C常用的数据结构定义、处理函数、宏、
3,(引入)如果定义组件的风格
定义组合构件的设计首先需要对GTK+自定义构件的设计非常熟悉,对GTK+构件的设计风格和继承关系很了解,并且能掌握对各个库的相应关系组合构件它不是单纯从某个构件继承下来的,只是组合任何想要组合的构件来实现某项功能因此必须考虑该组合构件的父类问题
组合构件也跟构件库里面的构件一样,它也可能要接收信号并做出相应的处理因此挂接信号也是设计需要考虑的问题
作为一个构件,组合构件也应有自己的风格,由于组合构件是多个构件的组合,每个构件又有其不同的风格,如何确定当前构件的风格也是设计的难点
二,组合构件的设计思想及其实现
1 组合构件的设计思想
通俗的讲,GTK+的构件库是基于C语言的,它不具有面向对象的特性,然而GTK+的确又是面向对象的,那是因为它用C语言来实现了C++编译器的功能因此它同样具有继承的特性,
它的代码风格也延续了面向对象的设计风格在GTK+库中,直接继承自GtkObject对象的构件主要是GtkWidget,它几乎是所有可视构件的共同祖先,大多数构件共有的属性都包括在其中与
其他GUI开发工具不同的是,我们不用直接创建GtkObject或GtkWidget对象,而是用定义对象的实例结构和类结构的方式来定义对象,然后再通过类型注册来实现对象当前笔者就根据组合
构件的特点,直接从GtkObject继承它与GtkWidget是一种并行关系和其他构件一样,它也有相应的宏定义,来进行各种强制转换和类型获取
任何一个构件都有其创建对象函数,组合构件也是一样,在对象中定义各个成员构件,在创建对象时将其一一创建,并根据需要对其各个构件来进行属性设定,最后返回的是组合构件对象本
身关于信号的设定也是和其他构件的方法一样,在类的结构体中定义信号,并在类的初始化中对信号进行定义
组合构件的接口设计应可以根据当前总体设计的需要,而不是像一般构件一样完全的独立出来,它具有自己的特色,并不需要刻意遵守一般构件的要求这也是组合构件的灵活性所在
GTK+允许用户通过rc文件来定制应用程序的主题风格,即设置构件颜色、字号大小,并为构件添加背景图标等而对于组合构件而言,由于其为多个构件的组合,每个构件都有其相
应的风格设计,因此严格的讲它本身是不具有风格设计的,所谓组合构件的风格设计,就是对各个构件进行风格设计,并将其风格设定封装在一个函数里,对外只提供一个接口对于组合构件
如果不进行风格设计,它将沿用整个图形界面的风格设计。
引入:
什么是gtk主题引擎???
主题引擎是应用程序主题使用的一些代码。如今,已有许多不同的主题引擎存在。
GTK + 主题由三件事: 一个主题引擎 ,这是一个共享对象包括代码的图形要素,一个配置文件来配置的运作主题的引擎和核心部分基于GTK +和额外的数据文件的主题引擎如图片。
A theme can include its own theme engine, it can use an existing theme engine, such as the Pixbuf theme which draws all elements in terms of images, or it can use GTK+'s built in drawing code.
GTK+程序启动如何分析主题?
每一个GTK+的程序都会在启动时分析当前主题的gtkrc文件来决定显示控件的风格,在gtkrc文件中通常会定义一个theme engine,并给它传递适当的参数,例如
engine "crux-engine" {
rect_scrollbar = TRUE
}
theme engine以共享库的形式存在,存放在/usr/lib/gtk-2.0/2.2.0/engines或/usr/lib/gtk/themes/engines下,文件名形式为libcrux-engine.so.
我们看在实施题材引擎的有些细节。 如上所述,题材引擎是一个共有的对象。 共有的对象必须出口三个入口:
(1)void theme_init (GtkThemeEngine *engine);
(2)void theme_exit (GtkThemeEngine *engine);
(3)GtkRcStyle *theme_create_rc_style (GtkThemeEngine *engine);
重点:1,在theme_init函数主要执行以下两个函数,注册生成GtkRCStyle和GtkStyle类。
crux_rc_style_register_type (module);
crux_style_register_type (module);
-----crux_rc_style_register_type函数执行GtkRCStyle类的初始化函数,重载crux_parse_rc_style和crux_rc_style_merge函数,用于gtkrc文件中参数的提取分析。
同样地,crux_style_register_type函数执行GtkStyle类的初始化函数,重载所有drawing functions,例如
static void crux_style_class_init (PixbufStyleClass *klass)
{
GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
style_class->draw_hline = draw_hline;
style_class->draw_vline = draw_vline;
style_class->draw_shadow = draw_shadow;
style_class->draw_polygon = draw_polygon;
style_class->draw_arrow = draw_arrow;
style_class->draw_diamond = draw_diamond;
这些主题引擎通过对这些作用中的每一个的GtkThemeEngin的描述,是GTK+为每个题材引擎模块创造它装载的对象。
如何安装主题引擎
我们现在常用的发行版都对主题引擎进行了打包,并与Gnome中的已经存在的引擎一起装载。
对其主题引擎使用下面的命名方案:gtk-engines-(GTK+ 1.2的引擎)和 gtk2-engines-(GTK+ 2.4 的引擎)。先检查所使用的发行版的引擎,如果有,直接使用它。
如果所用的发行版没有您想要的主题引擎,那么可以使用标准包的安装方法来安装。大多数引擎使用的是 atuoconf 和 make
install。这样安装就非常简单了:./configure &&
make && make install 。一般在readme中有详细的说明引擎如何安装。
引擎和主题如何区分?
我个人觉得,引擎其实只是一个程序,主题的配置文件就是是这个程序的参数,而这个程序运行的结果就是主题的外观。
如何从开始理解gtkrc在实践中的使用
GTK 有自己缺省处理应用程序的方法,这就是使用rc配置文件。这些文件可用于给几乎任何构件设置颜色,也能为一些构件的背景贴上一幅像素图。
rc 文件的功能
在你的应用程序开始处,应包含一个如下的函数调用:
void gtk_rc_parse( char *filename );
把 rc 文件名传递给被调用的函数,随后 GTK 会解析这个文件,并且使用文件中所定义构件类型的风格设置。
如果希望定义一套和其它构件集或同一构件集中其它逻辑部分具有不同风格的特定构件集,使用以下函数调用:
void gtk_widget_set_name( GtkWidget *widget,
gchar *name );
把新创建的构件作为第一个参数,把你给该构件定的名程作为第二个参数。这使你能够在 rc 文件中按名称更改这个构件的属性。
如果我们使用了一个如下的函数调用:
button = gtk_button_new_with_label ("redred");
gtk_widget_set_name (button,"redred");
那么这个按钮取名为"redred",并且在 rc 文件中可能通过像"redred button.GtkButton"这样的名称找到它。
后面作为示例的 rc 文件,设置主窗口的属性,告诉所有子窗口继承在"main button"风格项中规定的风格。在应用程序中的代码为:
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_name (window, "main window");
然后在 rc 文件中用如下一行定义它的风格:
widget "main window.*GtkButton*" style "main_button"
该定义把"主窗口"中的所有按钮构件设置为 rc 文件中定义的"main_buttons"风格。
如你所见,这是一个非常强大和灵活的系统。如何最大限度的利用它的优势需要使用你的想象力。)
一、gtk主题指南
1.Widgets
2.Styles
3.Engines
4.gtkrc文件
1)修改构件的属性
2)每一构件的分为五种状态
3)风格绑定
1.将一种风格绑定到组件类
2.组件嵌套的方式widget_class
如widget_class "*.GtkButton.*" style "button-content"
3.应用指定风格
4.风格绑定的优先次序
4)组件指定风格
5)高级指定风格(依据gtk2正式文档)
5.widget设置示例
1.Widgets
GTK拥有一套大量的widget集合,如按钮,滚动条,编辑框等,每一种组件的属性都可以单独进行配置。
所有的widget由GtkWidget派生出来的。也就是说,更改GtkWidget的属性所有的widgets会受到影响。幸运的是,大多数widget有其父类,如GtkButton的属性同样使GtkCheckButton生效,除非你对其进行单独的配制。
widgets, 一些常用元素
/GnomePanel /GtkButton /GtkCheckButton /GtkColorButton /GtkComboBox /GtkComboBoxEntry /GtkEntry /GtkFrame /GtkMenu /GtkMenuBar /GtkMenuItem /GtkNotebook /GtkProgressBar /GtkRadioButton /GtkScale /GtkSpinButton /GtkStatusbar /GtkTreeView /StyleProperties /SymbolicColors
2.Styles
用户自定义GtkWidget形成自己的风格,定义的方式有两种形式,一种是以使用Gtk中的style,但style定义方式中只给出了几种有限风格属性,如设置滚动条的宽度。另一种就是通过使用engine这种机制来实现,其中定义很多的属性可供使用时选择。
通过定义不同的styles合并在一起成为一个最终的Gtk主题,所以通常可以定义出一个基本的风格,其包含一此通用的选项配置,对于定义组件专有的属性可以在引用它的基础上做设置,如颜色的修改.
3.Engines
与styles组合实现出更有吸引力的风格,gtk内部实现很多可供选择的风格。
4.gtkrc文件
一个rc文件被称为gtkrc,存放的地方取决于系统的配置,通常放在/usr/share/themes/themename目录下,存在gtk-2.0/gtkrc文件,此文件可以是一个rc文件,里面定义了gtk中各种组件的配置。
1)修改构件的属性:
fg:设置一个构件的前景色
bg:设置一个构件的背景色
text:可编辑文本构件的前景色
base:可编辑文本构件的背景色
bg_pixmap:显示像素图的构件的背景色
font_name:设置字体风格
xthickness:设置左右边界的宽度
ythickness:设置上下边界宽度
2)每一构件的分为五种状态:
NORMAL:鼠标没有覆盖,点击的状态
PRELIGHT:鼠标在组件之上
ACTIVE:鼠标被按下或点击的状态,
INSENSITIVE:不能被激活,或点击的状态
SELECTED:被选对象可以带好多属性
3)风格绑定:
1.将一种风格绑定到组件类
格式:class "GtkButton" style "my-button" 将“my-button"风格绑定到GtkButton的所有实例
widget_class "*Text*" style "bright_yellow"
将"bright_yellow"风格绑定到名字中含有“Text“的组件
2.组件嵌套的方式widget_class
如widget_class "*.GtkButton.*" style "button-content"
3.应用指定风格
如果一个应用开发者已经明确陈列一种元素,在gtkrc文件中指明元素名,来将它风格化。
eg: widget “funky bar“ style “mystyle“
4.风格绑定的优先次序
对widget的rc风格绑定 > 对widget_class风格的绑定 > class 同一种组件的多种声明是,后一种优于前一种。指定优先的highest,rc,theme,application,gtk,lowest将覆盖上述的风格绑定,
4)组件指定风格:
gtk api文档列表中,列出的style properties,对某种widget类型,是明确的,eg。GtkWiget::focus-line-width = 2
5)高级指定风格(依据gtk2正式文档):
界定符#,注释所在行的内容,在解析gtkrc文件时,将此行被忽略掉。
1.binding name {...} 声明绑定设置
2.calss pattern [ style | binding [ : priority ]] name 对继承层的一个具体的分支,指定风格或绑定设置
3.include finename: 在此处引入文件,如果不是包含绝对路径的文件名,将会在当前打开rc文件的文件夹下,搜索此文件
4.module_path path: 设置搜索rc文件中涉及的主题引擎路径。
5.pixmap_path path: 设置搜索像素图的路径。
6.widget pattern [ style | binding [ : priority ]] name 给路径名上相配匹配的一组具体的组件设置风格或绑定。
7.widget_class pattern [ style | binding [ : priority ]] nane 给路径名上相匹配的一组具体的组件设置风格或绑定。
5.widget设置示例:
* Buttons:
buttons不存在背景的设置,只能通过对其所处的widget上添加背景的处理。
bevelling (relief): 对button进行三种状态的设置: GTK_RELIEF_NORMAL, GTK_RELIEF_HALF, GTK_RELIEF_NONE.
* Labels:
不存在背景色,估计可以通过text[]这一属性设置其前景色
* Text Boxes:
背景: base[NORMAL]
文本颜色: text[NORMAL]
应用自定义的风格: widget_class "*TextView*" style "my_style"
改变编辑时光标的颜色eg: GtkWidget::cursor-color "red"
* Scrollbars and Scales:
使用 widget_class "*Scrollbar*" 来指定scrollbars.
arrow button and main draggable rectangle colour is controlled by bg[NORMAL]
槽和边框设置背景色 bg[ACTIVE]
鼠标光标移动scrollbar(滚动条)上时的颜色使用bg[PRELIGHT]设置
光标箭头的颜色fg[NORMAL]
* Combobox: http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GtkComboBox
combobox是一个按钮包含:label, separator, and arrow
* Icons:
设置自定义的图标
stock["my-stock-item"] =
{
{ "itemmenusize.png", *, *, "gtk-menu" },
{ "itemtoolbarsize.png", *, *, "gtk-large-toolbar" }
{ "itemgeneric.png" } /* implicit *, *, * as a fallback */
}
* Menus:
菜单是一个组合控件,包括menubar和menuitems.
* Lists:
与Treeview组合为一个整体.
* Treeview:
Treeview开为两部分:head_window,bin_window,该组件可以按元素列表和树的形式显示
Treeview 背景色是通过base[]控制,如果处于非关注状态则按base[ACTIVE]的着色显示.
设置Treeview的列的顶部的颜色,使用bg控制.
Treeview列的顶部为一个按钮. 指定widget_class "*TreeView.GtkButton*". 指定顶部文本的颜色The text colour in the heads is controlled with fg, and not text.
The default line spacing of TreeView lists is quite large. It is not possible to reduce it in the rc file. This is a known issue.
Treeview 风格自属性有: allow-rules, even-row-color, expander-size, horizontal-separator, indent-expanders, odd-row-color, vertical-separator.
* Tabs:
文本内容在非选中的tab上使用的是fg[ACTIVE],背景色设置bg[ACTIVE].
定义tabs文本设置 widget_class "*GtkNotebook*GtkLabel".
* engine
gtk engines 给开发者提供大量不同的显示风格选项。通过使用不同的engine来设置不同风格的组件。
style "some-style" {
engine "clearlooks" {
# engine specific settings go here
}
}
三,主题实例
一个小例子:
………………
style "first"
{
xthickness = 2
ythickness = 2
fg[ACTIVE] = "#FFFFFF"
fg[SELECTED] = "#003366"
fg[NORMAL] = "#FFFFFF"
fg[PRELIGHT] = "#FFFFFF"
font_name = "Sans Bold 14"
}
………………
widget "first_win.*" style "first"
………………
颜色可以使用颜色的名称(GTK+ knows all names from the X color database /usr/lib/X11/rgb.txt),使用一种16进制的形式例如#rrrrggggbbbb, #rrrgggbbb, #rrggbb, or #rgb。r,g,b是16进制的整数(0-65535)或者是浮点数字0.0-1.0
从2.10开始颜色可以使用符号颜色 以@color-name 或者是用表达式合成颜色。
程序中怎么写???
GtkWidget tlHello;
tlHello = gtk_label_new ("Hello WORLD!/nGood night!");
gtk_widget_set_name (tlHello, "first_win");
gtk_widget_show (tlHello);
………………
例子:
# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
#
pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
#
# style <name> [= <name>]
# {
# <option>
# }
#
# widget <widget_set> style <style_name>
# widget_class <widget_class_set> style <style_name>
# 这里列出所有状态。注意有些状态不能用在一定的构件上。
#
# NORMAL -构件的一般状态,如鼠标不位于构件上方,键未按下时构件所处的状态。
#
# PRELIGHT - 当鼠标移到构件上方,在此状态下定义的颜色生效。
#
#
# ACTIVE -当处于构件上的鼠标键被按下或点击时,该构件被激活,相应的属性值将生效。
#
#
# INSENSITIVE -当构件被设置为不敏感 (insensitive) 时,它不能被激活,相应属性值起作用。
#
#
# SELECTED -选中一个对象时,取相应的属性值。
#
# 给定了这些状态,我们就能使用以下指令设置在这些状态下构件的属性。
#
# fg - 设置构件的前景色。
# fg - 设置构件的背景色。
# bg_pixmap - 设置构件的背景为一幅象素图。
# font - 设置给定构件所用的字体。
#
# 本例设置一种名为"button"的风格。这个名称实际不重要,因为在本文件的后面这个风格都分
# 配给了实际的构件。
style "window"
{
#此处设置窗口背景为指定的像素图。
#bg_pixmap[<STATE>] = "<pixmap filename>"
bg_pixmap[NORMAL] = "warning.xpm"
}
style "scale"
{
#设置"NORMAL"状态下前景色(字体颜色)为红色。
fg[NORMAL] = { 1.0, 0, 0 }
#设置此构件的背景像素图为其父构件的背景像素图。
bg_pixmap[NORMAL] = "<parent>"
}
style "button"
{
# 显示一个按钮的所有可能状态,唯一未用的状态是SELECTED。
fg[PRELIGHT] = { 0, 1.0, 1.0 }
bg[PRELIGHT] = { 0, 0, 1.0 }
bg[ACTIVE] = { 1.0, 0, 0 }
fg[ACTIVE] = { 0, 1.0, 0 }
bg[NORMAL] = { 1.0, 1.0, 0 }
fg[NORMAL] = { .99, 0, .99 }
bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
fg[INSENSITIVE] = { 1.0, 0, 1.0 }
}
# 在本例中,我们继承"button"风格的属性,然后重设PRELIGHT状态下的字体和背景色以创建一个新的"main_button"风格。
style "main_button" = "button"
{
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
bg[PRELIGHT] = { 0.75, 0, 0 }
}
style "toggle_button" = "button"
{
fg[NORMAL] = { 1.0, 0, 0 }
fg[ACTIVE] = { 1.0, 0, 0 }
# 这里设置toggle_button的背景像素图为其父构件的像素图(在应用程序中已定义)。
bg_pixmap[NORMAL] = "<parent>"
}
style "text"
{
bg_pixmap[NORMAL] = "marble.xpm"
fg[NORMAL] = { 1.0, 1.0, 1.0 }
}
style "ruler"
{
font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
}
# pixmap_path "~/.pixmaps"
# 下面设置使用以上所定义风格的构件类型。
# 构件类型是在类的组织中列出的,但是恰有可能在本文档中列出供用户参考。
widget_class "GtkWindow" style "window"
widget_class "GtkDialog" style "window"
widget_class "GtkFileSelection" style "window"
widget_class "*Gtk*Scale" style "scale"
widget_class "*GtkCheckButton*" style "toggle_button"
widget_class "*GtkRadioButton*" style "toggle_button"
widget_class "*GtkButton*" style "button"
widget_class "*Ruler" style "ruler"
widget_class "*GtkText" style "text"
# 设置作为“main windows”的子构件的所有按钮构件为main_button风格。
# 这些(专门命名的构件)都必须附有文档说明让用户更好地使用它们。
widget "main window.*GtkButton*" style "main_button"]
最后,我们要注意的是,模式也是有优先级的样式覆盖其他的样式依靠优先级,他们的顺序是从高到底:
rc
theme
application
gtkSpecifies a style or binding set for a particular branch of the inheritance hierarchy.
rc默认是从rc文件读出来,theme默认是从theme rc文件读,application是在一个程序建立的时候定义的,gtk是gtk+默认的样式
四,GTKRC文件写法规则,定制RC文件
1.为专用的应用程序使用专业的rc文件
2.把同一个模式的匹配尽量放到一起
例如:
style "Foo" { foo_content }
class "X" style "Foo"
style "Bar" { bar_content }
class "X" style "Bar"
修改成为:
style "FooBar" { foo_content bar_content }
class "X" style "FooBar"
3.尽量的减少使用统配符
4.避免递归的匹配多使用全的路径名称,尽量少使用统配符
5.在可能的情况下只在头或者是结尾使用统配符
6.尽量使用?代替*这样可以降低查找的复杂度
7.*要尽量少的使用