Linux 版 (精华区)

发信人: netiscpu (平淡是真), 信区: Linux
标  题: GTK入门导引(4)
发信站: 紫 丁 香 (Mon Dec 14 14:38:10 1998), 转信


发信人: hey (吟风·悠游98), 信区: Unix
标  题: GTK入门导引(4)
发信站: 华南网木棉站 (Tue Nov 10 10:44:12 1998), 转信

4. 封装物件

当我们制作一套软体, 您会希望在视窗内放超过一个以上的按钮. 我们第一个
范例"hello world"仅用一个物件, 因此我们能够很简单使用gtk_container_add
来"封装"该物件到视窗中. 但当您希够望放更多的物件到视窗中, 要如何控制它
们的位置? 这里就要用到"封装"(Packing). 

4.1 Packing Boxes的理论 

大部份的封装是由产生boxes来达成的. 这些是看不见的widget containers, 我
们可以用两种形式来将我们的物件封装进去, vertical box及horizontal box. 当
我们封装物件到一个horizontal box时, 物件是依我们呼叫的顺序由右至左平行
的被新增进去. 在vertical box, 物件是由上至下. 您可以将物件插入box, 也可以
将boxes插入box, 任意的组合用以产生所想要的效果. 

要产生horizontal box,我们使用gtk_hbox_new(), 而vertical boxe使用
gtk_vbox_new(). gtk_box_pack_start()及gtk_box_pack_end()函数 是用来将
物件放到containers里面. gtk_box_pack_start()函数会开始由左至右, 由上至
下来封装物件. gtk_box_pack_end()则相反, 由下至上, 由右至左. 使用这些函
数允许我们对右边或对左边较正, 而且可以用许多种方式来较正来取得所想要
的效果. 一个object可以是另一个container或物件. 而且事实上, 许多物件本身
也是containers. 像按钮就是, 不过我们一般只在按钮中用一个标签. 

使用这些呼叫, GTK知道要把物件放到那里去, 并且会自动缩放及其它比例上
的调整. 还有许多其它选项可以控制如何将物件封装在一起. 正如您所想的, 这
些方法可以给您许多的弹性来制作视窗. 

4.2 Boxes详述 

由于这样的弹性, packing boxes在一开始使用的话会有点搞糊涂. 还有许多其
它的选项,一开始还看不太出来它们如何凑在一起. 最后您会知道, 他们基本上
有五种不同的型式. 



每一行包含一个horizontal box (hbox)及好几个按钮. 所有按钮都是以同样的方
式来包入hbox内. 

这是gtk_box_pack_start的宣告. 

    void gtk_box_pack_start (GtkBox    *box,
                             GtkWidget *child,
                             gint       expand,
                             gint       fill,
                             gint       padding);

第一个参数是您要把object放进去的box, 第二个是该object. 现在这些物件将
会都是按钮. 

expand参数在gtk_box_pack_start()或gtk_box_pack_end()中控制 物件如何
在box中排列. expand = TRUE的话它们会填满box中所有额外的空间. expand
= FALSE的话, 该box会缩小到刚好该物件的大小. 设expand=FALSE您可做
好左右较正. 否则它们会填满整个box. 同样的效果可用tk_box_pack_start或
pack_end functions来达成. 

fill参数在gtk_box_pack中控制额外空间. fill=TRUE该物件会自行产生额外空
间, fill=FALSE则由box产生一个在物件周围的填白区域. 这只有在
expand=TRUE时, 才会有作用. 

当产生一个新的box, 该函数看起来像这样: 

    GtkWidget * gtk_hbox_new (gint homogeneous,
                              gint spacing);

homogeneous参数在gtk_hbox_new (and the same for gtk_vbox_new) 控制
每个物件是否有同样的宽或高. 若homogeneous=TRUE, 则expand也会被开
启. 

空白(spacing)及填白(padding)有什么不同呢 空白是加在物件之间, 填白只加
在物件的一边. 看以下这张图可能会明白一点: 



这里是一些用来产生以上影像的程式. 我做了蛮多的注解, 希望您不会有问题.
将它编译然后玩玩它. 

