最后的叶子
这一部分内容介绍有关GTK+常用文本类物件的一些函数。如果对内容有疑问,请在下方留言,谢谢!
GTK+的文本
显示文字和控制文本框自然是界面重头戏,基本每个窗口都离不开这样的物件。GTK+中和文本有关的物件主要有:文本标签(GtkLabel,以下简 称“文本”),输入框(GtkEntry),可编辑多行文本(GtkTextView,以下简称“多行文本”),调节按钮 (GtkSpinButton)。各物件有自己的优点。
- 文本:简单地显示一些文字,使用非常方便,一般用于显示界面上最普通的文字。
- 输入框:用于让用户输入一行文字,使用方便。
- 多行文本:用于让用户输入多行文字,或显示一段非常长的文字,可配合滚动区(GtkScrolledWindow)使用来达到很好的显示效果,也可为部分文字设置样式。它的缺陷在于使用繁琐。
- 调节按钮:用于输入数字,在控制数字输入方面的功能非常强大,其右侧有上下调节数字大小的按钮。
具体使用哪个物件需要根据实际情况决定。
访问文本、输入框
对文本类物件的操作基本相似。对这些物件的动态访问基本归结为以下两种——读取所包含的文字信息(读)、设置所包含的文字内容(写)。其他的设置基本不需要动态改变,初始时在Glade中设置好即可(如果真的需要修改,自己去看参考吧)。
下面这些函数用于对文本、输入框的读写,函数名字都很好记。
//写入文本内容
void
gtk_label_set_text(
GtkLabel *
label,
const
gchar *
str)
;
//读取文本内容
const
gchar*
gtk_label_get_text(
GtkLabel *
label)
;
//写入输入框内容
void
gtk_entry_set_text(
GtkEntry *
entry,
const
gchar *
text)
;
//读取输入框内容
const
gchar*
gtk_entry_get_text(
GtkEntry *
entry)
;
|
使用调节按钮
调节按钮是用于操作数字的,因而可以直接向其中写入或者读出实数或整数。
//设置调节按钮的数值
void
gtk_spin_button_set_value (
GtkSpinButton *
spin_button,
gdouble value)
;
//读出调节按钮的数值
gdouble gtk_spin_button_get_value (
GtkSpinButton *
spin_button)
;
gint gtk_spin_button_get_value_as_int(
GtkSpinButton *
spin_button)
;
|
做个实例吧。本系列第三部分做了一个计算器雏形,下面来稍稍完善一下。
计算器的上方有一个名为SAns的调节按钮,下面增加一个功能:当调节按钮的值的绝对值过大(大于等于常数CAL_ABS_MAX)时,弹出错误提示窗口。
每个调节按钮对应一个GtkAdjustment,首先应为调节按钮添加一个GtkAdjustment。在Glade中,点“常规”的“调整部件”右侧的“…”,弹出窗口中点“New”。
此时上方的物件选择栏末尾中会出现一个对象adjustment1,可以更改它的属性,即调节按钮的最值、步长等。
然后为SAns的信号value-changed添加操作句柄“on_SAns_value_changed”,然后在程序中添加相应回调函数。
回到程序中,在初始化时,用gtk_spin_button_set_range()修改调节按钮取值范围为 [-CAL_ABS_MAX,CAL_ABS_MAX],再编写回调函数on_SAns_value_changed(),顺便用上上一部分写的函数 gtk_show_error()。完整代码如下。
#include <gtk/gtk.h>
#define CAL_ABS_MAX 1e9
#define w_(builder,type,name) name=GTK_##type(gtk_builder_get_object(builder,#name))
GtkWindow *
WMain;
GtkSpinButton *
SAns;
//显示一个错误提示窗口
void
gtk_show_error(
gpointer window,
const
gchar*
message,
const
gchar*
title)
{
GtkWidget *
dialog;
dialog =
gtk_message_dialog_new_with_markup(
window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
message)
;
gtk_window_set_title(
GTK_WINDOW(
dialog)
,
title)
;
gtk_dialog_run(
GTK_DIALOG(
dialog)
)
;
gtk_widget_destroy(
dialog)
;
}
G_MODULE_EXPORT void
on_SAns_value_changed(
GtkObject*
widget,
gpointer user_data)
{
//gdouble在Windows下等价于double
gdouble d;
//读取调节按钮的值
d=
gtk_spin_button_get_value(
SAns)
;
//判断是否需要显示错误提示窗口
if
(
d>=
CAL_ABS_MAX)
{
gtk_show_error(
WMain,
"Too Large"
,
"Error!"
)
;
//设置调节按钮值为零
gtk_spin_button_set_value(
SAns,
0
)
;
}
else
if
(
-
d>=
CAL_ABS_MAX)
{
gtk_show_error(
WMain,
"Too Small"
,
"Error!"
)
;
//设置调节按钮值为零
gtk_spin_button_set_value(
SAns,
0
)
;
}
}
G_MODULE_EXPORT void
on_WMain_destroy(
GtkObject*
widget,
gpointer user_data)
{
gtk_main_quit(
)
;
}
GtkBuilder*
gtk_load_glade(
gchar*
filename)
{
GtkBuilder *
gb;
gb=
gtk_builder_new(
)
;
if
(
!
gtk_builder_add_from_file(
gb,
filename,
NULL)
)
return
NULL;
gtk_builder_connect_signals(
gb,
NULL)
;
return
gb;
}
void
cal_get_widgets(
GtkBuilder*
gb)
{
w_(
gb,
WINDOW,
WMain)
;
w_(
gb,
SPIN_BUTTON,
SAns)
;
}
void
cal_widget_init(
)
{
//初始化,设置调节按钮取值范围,数值超出此范围时自动调整为边界值。
gtk_spin_button_set_range(
SAns,-
CAL_ABS_MAX,
CAL_ABS_MAX)
;
gtk_widget_show_all(
GTK_WIDGET(
WMain)
)
;
}
int
main(
int
argc,
char
*
argv[
]
)
{
GtkBuilder *
gb;
gtk_init(
&
argc,&
argv)
;
gb=
gtk_load_glade(
"gtk-cal.glade"
)
;
if
(
gb==
NULL)
return
-
1
;
cal_get_widgets(
gb)
;
cal_widget_init(
)
;
gtk_main(
)
;
return
0
;
}
|
在以后的内容中,这个计算器将被逐渐完善。
访问多行文本
多行文本的使用比较复杂,涉及几个其他对象的使用。一个多行文本的内容储存在一个缓冲区GtkTextBuffer中,这个缓冲区需要用迭代器GtkTextIter访问、用GtkTextMark标记,文字样式用GtkTextTag设置。
看起来真的有些复杂。不过最基本的应用还是读、写。下面给出三个函数,可以直接读写多行文本。这几个函数基本够用了。
//读取多行文本中的文字内容
gchar*
gtk_text_view_get(
GtkTextView *
text_view)
{
GtkTextBuffer *
tb;
GtkTextIter st,
stp;
tb=
gtk_text_view_get_buffer(
text_view)
;
//获取对应的GtkTextBuffer
gtk_text_buffer_get_start_iter(
tb,&
st)
;
//获得起始点
gtk_text_buffer_get_end_iter(
tb,&
stp)
;
//获得结束点
return
gtk_text_buffer_get_text(
tb,&
st,&
stp,
FALSE)
;
//获得两点间所有字符
}
//在多行文本末尾追加文字,文字样式包含在text_tag中,如果不需要指定样式,text_tag设为NULL
void
gtk_text_view_append_with_tag(
GtkTextView*
text_view,
const
gchar*
text,
GtkTextTag*
text_tag)
{
GtkTextBuffer *
tb;
GtkTextIter stp;
tb=
gtk_text_view_get_buffer(
text_view)
;
gtk_text_buffer_get_end_iter(
tb,&
stp)
;
gtk_text_buffer_insert_with_tags(
tb,&
stp,
text,
strlen(
text)
,
text_tag,
NULL)
;
//在结束点处追加字符
gtk_text_buffer_get_end_iter(
tb,&
stp)
;
gtk_text_view_scroll_to_iter(
text_view,&
stp,
0
,
FALSE,
0
,
0
)
;
//将光标置于结束点
}
//清空多行文本
void
gtk_text_view_clear(
GtkTextView *
text_view)
{
gtk_text_buffer_set_text(
gtk_text_view_get_buffer(
text_view)
,
""
,
0
)
;
//设置文本内容为空
}
|
此外,样式可以这样新建:
gtk_text_buffer_create_tag(
gtk_text_view_get_buffer(
text_view)
,
tag_name,
property1,
value1,
property2,
value2,
... ,
NULL)
;
|
text_view是多行文本名字;tag_name是一个字符串,值不能和别的样式相同;property1,2,3,…各属性名字(字符串形式),可用的属性参见http://library.gnome.org/devel/gtk/unstable/GtkTextTag.html 中的Property栏;value1,2,3,…各属性对应的值(字符串形式)。
如果以上的方法不够用,只好查参考了。
小提醒:多行文本一般都需要放在滚动区(GtkScrolledWindow)里面。
处理UTF-8字符串
要注意的问题是,GTK+内部使用UTF-8编码。在处理非ASCII编码的字符串时,切不可使用C语言string.h里的函数。在UTF-8 中,字符含义比较复杂。还好,GLib中提供了很多用于处理多种编码字符串的函数,下面介绍一些用于处理UTF-8字符串的函数。
在http://library.gnome.org/devel/glib/stable/glib-Unicode-Manipulation.html 中介绍了很多有关UTF-8字符串的实用函数。这些函数命名与string.h里的常用函数相近,只是多了前缀g_utf8_,表示是专门用来处理UTF-8字符串的。介绍几个吧。
- g_utf8_strlen():统计UTF-8字符串中的字符数。在UTF-8编码中,不同语言的字符所占用的字节数不同(例如一个中文字符占3个字节),因而UTF-8所包含的字符数小于等于它的字节数,并且没有一个固定的关系。这个函数还是很常用且重要的。
- g_utf8_find_prev_char():已知某个字符的首地址,查找它前一个字符的首地址。因为不同语言的字符所占用的字节数不同,两个紧邻字符地址之差可能大于1。
- g_utf8_find_next_char():已知某个字符的首地址,查找它后一个字符的首地址。
- g_utf8_strncpy():拷贝出字符串的前n个字符(而不是前n个字节)。
- g_utf8_strchr():找到一个给定的字符最左端出现的位置。UTF-8字符串中字符是gunichar型,相当于一个32位无符号整数,对于非ASCII字符,其值大于127。
- g_utf8_collate():比较两个字符串的大小(以字典序靠前的为小)。这个函数的强大之处在于,它可以根据所处的语言环境来判断两个字符串的字典顺序,可以比较任何语言的UTF-8字符串!
在http://library.gnome.org/devel/glib/stable/glib-String-Utility-Functions.html 列 出了一些跨字符集的实用函数,适用于任何字符集。其中有一部分常常能用上,比如g_snprintf()和g_strdup_printf(),它们的功 能与C语言sprintf类似,都是把一串格式输出写进字符串里(常用于数字和字符混合输出到字符串里),但g_snprintf()和 g_strdup_printf()更安全。g_snprintf()需要指定目的字符串长度,避免输出越界;g_strdup_printf()则在函 数内部自行申请足够的空间存放目的字符串(注意它返回的字符串废弃之后需要用g_free()释放空间)。
在http://library.gnome.org/devel/glib/stable/glib-Character-Set-Conversion.html 有一些字符集转换的函数,有些需要字符集转换的场合会用得上(比如文件名可能不是UTF-8编码,有时需要转换)。