这一小结,将要学习将构建布局在窗口和对话框中.为了方便的管理我们的构件,在GTK+中,通常使用不可见的构件称作layout containers.
这一小节将要讨论GtkAlignment,GtkFixed,GtkVBox,GtkTable.
(一):GtkFixed
容器构建GtkFixed用于布置子构件在一个固定的位置和设定固定的大小.这种构件并不属于自动的布局关系器.实质上,在大多数应用程序中,并不多使用GtkFixed;
而在只用于一些比较特殊的场合,例如:游戏,含有绘图功能的专用软件,那些需要移动和调整大小的软件(如电子表格中的图标)以及那些小型的教育用途软件.
下面我们看一个例子:
#include <gtk/gtk.h>
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *button3;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"GtkFixed");
gtk_window_set_default_size(GTK_WINDOW(window),290,200);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window),fixed);
button1 = gtk_button_new_with_label("Button");
gtk_fixed_put(GTK_FIXED(fixed),button1,150,50);
gtk_widget_set_size_request(button1,80,35);
button2 = gtk_button_new_with_label("Button");
gtk_fixed_put(GTK_FIXED(fixed),button2,15,15);
gtk_widget_set_size_request(button2,80,35);
button3 = gtk_button_new_with_label("Button");
gtk_fixed_put(GTK_FIXED(fixed),button3,100,100);
gtk_widget_set_size_request(button3,80,35);
g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
下面是运行的结果:
在上面的例子中,我们使用代码生成了三个按钮,这三个按钮布局在固定的位置上.当窗口的大小改变的时候,按钮将会固定保持他们的大小和固定的坐标.
使用函数gtk_fixed_new()就能够生成一个GtkFixed的容器构件.如果我们想要想容器中添加组件,使用函数:
gtk_fixed_put(),例如gtk_fixed_put(GTK_FIXED(fixed),button1,150,50);
button1的坐标为x=150,y=50
(二):GtkVBox
GtkVBox是一种用于垂直布局的容器构件,他把放置在他中的子构件放置在一个单独的列中.类似的是 GtkHBox是放在一个单独的行中,是一种水平布局.
下面我们看一个例子:
#include <gtk/gtk.h>
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *settings;
GtkWidget *accounts;
GtkWidget *loans;
GtkWidget *cash;
GtkWidget *debts;
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,250);
gtk_window_set_title(GTK_WINDOW(window),"GtkVBox");
gtk_container_set_border_width(GTK_CONTAINER(window),5);
vbox = gtk_vbox_new(TRUE,1);
gtk_container_add(GTK_CONTAINER(window),vbox);
settings = gtk_button_new_with_label("Settings");
accounts = gtk_button_new_with_label("Accounts");
loans = gtk_button_new_with_label("Loans");
cash = gtk_button_new_with_label("Cash");
debts = gtk_button_new_with_label("Debts");
gtk_box_pack_start(GTK_BOX(vbox),settings,TRUE,TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox),accounts,TRUE,TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox),loans,TRUE,TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox),cash,TRUE,TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox),debts,TRUE,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;
}
下面是程序的运行结果:
效果很明显,垂直排版,所以我们在排版菜单选项的时候,就是使用这个工具的.
在上面这个例子中,如果改变窗口大小的时候,按钮的大小也会发生改变的.
使用函数gtk_vbox_new()可以生成GtkBox构件.在本例子中:
vbox = gtk_vbox_new(TRUE,1);
第一个参数设置为TRUE,表示所有的按钮大小都是一样的,并且按钮之间的距离设置为”1”像素.
至于下面这个函数
gtk_box_pack_start(GTK_BOX(vbox),settings,TRUE,TRUE,0);
该函数将”settings”构件布局在vbox 容器中.其中该函数的前两个参数分别是存放构件的容器和搜要放置的构件.后面的三个参数分别是expand,fill和padding,如果fill对应的参数如果设置为FALSE的话,按钮就不会充满整个vbox构件.如果之前在gtk_vbox_new(TRUE,1);中已经设置按钮都是等宽高的话,expand对应的参数是完全没有效果的.(在这里尽量这两个参数都设置成TRUE).
(三):GtkTable容器
GTkTabel容器,顾名思义,该容器类似于一个表格,既可以按照行来布局,也可以按照列来布局.
下面是我们的一个例子.
#include <gtk/gtk.h>
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *table;
GtkWidget *button;
char *values[16] = {"7","8","9","/","4","5","6","*","1","2",
"3","-","0",".","=","+"};
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),250,180);
gtk_window_set_title(GTK_WINDOW(window),"GtkTable");
gtk_container_set_border_width(GTK_CONTAINER(window),5);
table = gtk_table_new(4,4,TRUE);
gtk_table_set_row_spacings(GTK_TABLE(table),2);
gtk_table_set_col_spacings(GTK_TABLE(table),2);
int i = 0;
int j = 0;
int pos = 0;
for(i = 0;i < 4;i++){
for(j = 0;j < 4;j++){
button = gtk_button_new_with_label(values[pos]);
gtk_table_attach_defaults(GTK_TABLE(table),button,j,j+1,i,i+1);
pos++;
}
}
gtk_container_add(GTK_CONTAINER(window),table);
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;
}
下面是运行之后的效果:
通过上面运行的效果,我们看到我们做的是一个计算机的布局.
table = gtk_table_new(4,4,TRUE);
这样就生成了一个GtkTabel布局构件,并设置为4行4列.
gtk_table_set_row_spacings(GTK_TABLE(table),2);
gtk_table_set_col_spacings(GTK_TABLE(table),2);
这两个函数的目的是设置每行与每列的距离.
for(i = 0;i < 4;i++){
for(j = 0;j < 4;j++){
button = gtk_button_new_with_label(values[pos]);
gtk_table_attach_defaults(GTK_TABLE(table),button,j,j+1,i,i+1);
pos++;
}
}
该代码将会生成16个按钮并把他们布局 在GtkTable容器构件中.
(四):GtkAlignment
GtkAlignment容器构件控制了她的子构件的对齐方式和大小.
下面我们看一个例子.
#include <gtk/gtk.h>
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *ok;
GtkWidget *close;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *halign;
GtkWidget *valign;
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),350,200);
gtk_window_set_title(GTK_WINDOW(window),"GtkAlignment");
gtk_container_set_border_width(GTK_CONTAINER(window),10);
vbox = gtk_vbox_new(FALSE,5);
valign = gtk_alignment_new(0,1,0,0);
gtk_container_add(GTK_CONTAINER(vbox),valign);
gtk_container_add(GTK_CONTAINER(window),vbox);
hbox = gtk_hbox_new(TRUE,3);
ok = gtk_button_new_with_label("OK");
gtk_widget_set_size_request(ok,70,30);
gtk_container_add(GTK_CONTAINER(hbox),ok);
close = gtk_button_new_with_label("Close");
gtk_container_add(GTK_CONTAINER(hbox),close);
halign = gtk_alignment_new(1,0,0,0);
gtk_container_add(GTK_CONTAINER(halign),hbox);
gtk_box_pack_start(GTK_BOX(vbox),halign,FALSE,FALSE,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;
}
下面是程序运行的结果:
在这个例子中,将两个按钮布局到一个窗口的右下角.为了实现这个效果,我们使用了一个水平盒子构建horizontal box,一个竖直盒子构建vertical box和两个对齐容器构件alignment containers.
valign = gtk_alignment_new(0,1,0,0);
这样生成一个对齐容器构件.
gtk_conatiner_add(GTK_CONTAINER(vbox),valign);
将对齐容器构件布局在水平盒子中.
hbox = gtk_hbox_new(TRUE,3);
ok = gtk_button_new_with_label("OK");
gtk_widget_set_size_request(ok,70,30);
gtk_container_add(GTK_CONTAINER(hbox),ok);
close = gtk_button_new_with_label("Close");
gtk_container_add(GTK_CONTAINER(hbox),close);
上面代码首先生成一个水平盒子,并将两个按钮布局在里面.
halign = gtk_alignment_new(1,0,0,0);
gtk_container_add(GTK_CONTAINER(halign),hbox);
gtk_box_pack_start(GTK_BOX(vbox),halign,FALSE,FALSE,0);
上述代码生成一个对齐容器构件,然后将其子控件布局在右边,我们把水平盒子添加到对齐容器构件中,然后又把对齐容器构件添加到竖直盒子中.
注意:对齐容器构建只能放置一个子构件.所以要用盒子构件来帮助布局.
(五):Windows
该构件是一个比较常用的构建,我们先看一下在代码中如何使用,再看一下运行之后的结果:
#include <gtk/gtk.h>
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *table;
GtkWidget *title;
GtkWidget *activate;
GtkWidget *halign;
GtkWidget *halign2;
GtkWidget *valign;
GtkWidget *close;
GtkWidget *wins;
GtkWidget *help;
GtkWidget *ok;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_widget_set_size_request(window,300,250);
gtk_window_set_resizable(GTK_WINDOW(window),FALSE);
gtk_window_set_title(GTK_WINDOW(window),"Windows");
gtk_container_set_border_width(GTK_CONTAINER(window),15);
table = gtk_table_new(8,4,FALSE);
gtk_table_set_col_spacings(GTK_TABLE(table),3);
title = gtk_label_new("Window");
halign = gtk_alignment_new(0,0,0,0);
gtk_container_add(GTK_CONTAINER(halign),title);
gtk_table_attach(GTK_TABLE(table),halign,0,1,0,1,GTK_FILL,GTK_FILL,0,0);
wins = gtk_text_view_new();
gtk_text_view_set_editable(GTK_TEXT_VIEW(wins),FALSE);
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(wins),FALSE);
gtk_table_attach(GTK_TABLE(table),wins,0,2,1,3,GTK_FILL | GTK_EXPAND,GTK_FILL | GTK_EXPAND,1,1);
activate = gtk_button_new_with_label("Activate");
gtk_widget_set_size_request(activate,50,30);
gtk_table_attach(GTK_TABLE(table),activate,3,4,1,2,GTK_FILL,GTK_FILL,1,1);
valign = gtk_alignment_new(0,0,0,0);
close = gtk_button_new_with_label("Close");
gtk_widget_set_size_request(close,70,30);
gtk_container_add(GTK_CONTAINER(valign),close);
gtk_table_set_row_spacing(GTK_TABLE(table),1,3);
gtk_table_attach(GTK_TABLE(table),valign,3,4,2,3,GTK_FILL,GTK_FILL | GTK_EXPAND,1,1);
halign2 = gtk_alignment_new(0,1,0,0);
help = gtk_button_new_with_label("Help");
gtk_container_add(GTK_CONTAINER(halign2),help);
gtk_widget_set_size_request(help,70,30);
gtk_table_set_row_spacing(GTK_TABLE(table),3,6);
gtk_table_attach(GTK_TABLE(table),halign2,0,1,4,5,GTK_FILL,GTK_FILL,0,0);
ok = gtk_button_new_with_label("OK");
gtk_widget_set_size_request(ok,70,30);
gtk_table_attach(GTK_TABLE(table),ok,3,4,4,5,GTK_FILL,GTK_FILL,0,0);
gtk_container_add(GTK_CONTAINER(window),table);
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+图形开发中至关重要的一个问题,就是通过signal来实现事件的监听,同时了解一下信号机制的内部原理。