Previous Next Contents

8. Container物件

8.1 笔记本物件

笔记本物件好几个"页"的集合, 它们互相交叠在一起, 并可包含不同的讯息. 这个物件在GUI越来越普及, 它是个在显示有类同功能的资讯时很有用的物件.

第一个您会用到的是产生一个新的笔记本物件.

GtkWidget* gtk_notebook_new (void);

一旦物件产生後, 共有12个函数可以操作该笔记本物件. 我们一个一个来看.

第一个是要如何来安排"页标签". 这些"页标签"或"tabs", 可以用四个位置, 上, 下, 左, 右.

void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);

GtkPostionType可以是以下四个, 很好认.

GTK_POS_TOP是内定值.

接下来我们来看如何加"一页"到笔记本上. 共有三种方法来加页到笔记本上.

void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);

void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);

这些函数新增一页到笔记本, append由後新增, prepend由前新增. *child是要插入笔记本的物件, *tab_label是页标签.

void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);

参数与_append_及_prepend_相同, 除了多出一个参数, 位置. 该参数用来指定要插在那里.

现在我们知道要如何新增一页, 再来看看如何移除.

void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);

这个函数移除掉所指定的那一页.

要找出目前正在那一页, 可用以下函数:

gint gtk_notebook_current_page (GtkNotebook *notebook);

以下两个函数是向前或向後移动. 若目前在最後一页, 而您用gtk_notebook_next_page, 那麽笔记本会绕回第一页, 反之亦然.

void gtk_notebook_next_page (GtkNoteBook *notebook);
void gtk_notebook_prev_page (GtkNoteBook *notebook);

以下函数设定"有效页". 如果您希望笔记本开启到例如第五页, 您可以用这个函数. 内定页为第一页.

void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num);

以下两个函数可新增及移除页标签及边框.

void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gint show_tabs);
void gtk_notebook_set_show_border (GtkNotebook *notebook, gint show_border);

show_tabs及show_border可以是TRUE或FALSE(0或1).

现在我们来看个范例, 它是从testgtk.c中展开的, 用了所有13个函数. 该程式产生一个笔记本及六个按钮, 包含11页, 以三种方式加页, appended, inserted,及prepended. 这些按钮允许您旋转页标签位置, 新增/移除页标签及边框, 移除一页, 以前向及後向改变页的位置, 及离开程式.


#include <gtk/gtk.h>

/* This function rotates the position of the tabs */
void rotate_book (GtkButton *button, GtkNotebook *notebook)
{
    gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
}

/* Add/Remove the page tabs and the borders */
void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
{
    gint tval = FALSE;
    gint bval = FALSE;
    if (notebook->show_tabs == 0)
            tval = TRUE; 
    if (notebook->show_border == 0)
            bval = TRUE;
    
    gtk_notebook_set_show_tabs (notebook, tval);
    gtk_notebook_set_show_border (notebook, bval);
}

/* Remove a page from the notebook */
void remove_book (GtkButton *button, GtkNotebook *notebook)
{
    gint page;
    
    page = gtk_notebook_current_page(notebook);
    gtk_notebook_remove_page (notebook, page);
    /* Need to refresh the widget -- 
     This forces the widget to redraw itself. */
    gtk_widget_draw(GTK_WIDGET(notebook), NULL);
}

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

int main (int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *table;
    GtkWidget *notebook;
    GtkWidget *frame;
    GtkWidget *label;
    GtkWidget *checkbutton;
    int i;
    char bufferf[32];
    char bufferl[32];
    
    gtk_init (&argc, &argv);
    
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
                        GTK_SIGNAL_FUNC (destroy), NULL);
    
    gtk_container_border_width (GTK_CONTAINER (window), 10);
    
    table = gtk_table_new(2,6,TRUE);
    gtk_container_add (GTK_CONTAINER (window), table);
    
    /* Create a new notebook, place the position of the tabs */
    notebook = gtk_notebook_new ();
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
    gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
    gtk_widget_show(notebook);
    
    /* lets append a bunch of pages to the notebook */
    for (i=0; i < 5; i++) {
        sprintf(bufferf, "Append Frame %d", i+1);
        sprintf(bufferl, "Page %d", i+1);
        
        frame = gtk_frame_new (bufferf);
        gtk_container_border_width (GTK_CONTAINER (frame), 10);
        gtk_widget_set_usize (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (bufferf);
        gtk_container_add (GTK_CONTAINER (frame), label);
        gtk_widget_show (label);
        
        label = gtk_label_new (bufferl);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
    }
    
    
    /* now lets add a page to a specific spot */
    checkbutton = gtk_check_button_new_with_label ("Check me please!");
    gtk_widget_set_usize(checkbutton, 100, 75);
    gtk_widget_show (checkbutton);
    
    label = gtk_label_new ("Add spot");
    gtk_container_add (GTK_CONTAINER (checkbutton), label);
    gtk_widget_show (label);
    label = gtk_label_new ("Add page");
    gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
    
    /* Now finally lets prepend pages to the notebook */
    for (i=0; i < 5; i++) {
        sprintf(bufferf, "Prepend Frame %d", i+1);
        sprintf(bufferl, "PPage %d", i+1);
        
        frame = gtk_frame_new (bufferf);
        gtk_container_border_width (GTK_CONTAINER (frame), 10);
        gtk_widget_set_usize (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (bufferf);
        gtk_container_add (GTK_CONTAINER (frame), label);
        gtk_widget_show (label);
        
        label = gtk_label_new (bufferl);
        gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
    }
    
    /* Set what page to start at (page 4) */
    gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
    
    
    /* create a bunch of buttons */
    button = gtk_button_new_with_label ("close");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               GTK_SIGNAL_FUNC (destroy), NULL);
    gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
    gtk_widget_show(button);
    
    button = gtk_button_new_with_label ("next page");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               (GtkSignalFunc) gtk_notebook_next_page,
                               GTK_OBJECT (notebook));
    gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
    gtk_widget_show(button);
    
    button = gtk_button_new_with_label ("prev page");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               (GtkSignalFunc) gtk_notebook_prev_page,
                               GTK_OBJECT (notebook));
    gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
    gtk_widget_show(button);
    
    button = gtk_button_new_with_label ("tab position");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
    gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
    gtk_widget_show(button);
    
    button = gtk_button_new_with_label ("tabs/border on/off");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               (GtkSignalFunc) tabsborder_book,
                               GTK_OBJECT (notebook));
    gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
    gtk_widget_show(button);
    
    button = gtk_button_new_with_label ("remove page");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               (GtkSignalFunc) remove_book,
                               GTK_OBJECT(notebook));
    gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
    gtk_widget_show(button);
    
    gtk_widget_show(table);
    gtk_widget_show(window);
    
    gtk_main ();
    
    return 0;
}

