• “菜单”(menubar)和“工具栏”(toolbars)


    “菜单”(menubar)和“工具栏”(toolbars)

    “菜单” (menubar)和“工具栏”(toolbars)

    在这个部分的GTK+程序设计教程中,我们使用“菜单”和“工具栏”。

    “菜单”( menubar) 是GUI程序中最为常见的部分之一。各种各样的命令和功能都可以借以“菜单”来实现。 当我们习惯在终端(console)中启动应用程序的时候,必须要记得很多复杂的命令和参数 ,在本章节中我们将 这一切都转化为可见的操作。菜单和工具栏中标准化的操作,将让你摆脱学习新软件所耗费的大量时间和精力。

    简单的菜单示列

    在我们的第一个例子中,我们将生成一个含有文件菜单的菜单栏。文件菜单将只有一个菜单条(menu item)。如果点击这个菜单条程序将退出。

    #include <gtk/gtk.h>
    
    
    int main( int argc, char *argv[])
    {
    
      GtkWidget *window;
      GtkWidget *vbox;
    
      GtkWidget *menubar;
      GtkWidget *filemenu;
      GtkWidget *file;
      GtkWidget *quit;
    
      gtk_init(&argc, &argv);
    
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
      gtk_window_set_title(GTK_WINDOW(window), "menu");
    
      vbox = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(window), vbox);
    
      menubar = gtk_menu_bar_new();
      filemenu = gtk_menu_new();
    
      file = gtk_menu_item_new_with_label("File");
      quit = gtk_menu_item_new_with_label("Quit");
    
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
      gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
      gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
      gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
    
      g_signal_connect_swapped(G_OBJECT(window), "destroy",
            G_CALLBACK(gtk_main_quit), NULL);
    
      g_signal_connect(G_OBJECT(quit), "activate",
            G_CALLBACK(gtk_main_quit), NULL);
    
      gtk_widget_show_all(window);
    
      gtk_main();
    
      return 0;
    }
    

    生成一个菜单栏的确会让人有点疑惑。我们要牢记的是一个菜单栏和一个菜单都是源属于同一个构件的,也就是菜单外壳(menu shell)。菜单选项(menu items )是一个只对菜单有效的子构件。他们通常用来实现子菜单。

    menubar = gtk_menu_bar_new();
    filemenu = gtk_menu_new();
    

    在上面的代码中我们生成了一个菜单栏构件(menubar)和一个菜单构件(menu)。

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
    

    上面的代码就会生成一个名为“文件”的菜单。这也就是说其实菜单栏就是一个菜单外壳。很显然这里的文件菜单也是一个菜单外壳。这就是为什么我们把文件菜单称为子菜单或者说是一个子外壳。

    gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
    

    菜单选项由函数 gtk_menu_shell_append() f来实现。然后一般情况下菜单选项被填加进菜单外壳里。 在我们的这个例子中,“quit”菜单选项是被填加进“file”菜单栏里,然后类似的是“file”菜单选项被填加进菜单中(menubar)。

    g_signal_connect(G_OBJECT(quit), "activate",
          G_CALLBACK(gtk_main_quit), NULL);
    

    当你单击“quit”菜单按钮,程序就会退出。


    Simple menu
    Figure: Simple menu

    图象菜单, mnemonics &accelerators

    在接下来的这个例子中,我们将更进一步的去探索,在GTK+系统中我们可以应用的功能。Accelerators 是快捷键的意思,用来方便的用键盘上的组合键激活一个菜单选项。 Mnemonics也是是快捷键用于用于GUI的基础。他们的具体表现都为带有下画线的字符。(译者:似乎说的不清楚啊,呵呵。具体的区别还是请参见下面的具体代码实现以及对应的程序效果图)

    #include <gtk/gtk.h>
    #include <gdk/gdkkeysyms.h>
    
    
    int main( int argc, char *argv[])
    {
    
      GtkWidget *window;
      GtkWidget *vbox;
    
      GtkWidget *menubar;
      GtkWidget *filemenu;
      GtkWidget *file;
      GtkWidget *new;
      GtkWidget *open;
      GtkWidget *quit;
    
      GtkWidget *sep;
    
      GtkAccelGroup *accel_group = NULL;
    
      gtk_init(&argc, &argv);
    
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
      gtk_window_set_title(GTK_WINDOW(window), "menu");
    
      vbox = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(window), vbox);
    
      menubar = gtk_menu_bar_new();
      filemenu = gtk_menu_new();
    
      accel_group = gtk_accel_group_new();
      gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
    
      file = gtk_menu_item_new_with_mnemonic("_File");
      new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
      open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
      sep = gtk_separator_menu_item_new();
      quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group);
    
      gtk_widget_add_accelerator(quit, "activate", accel_group, 
          GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
    
    
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
      gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), new);
      gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open);
      gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep);
      gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
      gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
      gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
    
      g_signal_connect_swapped(G_OBJECT(window), "destroy",
          G_CALLBACK(gtk_main_quit), NULL);
    
      g_signal_connect(G_OBJECT(quit), "activate",
          G_CALLBACK(gtk_main_quit), NULL);
    
      gtk_widget_show_all(window);
    
      gtk_main();
    
      return 0;
    }
    

    在上面的整个代码程序中,向大家展示了是如何向一个菜单选项中去填加一个图象的。当然也包括了如何使用accelerator 以及 mnemonics 。

    accel_group = gtk_accel_group_new();
    gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
    ...
    quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group);
    gtk_widget_add_accelerator(quit, "activate", accel_group, 
        GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
    

    一个 accelerator 组有好多个accelerators快捷键。这里我们生成了一个“Ctrl + q” accelerators快捷键。

    file = gtk_menu_item_new_with_mnemonic("_File");
    

    我们需要调用函数 gtk_menu_item_new_with_mnemonic() 来生成一个mnemonic快捷键。你可以按下键盘上的“ Alt + F”就可以看到. mnemonic快捷键的效果。

    new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
    open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
    

    在上面的代码中我们生成了两个带有图象的菜单选项。在所调用的函数的第二个参数中,我们设置为NULL,这样达到的效果是我们自动生成了accelerators快捷键。我们也为菜单选项分别提供了图象与文字。

    sep = gtk_separator_menu_item_new();
    

    菜单选项能够被一个水平的分割线隔开。这样的话我们就可以从逻辑上把一些菜单选项给区分开来。


    Menu example
    Figure: Menu example

    选择(Check)菜单选项 (menu item)

    GtkCheckMenuItem 便是一个可以生成带有选择的菜单选项。

    #include <gtk/gtk.h>
    
    
    void toggle_statusbar(GtkWidget *widget, gpointer statusbar) 
    {
      if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
        gtk_widget_show(statusbar);
      } else {
        gtk_widget_hide(statusbar);
      }
    }
    
    
    int main( int argc, char *argv[])
    {
    
      GtkWidget *window;
      GtkWidget *vbox;
    
      GtkWidget *menubar;
      GtkWidget *viewmenu;
      GtkWidget *view;
      GtkWidget *tog_stat;
      GtkWidget *statusbar;
      
    
      gtk_init(&argc, &argv);
    
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
      gtk_window_set_title(GTK_WINDOW(window), "view statusbar");
    
      vbox = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(window), vbox);
    
      menubar = gtk_menu_bar_new();
      viewmenu = gtk_menu_new();
    
      view = gtk_menu_item_new_with_label("View");
      tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");
      gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tog_stat), TRUE);
    
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), viewmenu);
      gtk_menu_shell_append(GTK_MENU_SHELL(viewmenu), tog_stat);
      gtk_menu_shell_append(GTK_MENU_SHELL(menubar), view);
      gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
    
      statusbar = gtk_statusbar_new();
      gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);
    
      g_signal_connect_swapped(G_OBJECT(window), "destroy",
            G_CALLBACK(gtk_main_quit), NULL);
    
      g_signal_connect(G_OBJECT(tog_stat), "activate", 
            G_CALLBACK(toggle_statusbar), statusbar);
    
      gtk_widget_show_all(window);
    
      gtk_main();
    
      return 0;
    }
    

    在我们的代码示例中,我们展示了如何去制造一个带有选择框的菜单选项。具体的功能是:如果选择框被选中则“状态栏”就会显示出来,反之则不会显示。

    tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");
    

    函数gtk_check_menu_item_new_with_label() 可以生成一个新的带有选择框的菜单选项。

    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
      gtk_widget_show(statusbar);
    } else {
      gtk_widget_hide(statusbar);
    }
    

    如果选择框被选中则“状态栏”就会显示出来,反之则不会显示。


    Check menu item
    Figure: Check menu item

    工具栏(A toolbar)

    菜单栏为我们编程时实现某种功能提供了方便与快捷。在接下来的章节中,我们将为你展示一种在特定情况下可以更加便捷的的方法——制造一个“工具栏。”

    #include <gtk/gtk.h>
    
    
    int main( int argc, char *argv[])
    {
      GtkWidget *window;
      GtkWidget *vbox;
      
      GtkWidget *toolbar;
      GtkToolItem *new;
      GtkToolItem *open;
      GtkToolItem *save;
      GtkToolItem *sep;
      GtkToolItem *exit;
    
    
      gtk_init(&argc, &argv);
    
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
      gtk_window_set_title(GTK_WINDOW(window), "toolbar");
    
      vbox = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(window), vbox);
    
    
      toolbar = gtk_toolbar_new();
      gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
    
      gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);
    
      new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);
    
      open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), open, -1);
    
      save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), save, -1);
    
      sep = gtk_separator_tool_item_new();
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); 
    
      exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);
    
      gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);
    
      g_signal_connect(G_OBJECT(exit), "clicked", 
            G_CALLBACK(gtk_main_quit), NULL);
    
      g_signal_connect_swapped(G_OBJECT(window), "destroy",
            G_CALLBACK(gtk_main_quit), NULL);
    
      gtk_widget_show_all(window);
    
      gtk_main();
    
      return 0;
    }
    

    以上的代码中,我们制作了一个简单的工具栏实现。

    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS)
    

    从上面的两行代码中你应该可以看出来,我们生成了一个“崭新”的工具栏:)。我们还特地使他们都用图片来显示,没有包含文字。

    new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);
    

    从 stock中我们生成了一个新的工具栏按钮。要想把工具栏按钮插入到工具栏中,很简单!只需要调用函数 gtk_toolbar_insert() 就可以搞定。

    sep = gtk_separator_tool_item_new();
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); 
    

    上面的代码,我们生成了一个分割线把工具栏按钮们分开(只是逻辑上的分组需要)。


    Toolbar
    Figure: Toolbar

    功能失效(Undo redo)

    在接下来的例子中,我们将展示一个神奇的功能:使工具栏中的一个按钮功能失效(让他变成阴影)。这在GUI设计中是一个常见的技巧。 举个例子:当我们把一片文章单击保存后,那个保存按钮就会变成阴影状,也就是功能失效了。就是来提示你:保存功能已经执行过了,不需要再执行保存功能了。

    #include <gtk/gtk.h>
    #include <string.h>
    
    
    void undo_redo(GtkWidget *widget,  gpointer item) 
    {
      static int count = 2;
      const char *name = gtk_widget_get_name(widget);
    
      if ( strcmp(name, "undo") ) {
        count++;
      } else {
        count--;
      }
     
      if (count < 0) {
         gtk_widget_set_sensitive(widget, FALSE);
         gtk_widget_set_sensitive(item, TRUE);
      } 
    
      if (count > 5) {
         gtk_widget_set_sensitive(widget, FALSE);
         gtk_widget_set_sensitive(item, TRUE);
      }
    }
    
    
    int main( int argc, char *argv[])
    {
      GtkWidget *window;
      GtkWidget *vbox;
    
      GtkWidget *toolbar;
      GtkToolItem *undo;
      GtkToolItem *redo;
      GtkToolItem *sep;
      GtkToolItem *exit;
    
    
      gtk_init(&argc, &argv);
    
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
      gtk_window_set_title(GTK_WINDOW(window), "undoredo");
    
      vbox = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(window), vbox);
    
      toolbar = gtk_toolbar_new();
      gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
    
      gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);
    
      undo = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO);
      gtk_widget_set_name(GTK_WIDGET(undo), "undo");
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), undo, -1);
    
      redo = gtk_tool_button_new_from_stock(GTK_STOCK_REDO);
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), redo, -1);
    
      sep = gtk_separator_tool_item_new();
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); 
    
      exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
      gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);
    
      gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);
    
      g_signal_connect(G_OBJECT(undo), "clicked", 
            G_CALLBACK(undo_redo), redo);
    
      g_signal_connect(G_OBJECT(redo), "clicked", 
            G_CALLBACK(undo_redo), undo);
    
      g_signal_connect(G_OBJECT(exit), "clicked", 
            G_CALLBACK(gtk_main_quit), NULL);
    
      g_signal_connect_swapped(G_OBJECT(window), "destroy",
            G_CALLBACK(gtk_main_quit), NULL);
    
      gtk_widget_show_all(window);
    
      gtk_main();
    
      return 0;
    }
    

    我们的例子中用到了 GTK+ stock 来实现是 “功能有效”还是“功能失效”。当你单击几下 按钮后,那个按钮就会变成阴影状,也就是说他从“功能有效”变成了“功能失效”。

    if (count < 0) {
       gtk_widget_set_sensitive(widget, FALSE);
       gtk_widget_set_sensitive(item, TRUE);
    } 
    
    if (count > 5) {
       gtk_widget_set_sensitive(widget, FALSE);
       gtk_widget_set_sensitive(item, TRUE);
    }
    

    gtk_widget_set_sensitive() 是被用来告诉计算机是否要击活一个工具栏按钮。


    Undo redo
    Figure: Undo redo
  • 相关阅读:
    ReentrantLock的实现原理
    Dubbo服务治理
    AQS原理
    flink写es性能优化
    spring的事务机制
    星形模型和雪花模型的区别
    关于使用云服务器做广域网通讯测试的资料整理
    pycharm 远程连接
    日记 2022.04.20
    《时间简史》 初读后感
  • 原文地址:https://www.cnblogs.com/xchsp/p/4322032.html
Copyright © 2020-2023  润新知