GTK+中的构件II(Widgets)
在本章的GTK+程序设计中,我们仍然要继续向大家介绍和展示各种各样的构件。
GtkComboBox
GtkComboBox
构件的作用是让程序使用者根据不同的需求从很多选项中进行选择。
#include <gtk/gtk.h>
void combo_selected(GtkWidget *widget, gpointer window)
{
gchar *text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget));
gtk_label_set_text(GTK_LABEL(window), text);
g_free(text);
}
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *combo;
GtkWidget *label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GtkCombo");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
fixed = gtk_fixed_new();
combo = gtk_combo_box_new_text();
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mandriva");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Fedora");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mint");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Gentoo");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Debian");
gtk_fixed_put(GTK_FIXED(fixed), combo, 50, 50);
gtk_container_add(GTK_CONTAINER(window), fixed);
label = gtk_label_new("-");
gtk_fixed_put(GTK_FIXED(fixed), label, 50, 110);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
g_signal_connect(G_OBJECT(combo), "changed",
G_CALLBACK(combo_selected), (gpointer) label);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
上面的这个例子主要是完成一个个下拉选择框( combo box)和一个标签(label)。在这里下拉选择框有六个选项。他们的名字都是Linux操作系统的不同发行版本。标签中的内容就是我们所选择的那个选项的内容。
combo = gtk_combo_box_new_text();
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mandriva");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Fedora");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mint");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Gentoo");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Debian");
在上面,我们生成了一个GtkComboBox
构件;然后又把Linux 发行版本的名字填加到其中去。
label = gtk_label_new("-");
同样我们也生成了一个标签构件。
gchar *text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget));
gtk_label_set_text(GTK_LABEL(window), text);
g_free(text);
上面的代码表明,我们从所选的选项中获得了文本内容,并把此内容的传递给了标签构件。在官方公布的GTK+编程文本中显示:函数 gtk_combo_box_get_active_text()
的返回值是当前最新击活选项所对应的内容。这也就是说,我们有必要要释放对应的内存空间。
![GktComboBox](http://static.oschina.net/uploads/img/201503/08180906_9Crp.png)
GtkHSeparator
GtkHSeparator
构件是一条水平分割线。这也属于一种布局构件。这一类的构件都是出于界面设计需求的考虑。他的兄弟构件也就是竖直分割线构件 GtkVSeparator
。
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *label1;
GtkWidget *label2;
GtkWidget *hseparator;
GtkWidget *vbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window), "GtkHSeparator");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(window), 20);
label1 = gtk_label_new("Zinc is a moderately reactive, blue gray metal \
that tarnishes in moist air and burns in air with a bright bluish-green flame,\
giving off fumes of zinc oxide. It reacts with acids, alkalis and other non-metals.\
If not completely pure, zinc reacts with dilute acids to release hydrogen.");
gtk_label_set_line_wrap(GTK_LABEL(label1), TRUE);
label2 = gtk_label_new("Copper is an essential trace nutrient to all high \
plants and animals. In animals, including humans, it is found primarily in \
the bloodstream, as a co-factor in various enzymes, and in copper-based pigments. \
However, in sufficient amounts, copper can be poisonous and even fatal to organisms.");
gtk_label_set_line_wrap(GTK_LABEL(label2), TRUE);
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(window), vbox);
hseparator = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(vbox), label1, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, TRUE, 10);
gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, TRUE, 0);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
以上的代码正是在向我们展示了两个label构件,内容是讲的两种化学元素的定义;接着呢这两个构件又被一个叫做horizontal 的GtkHSeparator构件给分割开来了。这样看起来,整个程序界面就美观多啦!不是么?:)
label1 = gtk_label_new("Zinc is a moderately reactive, blue gray metal \
that tarnishes in moist air and burns in air with a bright bluish-green flame,\
giving off fumes of zinc oxide. It reacts with acids, alkalis and other non-metals.\
If not completely pure, zinc reacts with dilute acids to release hydrogen.");
我们首先生成了第一个label构件,内容是锌的定义。
gtk_label_set_line_wrap(GTK_LABEL(label2), TRUE);
当然得有换行啦!上面的代码就是给文本进行换行的。
hseparator = gtk_hseparator_new();
然后我们就又生成了一个水平分割器。(horizontal separator)
gtk_box_pack_start(GTK_BOX(vbox), label1, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, TRUE, 10);
gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, TRUE, 0);
最后我们把分割器放置在两个标签中间。
![GtkHSeparator](http://static.oschina.net/uploads/img/201503/08180907_K4hf.png)
GtkEntry
GtkEntry
构件是什么?她其实就是一个只拥有单行文本输入框的构件。她主要是用来进行单行文本的输入。
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *table;
GtkWidget *label1;
GtkWidget *label2;
GtkWidget *label3;
GtkWidget *entry1;
GtkWidget *entry2;
GtkWidget *entry3;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window), "GtkEntry");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
table = gtk_table_new(3, 2, FALSE);
gtk_container_add(GTK_CONTAINER(window), table);
label1 = gtk_label_new("Name");
label2 = gtk_label_new("Age");
label3 = gtk_label_new("Occupation");
gtk_table_attach(GTK_TABLE(table), label1, 0, 1, 0, 1,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_table_attach(GTK_TABLE(table), label2, 0, 1, 1, 2,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_table_attach(GTK_TABLE(table), label3, 0, 1, 2, 3,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
entry1 = gtk_entry_new();
entry2 = gtk_entry_new();
entry3 = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry1, 1, 2, 0, 1,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_table_attach(GTK_TABLE(table), entry2, 1, 2, 1, 2,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_table_attach(GTK_TABLE(table), entry3, 1, 2, 2, 3,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_widget_show(table);
gtk_widget_show(label1);
gtk_widget_show(label2);
gtk_widget_show(label3);
gtk_widget_show(entry1);
gtk_widget_show(entry2);
gtk_widget_show(entry3);
gtk_widget_show(window);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
在本节的例子中我们向大家展示的是三个文本输入框和分别对应的三个标签。
table = gtk_table_new(3, 2, FALSE);
gtk_container_add(GTK_CONTAINER(window), table);
为了方便我们管理构件,我们使用了table容器构件。
entry1 = gtk_entry_new();
entry2 = gtk_entry_new();
entry3 = gtk_entry_new();
生成三个文本输入框。
gtk_table_attach(GTK_TABLE(table), entry1, 1, 2, 0, 1,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_table_attach(GTK_TABLE(table), entry2, 1, 2, 1, 2,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
gtk_table_attach(GTK_TABLE(table), entry3, 1, 2, 2, 3,
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 5, 5);
把构件放置到table构件中。
![GtkEntry](http://static.oschina.net/uploads/img/201503/08180907_fOdU.png)
GtkImage
GtkImage
构件功能是用来显示图象的。
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *image;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
gtk_window_set_title(GTK_WINDOW(window), "Red Rock");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(window), 2);
image = gtk_image_new_from_file("redrock.png");
gtk_container_add(GTK_CONTAINER(window), image);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
在我们本节的这个例子中,我们向大家展示,我们是如何把一个城堡的图象用GTK+显示出来的。这个城堡叫做Red Rock 位于斯洛伐克的西部。如果你喜欢的话可以下载这个图片。 here.
gtk_container_set_border_width(GTK_CONTAINER(window), 2);
我们给这个图片设置了2px 的边框大小。
image = gtk_image_new_from_file("redrock.png");
gtk_container_add(GTK_CONTAINER(window), image);
我们从一个图象文件中加载了图象,并把他放到布局构件中。
![GtkImage](http://static.oschina.net/uploads/img/201503/08180910_FjKb.jpg)
GtkStatusbar
构件GtkStatusbar
是的功能是用来显示状态信息用的。他通常被自动强制放置于应用程序窗口的底部。
#include <gtk/gtk.h>
void button_pressed(GtkWidget *widget, gpointer window)
{
gchar *str;
str = g_strdup_printf("Button %s clicked",
gtk_button_get_label(GTK_BUTTON(widget)));
gtk_statusbar_push(GTK_STATUSBAR(window),
gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str);
g_free(str);
}
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *statusbar;
GtkWidget *vbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 280, 150);
gtk_window_set_title(GTK_WINDOW(window), "GtkStatusbar");
vbox = gtk_vbox_new(FALSE, 2);
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_box_pack_start(GTK_BOX(vbox), fixed, TRUE, TRUE, 1);
button1 = gtk_button_new_with_label("OK");
gtk_widget_set_size_request(button1, 80, 30 );
button2 = gtk_button_new_with_label("Apply");
gtk_widget_set_size_request(button2, 80, 30 );
gtk_fixed_put(GTK_FIXED(fixed), button1, 50, 50);
gtk_fixed_put(GTK_FIXED(fixed), button2, 150, 50);
statusbar = gtk_statusbar_new();
gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);
g_signal_connect(G_OBJECT(button1), "clicked",
G_CALLBACK(button_pressed), G_OBJECT(statusbar));
g_signal_connect(G_OBJECT(button2), "clicked",
G_CALLBACK(button_pressed), G_OBJECT(statusbar));
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
在我们上面的这段代码示例中,我们展示了两个按钮和一个状态栏。如果我们单击按钮,一条信息便在状态栏中显示出来。也就说,状态栏反映了哪个按钮被我们按下了。
gchar *str;
str = g_strdup_printf("Button %s clicked",
gtk_button_get_label(GTK_BUTTON(widget)));
这里我们生成了一条消息。
gtk_statusbar_push(GTK_STATUSBAR(window),
gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str);
然后我们把这条消息放置在状态栏中。
![GtkStatusbar](http://static.oschina.net/uploads/img/201503/08180910_I3jg.png)
GtkIconView
构件GtkIconView 的功能是用来在一个栅格中显示一系列的图标。
#include <gtk/gtk.h>
#include <assert.h>
enum
{
COL_DISPLAY_NAME,
COL_PIXBUF,
NUM_COLS
};
GtkTreeModel * init_model(void)
{
GtkListStore *list_store;
GdkPixbuf *p1, *p2, *p3, *p4;
GtkTreeIter iter;
GError *err = NULL;
p1 = gdk_pixbuf_new_from_file("ubuntu.png", &err);
p2 = gdk_pixbuf_new_from_file("gnumeric.png", &err);
p3 = gdk_pixbuf_new_from_file("blender.png", &err);
p4 = gdk_pixbuf_new_from_file("inkscape.png", &err);
assert(err==NULL);
list_store = gtk_list_store_new(NUM_COLS,
G_TYPE_STRING, GDK_TYPE_PIXBUF);
int i = 0;
for (i; i < 50; i++) {
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, COL_DISPLAY_NAME,
"ubuntu", COL_PIXBUF, p1, -1);
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, COL_DISPLAY_NAME,
"gnumeric", COL_PIXBUF, p2, -1);
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, COL_DISPLAY_NAME,
"blender", COL_PIXBUF, p3, -1);
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, COL_DISPLAY_NAME,
"inkscape", COL_PIXBUF, p4, -1);
}
return GTK_TREE_MODEL(list_store);
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *icon_view;
GtkWidget *sw;
gtk_init (&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), "Icon View");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_widget_set_size_request(window, 350, 330);
sw = gtk_scrolled_window_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER (window), sw);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
GTK_SHADOW_IN);
icon_view = gtk_icon_view_new_with_model(init_model());
gtk_container_add(GTK_CONTAINER(sw), icon_view);
gtk_icon_view_set_text_column(GTK_ICON_VIEW(icon_view),
COL_DISPLAY_NAME);
gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(icon_view),
COL_PIXBUF);
gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(icon_view),
GTK_SELECTION_MULTIPLE);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
在本节的代码示例中,我们显示了200个小图标。他们分别是四个著名开源项目的图标。
p1 = gdk_pixbuf_new_from_file("ubuntu.png", &err);
p2 = gdk_pixbuf_new_from_file("gnumeric.png", &err);
p3 = gdk_pixbuf_new_from_file("blender.png", &err);
p4 = gdk_pixbuf_new_from_file("inkscape.png", &err);
我们从磁盘文件中载入了四个图标。
list_store = gtk_list_store_new(NUM_COLS,
G_TYPE_STRING, GDK_TYPE_PIXBUF);
我们将存储文本和像素缓冲区(pixbuf)的数据。
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, COL_DISPLAY_NAME,
"ubuntu", COL_PIXBUF, p1, -1);
上面这段代码,正是把新图标填加到准备显示的缓存区中。
icon_view = gtk_icon_view_new_with_model(init_model());
gtk_container_add(GTK_CONTAINER(sw), icon_view);
gtk_icon_view_set_text_column(GTK_ICON_VIEW(icon_view),
COL_DISPLAY_NAME);
gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(icon_view),
COL_PIXBUF);
最后,我们又生成了一个GtkIconView
构件然后把图标和图标文本整合在一起。 (译者注:如果本节理解起来有难度的话,正是说明你对MVC的概念还不是很清楚,建议查看相关文档:))
![Icon View](http://static.oschina.net/uploads/img/201503/08180912_peMq.png)