8.2 卷动视窗

卷动视窗是用来产生在视窗内可卷动的区域. 您可以在卷动视窗中插入任意种物件, 而不管视窗大小如何, 这些物件因为在卷动区域内, 因此都可以被用到.

您可以用以下函数来产生卷动视窗:

GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment,
                                    GtkAdjustment *vadjustment);

第一个参数是水平调整方向, 第二个是垂直调整方向. 它们一般被设为NULL.

void gtk_scrolled_window_set_policy      (GtkScrolledWindow *scrolled_window,
                                          GtkPolicyType      hscrollbar_policy,
                                                                                  GtkPolicyType      vscrollbar_policy);

第一个参数是想要改变的视窗. 第二个是设定水平卷动的方式, 第三个是垂直卷动的方式.

policy可以是GTK_POLICY_AUTOMATIC, 或GTK_POLICY_ALWAYS. GTK_POLICY_AUTOMATIC会自动决定是否使用scrollbars. GTK_POLICY_ALWAYS则scrollbars始终在那里.

这里是个将100个双态按钮包进一个卷动视窗的范例.

#include <gtk/gtk.h>

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

int main (int argc, char *argv[])
{
    static GtkWidget *window;
    GtkWidget *scrolled_window;
    GtkWidget *table;
    GtkWidget *button;
    char buffer[32];
    int i, j;
    
    gtk_init (&argc, &argv);
    
    /* Create a new dialog window for the scrolled window to be
     * packed into.  A dialog is just like a normal window except it has a 
     * vbox and a horizontal seperator packed into it.  It's just a shortcut
     * for creating dialogs */
    window = gtk_dialog_new ();
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
                        (GtkSignalFunc) destroy, NULL);
    gtk_window_set_title (GTK_WINDOW (window), "dialog");
    gtk_container_border_width (GTK_CONTAINER (window), 0);
    
    /* create a new scrolled window. */
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
    
    gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
    
    /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
     * GTK_POLICY_AUTOMATIC will automatically decide whether you need
     * scrollbars, wheras GTK_POLICY_ALWAYS will always leave the scrollbars
     * there.  The first one is the horizontal scrollbar, the second, 
     * the vertical. */
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
    /* The dialog window is created with a vbox packed into it. */                                                              
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window, 
                        TRUE, TRUE, 0);
    gtk_widget_show (scrolled_window);
    
    /* create a table of 10 by 10 squares. */
    table = gtk_table_new (10, 10, FALSE);
    
    /* set the spacing to 10 on x and 10 on y */
    gtk_table_set_row_spacings (GTK_TABLE (table), 10);
    gtk_table_set_col_spacings (GTK_TABLE (table), 10);
    
    /* pack the table into the scrolled window */
    gtk_container_add (GTK_CONTAINER (scrolled_window), table);
    gtk_widget_show (table);
    
    /* this simply creates a grid of toggle buttons on the table
     * to demonstrate the scrolled window. */
    for (i = 0; i < 10; i++)
            for (j = 0; j < 10; j++) {
                sprintf (buffer, "button (%d,%d)\n", i, j);
                button = gtk_toggle_button_new_with_label (buffer);
                gtk_table_attach_defaults (GTK_TABLE (table), button,
                                           i, i+1, j, j+1);
                gtk_widget_show (button);
            }
    
    /* Add a "close" button to the bottom of the dialog */
    button = gtk_button_new_with_label ("close");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                               (GtkSignalFunc) gtk_widget_destroy,
                               GTK_OBJECT (window));
    
    /* this makes it so the button is the default. */
    
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
    
    /* This grabs this button to be the default button. Simply hitting
     * the "Enter" key will cause this button to activate. */
    gtk_widget_grab_default (button);
    gtk_widget_show (button);
    
    gtk_widget_show (window);
    
    gtk_main();
    
    return(0);
}

玩弄一下这个视窗. 您会看到scrollbars如何反应. 您也会想用用gtk_widget_set_usize()来设定视窗内定的大小.


Previous Next Contents