Linux 版 (精华区)

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


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

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 <gtk/gtk.h>

    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 <gtk/gtk.h>
    #include <strings.h>

    #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[] =
    {
            {"<Main>/File/New", "<control>N", NULL, NULL},
            {"<Main>/File/Open", "<control>O", NULL, NULL},
            {"<Main>/File/Save", "<control>S", NULL, NULL},
            {"<Main>/File/Save as", NULL, NULL, NULL},
            {"<Main>/File/<separator>", NULL, NULL, NULL},
            {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
            {"<Main>/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], "<Main>");
            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, "<control>");
        if (modifiers & GDK_SHIFT_MASK)
                strcat(accel, "<shift>");
        if (modifiers & GDK_MOD1_MASK)
                strcat(accel, "<alt>");
        
        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 <gtk/gtk.h>

    #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 *~

--
        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)
页面执行时间:211.158毫秒