在Gtk+中使用流式布局
搞Gtk的大牛们搞什么飞机哦,布局Widget这样的东西,居然被大牛们当成MM一样藏起来拉!就藏在GIMP里面作Custom Widget也不放到GTK作为标准控件。
做一个小玩意时我遇到了一个比较令人苦恼的问题,那就是Gtk+ 的布局管理Widget里面没有那种像Java Flowlayout一样的东西。什么box,什么frame,都不是我想要的。
记得学java布局管理的时候觉得流式布局真白痴,其实也有可用之处啊,最典型的就是GIMP和Dia这样的toolbox啦,就像下面这样,在WIndows的UI系统里面搞这个不是那么容易的吧…

Dia toolbox
我在Gtk的参考里面找啊找,还是没找到,于是去看Dia的源代码去。
NNNNND!我我居然发现了一个叫GtkWrapBox的Widget。NNND,去google一看,还真有这个玩意,就在Gimp的在线Gtk接口文档中。
可以看到这个叫GtkWrapBox的Widget有两个派生,分别是横向折行和纵向折行;可以看到这个叫GtkWrapBox的Widget还是GtkContainer的派生类;但是最可恶的地方就是——你去看文档里面的Object Hierarchy吧,GtkContainer下绝对没有GtkWrapBox,GtkWrapBox的上层Object绝对是 GtkContainer。NND。
http://developer.gimp.org/api/2.0/app/GtkWrapBox.html#id3166842
http://developer.gimp.org/api/2.0/gtk/GtkContainer.html#id3824858
搞Gtk的大牛们搞什么飞机哦,布局Widget这样的东西,居然被大牛们当成MM一样藏起来拉!就藏在GIMP里面作Custom Widget也不放到GTK作为标准控件。
好了,既然这样就好办了。我去把GtkWrapBox的源码搞过来看一下就好了。源码如下:
$ ls *.c *.h
gtkhwrapbox.c gtkvwrapbox.c gtkwrapbox.c
gtkhwrapbox.h gtkvwrapbox.h gtkwrapbox.h
下面我来测试一下下啦。我拿GTK 的Hello World改了一段代码,可用!
[main.c]:
#include
#include
#include
#include "gtkhwrapbox.h"
/* This is a callback function. The data arguments are ignored
* in this example. More on callbacks below. */
static void hello( GtkWidget *widget,
gpointer data )
{
g_print ("Hello World\n");
}
static gboolean delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
/* If you return FALSE in the "delete_event" signal handler,
* GTK will emit the "destroy" signal. Returning TRUE means
* you don't want the window to be destroyed.
* This is useful for popping up 'are you sure you want to quit?'
* type dialogs. */
g_print ("delete event occurred\n");
/* Change TRUE to FALSE and the main window will be destroyed with
* a "delete_event". */
return TRUE;
}
/* Another callback */
static void destroy( GtkWidget *widget,
gpointer data )
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *button[10];
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application. */
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
//给windows连接delete_event信号
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
//给windows连接destroy信号
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
//设置边框
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
// 创建一个 hwrapbox
GtkWidget * wrapbox = gtk_hwrap_box_new(FALSE);
/* 创建 10 个 button with the label "Fuck Off". */
int i = 0;
for (i = 0; i < 10; ++i) {
button[i] = gtk_button_new_with_label ("Fuck Off");
//将clicked信号连接到hello函数
g_signal_connect (G_OBJECT (button[i]), "clicked",
G_CALLBACK (hello), NULL);
//将clicked信号连接到gtk_widget_destroy, 考虑到该
//函数接受一个widget参数, So, 使用g_signal_connect_swapped
g_signal_connect_swapped (G_OBJECT (button[i]), "clicked",
G_CALLBACK (gtk_widget_destroy), G_OBJECT (window));
//将各个button打包进wrapbox
gtk_wrap_box_pack(GTK_WRAP_BOX(wrapbox), button[i],
FALSE, FALSE, FALSE, FALSE);
//显示各个button
gtk_widget_show (button[i]);
}
//把wrapbox加入window
gtk_container_add (GTK_CONTAINER (window), wrapbox);
// 显示wrapbox和windows.
gtk_widget_show (wrapbox);
gtk_widget_show (window);
//gtk main入口函数
gtk_main ();
return 0;
}
这里是我用的makefile:
[makefile]:
GLADE_ADD = -export-dynamic -Wall
LINKFLAGS = `pkg-config --libs gtk+-2.0 libglade-2.0` $(GLADE_ADD)
CFLAGS = `pkg-config --cflags gtk+-2.0 libglade-2.0` $(GLADE_ADD)
OBJ = main.o gtkhwrapbox.o gtkvwrapbox.o gtkwrapbox.o
main: $(OBJ)
gcc -o main $(OBJ) $(LINKFLAGS)
%.o: %.c
gcc -g -c $(CFLAGS) $< -o $@
clean:
rm -f *.o main
下面是screenshot, 还是可以的啦 , 不过嗯个,还有个问题,因为这个玩意不属于gtk标准组件,所以pygtk里面也没有它啦,那...岂不是要我自己搞一下 (ToT)。