4.3 封装示范程式 

    #include "gtk/gtk.h"

    void
    destroy (GtkWidget *widget, gpointer *data)
    {
        gtk_main_quit ();
    }

    /* Make a new hbox filled with button-labels. Arguments for the 
     * variables we're interested are passed in to this function. 
     * We do not show the box, but do show everything inside. */
    GtkWidget *make_box (gint homogeneous, gint spacing,
                         gint expand, gint fill, gint padding) 
    {
        GtkWidget *box;
        GtkWidget *button;
        char padstr[80];
        
        /* create a new hbox with the appropriate homogeneous and spacing
         * settings */
        box = gtk_hbox_new (homogeneous, spacing);
        
        /* create a series of buttons with the appropriate settings */
        button = gtk_button_new_with_label ("gtk_box_pack");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);
        
        button = gtk_button_new_with_label ("(box,");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);
        
        button = gtk_button_new_with_label ("button,");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);
        
        /* create a button with the label depending on the value of
         * expand. */
        if (expand == TRUE)
                button = gtk_button_new_with_label ("TRUE,");
        else
                button = gtk_button_new_with_label ("FALSE,");
        
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);
        
        /* This is the same as the button creation for "expand"
         * above, but uses the shorthand form. */
        button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);
        
        sprintf (padstr, "%d);", padding);
        
        button = gtk_button_new_with_label (padstr);
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);
        
        return box;
    }

    int
    main (int argc, char *argv[])
    {
        GtkWidget *window;
        GtkWidget *button;
        GtkWidget *box1;
        GtkWidget *box2;
        GtkWidget *separator;
        GtkWidget *label;
        GtkWidget *quitbox;
        int which;
        
        /* Our init, don't forget this! :) */
        gtk_init (&argc, &argv);
        
        if (argc != 2) {
            fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
            /* this just does cleanup in GTK, and exits with an exit status of 1. */
            gtk_exit (1);
        }
        
        which = atoi (argv[1]);

        /* Create our window */
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

        /* You should always remember to connect the destroy signal to the
         * main window.  This is very important for proper intuitive
         * behavior */
        gtk_signal_connect (GTK_OBJECT (window), "destroy",
                            GTK_SIGNAL_FUNC (destroy), NULL);
        gtk_container_border_width (GTK_CONTAINER (window), 10);
        
        /* We create a vertical box (vbox) to pack the horizontal boxes into.
         * This allows us to stack the horizontal boxes filled with buttons one
         * on top of the other in this vbox. */
        box1 = gtk_vbox_new (FALSE, 0);
        
        /* which example to show.  These correspond to the pictures above. */
        switch (which) {
        case 1:
            /* create a new label. */
            label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
            
            /* Align the label to the left side.  We'll discuss this function and 
             * others in the section on Widget Attributes. */
            gtk_misc_set_alignment (GTK_MISC (label), 0, 0);

            /* Pack the label into the vertical box (vbox box1).  Remember that 
             * widgets added to a vbox will be packed one on top of the other in
             * order. */
            gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
            
            /* show the label */
            gtk_widget_show (label);
            
            /* call our make box function - homogeneous = FALSE, spacing = 0,
             * expand = FALSE, fill = FALSE, padding = 0 */
            box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);

            /* call our make box function - homogeneous = FALSE, spacing = 0,
             * expand = FALSE, fill = FALSE, padding = 0 */
            box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* creates a separator, we'll learn more about these later, 
             * but they are quite simple. */
            separator = gtk_hseparator_new ();
            
            /* pack the separator into the vbox.  Remember each of these
             * widgets are being packed into a vbox, so they'll be stacked
             * vertically. */
            gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
            gtk_widget_show (separator);
            
            /* create another new label, and show it. */
            label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
            gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
            gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
            gtk_widget_show (label);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* another new separator. */
            separator = gtk_hseparator_new ();
            /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
            gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
            gtk_widget_show (separator);
            
            break;

        case 2:

            /* create a new label, remember box1 is a vbox as created 
             * near the beginning of main() */
            label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
            gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
            gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
            gtk_widget_show (label);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            separator = gtk_hseparator_new ();
            /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
            gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
            gtk_widget_show (separator);
            
            label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
            gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
            gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
            gtk_widget_show (label);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* Args are: homogeneous, spacing, expand, fill, padding */
            box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            separator = gtk_hseparator_new ();
            /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
            gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
            gtk_widget_show (separator);
            break;
        
        case 3:

        /* This demonstrates the ability to use gtk_box_pack_end() to
             * right justify widgets.  First, we create a new box as before. */
            box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
            /* create the label that will be put at the end. */
            label = gtk_label_new ("end");
            /* pack it using gtk_box_pack_end(), so it is put on the right side
             * of the hbox created in the make_box() call. */
            gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
            /* show the label. */
            gtk_widget_show (label);
            
            /* pack box2 into box1 (the vbox remember ? :) */
            gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
            gtk_widget_show (box2);
            
            /* a separator for the bottom. */
            separator = gtk_hseparator_new ();
            /* this explicitly sets the separator to 400 pixels wide by 5 pixels
             * high.  This is so the hbox we created will also be 400 pixels wide,
             * and the "end" label will be separated from the other labels in the
             * hbox.  Otherwise, all the widgets in the hbox would be packed as
             * close together as possible. */
            gtk_widget_set_usize (separator, 400, 5);
            /* pack the separator into the vbox (box1) created near the start 
             * of main() */
            gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
            gtk_widget_show (separator);    
        }
        
        /* Create another new hbox.. remember we can use as many as we need! */
        quitbox = gtk_hbox_new (FALSE, 0);
        
        /* Our quit button. */
        button = gtk_button_new_with_label ("Quit");
        
        /* setup the signal to destroy the window.  Remember that this will send
         * the "destroy" signal to the window which will be caught by our signal
         * handler as defined above. */
        gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                                   GTK_SIGNAL_FUNC (gtk_widget_destroy),
                                   GTK_OBJECT (window));
        /* pack the button into the quitbox.
         * The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
        gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
        /* pack the quitbox into the vbox (box1) */
        gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
        
        /* pack the vbox (box1) which now contains all our widgets, into the
         * main window. */
        gtk_container_add (GTK_CONTAINER (window), box1);
        
        /* and show everything left */
        gtk_widget_show (button);
        gtk_widget_show (quitbox);
        
        gtk_widget_show (box1);
        /* Showing the window last so everything pops up at once. */
        gtk_widget_show (window);
        
        /* And of course, our main function. */
        gtk_main ();

        /* control returns here when gtk_main_quit() is called, but not when 
         * gtk_exit is used. */
        
        return 0;
    }

