当前位置:Linux教程 - Linux - GTK入门导读(Menu物件)

GTK入门导读(Menu物件)



         14. Menu物件
    有两种方式来产生选单物件, 一种简单的, 一种难的. 两种各有其用途, 但您可以用menu_factory(简单的). 难的方法是一个一个产生. 简单的是用gtk_menu_factory 这个简单多了, 但各有其优劣之处.

    menufactory很好用, 虽然另外写一些函数, 以手动函数来产生这些选单会比较有用. 不过, 以menufactory, 也是可以加影像到选单中.


    14.1 Manual Menu Creation
    在教学的目的上, 我们先来看看难的方法.:)

    先看看产生选单的函数. 第一个当然是产生一个新的选单.


    GtkWidget *gtk_menu_bar_new()

    GtkWidget *gtk_menu_new();

    这个函数返回一个新的选单, 它还不会显示.

    以下两个函数是用来产生选单项目.


    GtkWidget *gtk_menu_item_new()

    and


    GtkWidget *gtk_menu_item_new_with_label(const char *label)

    动态新增


    gtk_menu_item_append()

    gtk_menu_item_set_submenu()

    gtk_menu_new_with_label及gtk_menu_new函数一个产生一个新的选单项目并带标签, 另一个则是个空的选单项目.

    产生选单的步骤大致如下:

    使用gtk_menu_new()来产生一个新的选单
    使用gtk_menu_item_new()来产生一个新的选单项目. 这会是主选单, 文字将会是menu bar本身.
    使用gtk_menu_item_new来将每一个项目产生出来用gtk_menu_item_append()来将每个新项目放在一起. 这会产生一列选单项目.
    使用gtk_menu_item_set_submenu()来接到心产生的menu_items到主选单项目. (在第二步中所产生出来的).
    使用gtk_menu_bar_new来产生一个menu bar. 这一步仅需做一次, 当我们产生一系列选单在menu bar上.
    使用gtk_menu_bar_append来将主选单放到menubar.

    14.2 Manual Menu范例
    我们来做做看, 看看一个范例会比较有帮助.



    #include

    int main (int argc, char *argv[])
    {

    GtkWidget *window;
    GtkWidget *menu;
    GtkWidget *menu_bar;
    GtkWidget *root_menu;
    GtkWidget *menu_items;
    char buf[128];
    int i;

    gtk_init (&argc, &argv);

    /* create a new window */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW (window), \"GTK Menu Test\");
    gtk_signal_connect(GTK_OBJECT (window), \"destroy\",
    (GtkSignalFunc) gtk_exit, NULL);

    /* Init the menu-widget, and remember -- never
    * gtk_show_widget() the menu widget!! */
    menu = gtk_menu_new();

    /* This is the root menu, and will be the label will be the menu name displayed on
    * the menu bar. There won\"t be
    * a signal handler attached, as it only pops up the rest of the menu when pressed. */
    root_menu = gtk_menu_item_new_with_label(\"Root Menu\");

    gtk_widget_show(root_menu);

    /* Next we make a little loop that makes three menu-entries for \"test-menu\".
    * Notice the call to gtk_menu_append. Here we are adding a list of menu items
    * to our menu. Normally, we\"d also catch the \"clicked\" signal on each of the
    * menu items and setup a callback for it, but it\"s omitted here to save space. */

    for(i = 0; i < 3; i++)
    {
    /* Copy the names to the buf. */
    sprintf(buf, \"Test-undermenu - %d\", i);

    /* Create a new menu-item with a name... */
    menu_items = gtk_menu_item_new_with_label(buf);

    /* ...and add it to the menu. */
    gtk_menu_append(GTK_MENU (menu), menu_items);

    /* Show the widget */
    gtk_widget_show(menu_items);
    }

    /* Now we specify that we want our newly created \"menu\" to be the menu for the \"root menu\" */
    gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);

    /* Create a menu-bar to hold the menus and add it to our main window*/
    menu_bar = gtk_menu_bar_new();
    gtk_container_add(GTK_CONTAINER(window), menu_bar);
    gtk_widget_show(menu_bar);

    /* And finally we append the menu-item to the menu-bar -- this is the \"root\"
    * menu-item I have been raving about =) */
    gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);

    /* always display the window as the last step so it all splashes on the screen at once. */
    gtk_widget_show(window);

    gtk_main ();

    return 0;
    }

    您也可以设定一个选单项目无效, 并使用accelerator table结合按键到选单功能.


    14.3 使用GtkMenuFactory
    我们已经示范了难的方法, 这里是用gtk_menu_factory的方法.


    14.4 Menu Factory范例
    这里是menu factory的范例. 这是第一个档案, menus.h. 另有menus.c及main.c


    #ifndef __MENUS_H__
    #define __MENUS_H__

    #ifdef __cplusplus
    extern \"C\" {
    #endif /* __cplusplus */

    void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
    void menus_create(GtkMenuEntry *entries, int nmenu_entries);

    #ifdef __cplusplus
    }
    #endif /* __cplusplus */

    #endif /* __MENUS_H__ */

    And here is the menus.c file.



    #include
    #include

    #include \"main.h\"


    static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
    static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
    void menus_init(void);
    void menus_create(GtkMenuEntry * entries, int nmenu_entries);


    /* this is the GtkMenuEntry structure used to create new menus. The
    * first member is the menu definition string. The second, the
    * default accelerator key used to access this menu function with
    * the keyboard. The third is the callback function to call when
    * this menu item is selected (by the accelerator key, or with the
    * mouse.) The last member is the data to pass to your callback function.
    */

    static GtkMenuEntry menu_items[] =
    {
    {\"
    /File/New\", \"N\", NULL, NULL},
    {\"
    /File/Open\", \"O\", NULL, NULL},
    {\"
    /File/Save\", \"S\", NULL, NULL},
    {\"
    /File/Save as\", NULL, NULL, NULL},
    {\"
    /File/\", NULL, NULL, NULL},
    {\"
    /File/Quit\", \"Q\", file_quit_cmd_callback, \"OK, I\"ll quit\"},
    {\"
    /Options/Test\", NULL, NULL, NULL}
    };

    /* calculate the number of menu_item\"s */
    static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);

    static int initialize = TRUE;
    static GtkMenuFactory *factory = NULL;
    static GtkMenuFactory *subfactory[1];
    static GHashTable *entry_ht = NULL;

    void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
    {
    if (initialize)
    menus_init();

    if (menubar)
    *menubar = subfactory[0]->widget;
    if (table)
    *table = subfactory[0]->table;
    }

    void menus_init(void)
    {
    if (initialize) {
    initialize = FALSE;

    factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
    subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);

    gtk_menu_factory_add_subfactory(factory, subfactory[0], \"
    \");
    menus_create(menu_items, nmenu_items);
    }
    }

    void menus_create(GtkMenuEntry * entries, int nmenu_entries)
    {
    char *accelerator;
    int i;

    if (initialize)
    menus_init();

    if (entry_ht)
    for (i = 0; i < nmenu_entries; i++) {
    accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
    if (accelerator) {
    if (accelerator[0] == \"\\0\")
    entries[i].accelerator = NULL;
    else
    entries[i].accelerator = accelerator;
    }
    }
    gtk_menu_factory_add_entries(factory, entries, nmenu_entries);

    for (i = 0; i < nmenu_entries; i++)
    if (entries[i].widget) {
    gtk_signal_connect(GTK_OBJECT(entries[i].widget), \"install_accelerator\",
    (GtkSignalFunc) menus_install_accel,
    entries[i].path);
    gtk_signal_connect(GTK_OBJECT(entries[i].widget), \"remove_accelerator\",
    (GtkSignalFunc) menus_remove_accel,
    entries[i].path);
    }
    }

    static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
    {
    char accel[64];
    char *t1, t2[2];

    accel[0] = \"\\0\";
    if (modifiers & GDK_CONTROL_MASK)
    strcat(accel, \"\");
    if (modifiers & GDK_SHIFT_MASK)
    strcat(accel, \"\");
    if (modifiers & GDK_MOD1_MASK)
    strcat(accel, \"\");

    t2[0] = key;
    t2[1] = \"\\0\";
    strcat(accel, t2);

    if (entry_ht) {
    t1 = g_hash_table_lookup(entry_ht, path);
    g_free(t1);
    } else
    entry_ht = g_hash_table_new(g_string_hash, g_string_equal);

    g_hash_table_insert(entry_ht, path, g_strdup(accel));

    return TRUE;
    }

    static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
    {
    char *t;

    if (entry_ht) {
    t = g_hash_table_lookup(entry_ht, path);
    g_free(t);

    g_hash_table_insert(entry_ht, path, g_strdup(\"\"));
    }
    }

    void menus_set_sensitive(char *path, int sensitive)
    {
    GtkMenuPath *menu_path;

    if (initialize)
    menus_init();

    menu_path = gtk_menu_factory_find(factory, path);
    if (menu_path)
    gtk_widget_set_sensitive(menu_path->widget, sensitive);
    else
    g_warning(\"Unable to set sensitivity for menu which doesn\"t exist: %s\", path);
    }

    And here\"s the main.h


    #ifndef __MAIN_H__
    #define __MAIN_H__


    #ifdef __cplusplus
    extern \"C\" {
    #endif /* __cplusplus */

    void file_quit_cmd_callback(GtkWidget *widget, gpointer data);

    #ifdef __cplusplus
    }
    #endif /* __cplusplus */

    #endif /* __MAIN_H__ */

    And main.c


    #include

    #include \"main.h\"
    #include \"menus.h\"


    int main(int argc, char *argv[])
    {
    GtkWidget *window;
    GtkWidget *main_vbox;
    GtkWidget *menubar;

    GtkAcceleratorTable *accel;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_signal_connect(GTK_OBJECT(window), \"destroy\",
    GTK_SIGNAL_FUNC(file_quit_cmd_callback),
    \"WM destroy\");
    gtk_window_set_title(GTK_WINDOW(window), \"Menu Factory\");
    gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);

    main_vbox = gtk_vbox_new(FALSE, 1);
    gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
    gtk_container_add(GTK_CONTAINER(window), main_vbox);
    gtk_widget_show(main_vbox);

    get_main_menu(&menubar, &accel);
    gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
    gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
    gtk_widget_show(menubar);

    gtk_widget_show(window);
    gtk_main();

    return(0);
    }

    /* This is just to demonstrate how callbacks work when using the
    * menufactory. Often, people put all the callbacks from the menus
    * in a separate file, and then have them call the appropriate functions
    * from there. Keeps it more organized. */
    void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
    {
    g_print (\"%s\\n\", (char *) data);
    gtk_exit(0);
    }

    这里是makefile.


    CC = gcc
    PROF = -g
    C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
    L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
    L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
    PROGNAME = at

    O_FILES = menus.o main.o

    $(PROGNAME): $(O_FILES)
    rm -f $(PROGNAME)
    $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)

    .c.o:
    $(CC) -c $(C_FLAGS) $<

    clean:
    rm -f core *.o $(PROGNAME) nohup.out
    distclean: clean
    rm -f *~

    发布人:netbull 来自:Linux开发指南