4.4 使用表格来封装 

我们来看看另一个封装的方法 - 用表格. 在很多状况下, 这是极其有用的. 

使用表格, 我们产生格线来将物件放入. 物件会照我们安排的位置排入. 

我们第一个要看的是gtk_table_new这个函数: 

    GtkWidget* gtk_table_new (gint rows,
                              gint columns,
                              gint homogeneous);

第一个参数是多少列, 第二个是多少栏. 

homogeneous参数用来决定表格如何来定大小. 若homogeneous为TRUE,
table boxes会被重定为在其中最大物件的大小. 若homogeneous为FALSE, 则
其大小为, "高"为列中最高的物件, 及"宽"栏中最宽的物件大小. 

列及栏的编号为从0到n. n是我们在gtk_table_new中所指定的值. 所以, 如果您
指定rows = 2及columns = 2, 整个排列会看起来像这样: 

     0          1          2
    0+----------+----------+
     |          |          |
    1+----------+----------+
     |          |          |
    2+----------+----------+

坐标系统开始于左上角. 要把物件放进box中, 可用以下函数: 

    void gtk_table_attach (GtkTable      *table,
                           GtkWidget     *child,
                           gint           left_attach,
                           gint           right_attach,
                           gint           top_attach,
                           gint           bottom_attach,
                           gint           xoptions,
                           gint           yoptions,
                           gint           xpadding,
                           gint           ypadding);

第一个参数("table")是您才刚产生的表格, 而第二个("child")是您想放进去的
物件. 

而left_attach及right_attach参数指定要把物件放在那里, 及用多少个boxes. 如
果您想要用右下角的表格, 可以这样填表. left_attach = 1, right_attach = 2,
top_attach = 1, bottom_attach = 2. 

现在, 如果您想要物件来使用上面2x2的表格, 您可以使用left_attach = 0,
right_attach =2, top_attach = 0, bottom_attach = 1. 

xoptions及yoptions是用来指定封装选项, 可以同时组合多个选项(用or). 

这些选项是: 

    GTK_FILL - 如果table box大过物件, 且GTK_FILL 被指定了, 该物件
    会扩展成使用所有可用的空间. 
    GTK_SHRINK - 如果table widget小于该物件, (一般是使用者缩放该
    视窗), 那么该物件将会一直被挤压到看不见为止. 如果GTK_SHRINK
    被指定了, 该物件会跟著table一起缩小. 
    GTK_EXPAND - 这会使table本身扩展, 并利用视窗中所有可用空间. 

填空就像boxes, 产生一个在物件周边空白的区域. 

gtk_table_attach()有许多选项. 这里有个捷径: 

    void gtk_table_attach_defaults (GtkTable   *table,
                                    GtkWidget  *widget,
                                    gint        left_attach,
                                    gint        right_attach,
                                    gint        top_attach,
                                    gint        bottom_attach);

X及Y选项内定为GTK_FILL | GTK_EXPAND, X及Y填空则设为0. 其馀的参
数则相同于以上的函数. 

我们另外有gtk_table_set_row_spacing()及gtk_table_set_col_spacing(). 这些
会在指定的栏及列插入空白. 

    void gtk_table_set_row_spacing (GtkTable      *table,
                                    gint           row,
                                    gint           spacing);

及 

    void       gtk_table_set_col_spacing  (GtkTable      *table,
                                           gint           column,
                                           gint           spacing);

对栏来说, 空格是在栏的右边. 而列则是在下面. 

您也可以用以下函数来产生固定的空格. 

    void gtk_table_set_row_spacings (GtkTable *table,
                                     gint      spacing);

及, 

    void gtk_table_set_col_spacings (GtkTable  *table,
                                     gint       spacing);

使用这些函数, 其最后一栏及最后一列并没有空格存在. 

4.5 Table Packing范例 

目前并无说明, 请参照testgtk.c 


--
        6m3m┌───────────────────────┐0m
        6m3m│     4m疾如风,徐如林,侵掠如火,不动如山       3m│4m 0m
        6m3m└───────────────────────┘0m4m 0m
          4m                                                 0m

m;32m※ 来源:.华南网木棉站 bbs.gznet.edu.cn.[FROM: 202.38.212.66]m
--
m;32m※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: mtlab.hit.edu.cn]
--

                              Enjoy Linux!
                          -----It's FREE!-----

※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: mtlab.hit.edu.cn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.896毫秒