跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

利用 GNOME 库来简化应用编程

开始所需的一切

George Lebl (jirka@5z.com), 开发者和 GNOME 项目成员
George (在捷克是 Jiri 或 Jirka)Lebl 出生在捷克斯洛伐克布拉格,现在居住在美国加利福尼亚的圣迭哥,他将在那里获得学位。在使用了几年非 UNIX 操作系统后,他开始使用 Unix,在四年前成为 Unix 的追随者,两年前成为“自由软件”追随者。他在 1997 年秋天参加了 GNOME 项目,最后又成了 C 的追随者。最重要的是,他是一个 VI 使用者。可通过 jirka@5z.com 与他联系。

简介: 开发者和 GNOME 项目成员 George Lebl 提供了 GNOME 库能力的概述和应用程序构建技术的介绍。这些库不仅用来构建 GUI,它们还是许多其它项目的实用部件。George 利用一个简单的 Hello World 应用程序说明了 GNOME 开发技术,将为您作逐一介绍。

发布日期: 1999 年 9 月 01 日
级别: 初级
访问情况 : 2892 次浏览
评论: 


让我们从回答几个可能有的问题开始:

什么是 GNOME?
GNOME 是好几样东西:它是 Unix 的图形环境;一个有用的小应用程序和实用程序的集合;以及一组应用编程库。现在,我们集中在 GNOME 库上,它可以帮助开发者快速又省力地构建与 GNOME 兼容、一致和功能强大的 GUI 应用程序。
为什么使用 GNOME 库?
为什么不直接利用 GUI 工具箱(例如 GTK+、Motif 或 Qt)编程,不带任何其它库?这些工具各自有其优点,但我相信使用 GNOME 库的优势要远远超过它们。通过使用 GNOME 库,您可以节省大量时间,因为已编写了大量代码,而且已经创建了许多窗口小部件。这些窗口小部件在所有使用 GNOME 库的应用程序中还能保持一致的外观和感觉。应用程序之间的代码共享减少了内存需求,因为代码将是共享库的一部分,而不必为每个应用程序装入内存中。但 GNOME 最大的好处是,库可以让您集中在应用程序的真正功能;而不必将时间花费在编写和调试用户界面上。

编写 GNOME 应用程序

那您确定要使用 GNOME 吗?好,让我们从基本开始:GNOME 应用程序使用几种库的 层次结构,而 GNOME 库 构成最高层次。 GNOME 库包含了帮助程序例程、类和专门化的窗口小部件(例如 GnomeCanvas,一种快速、无闪烁的高级绘制窗口小部件),并为应用程序提供了框架。

层次结构中第二高层次是 GTK ,它是 GTK+ 库的一部分。该库提供了基本工具箱和窗口小部件(例如按钮、标签和输入框),用于构建 GUI 应用程序。大多数 GUI 都是直接用 GTK 编写的,GTK 也为在 GNOME 库中使用提供了一个复杂的对象系统。


GNOME 应用程序的基本结构
GNOME 应用程序的基本结构

库层次结构中的下一层是 GDK,它是 X 库周围的一个简单封装器,只在您有特殊绘制需要或需要在窗口上设置特殊特性时使用。

最底层是 GLib ,它是 C 的实用程序库,包含了可移植性和实用程序函数,以及一些容器类 -- 链表、大小可调的数组、变长字符串、散列、高速缓存和事件循环,以及其它一些有用的东西。

不要从所有有关 C 的交谈中得出这样一个印象,就是 C 是仅可用于 GNOME 应用程序开发的语言。实际上,因为 GTK+ 和 GNOME 都是用 C 写的,所以编写与其它语言(例如 Objective C、C、C++、Perl、Guile、Python 和 Eiffel)的绑定是非常简便的。


GNOME 和 GTK+ 层

GNOME 库分成以下三个基本部分:libgnome、libgnomeui 和 libgnorba。 libgnome 是实用程序库,在思想上与 GLib 类似,后者提供了一些服务,例如配置装入和保存、应用程序启动、mime 类型标识,以及元数据存储器。 libgnomeui 部分是用户界面部分,包含了应用程序框架 (GnomeApp)、布景 (GnomeCanvas) 和许多其它有用的专门窗口小部件。最后一个部分是 libgnorba ,它用于将 GTK+/GNOME 应用程序与 CORBA 技术进行集成。

在编写 GNOME 应用程序时,知道如何使用 GTK+ 是很重要的。所有 libgnomeui 类都基于 GTK+,因此使用它们的方法与使用标准 GTK+ 窗口小部件的方法是差不多的。

GTK+ 是一个基于容器的工具箱,这意味着大多数窗口小部件都作为保存其它窗口小部件的“容器”使用。例如,按钮就是一个很可能包含标签窗口小部件的容器。但其它容器提供的只不过是一种将更多窗口小部件放在一起的方法(它们当中最有用的是水平框和垂直框,可以将几个窗口小部件放在一行,或可用于格式化和布局的表中。)

这种层次结构允许直接计算所有几何结构,意味着应用程序可在不同视觉设置(例如字体大小)中使用,并能在重新调整窗口大小时(甚至在国际化程序时)做出正确的反应。它还可以使在运行时期间自动生成 GUI 的开发更容易。


GTK+ 应用程序中窗口小部件层次结构的示例
GTK+ 应用程序中窗口小部件层次结构的示例

在需要将一个操作与某一特定事件(例如单击按钮)连接时,必须使用“ 信号 ”,信号是允许将操作与定制函数绑定的特殊 GTK+ 类方法。例如,按钮会有“已单击”信号,可以将希望用户单击按钮时发生的操作与之绑定。每个信号都不同,所以要确保在定义处理程序函数时使用正确的函数原型。


样本 GNOME 应用程序

现在让我们看一下样本 GNOME 应用程序:一个固定的 "Hello World" 程序 -- 但并不是任意 "Hello World"。这个应用程序是由菜单、 "about" 对话框和状态栏所组成的。

该应用程序有一个带有剥离菜单的对接菜单栏和一个带有菜单提示的状态栏。它自动保存菜单上用户定义的快捷键(用鼠标在菜单上单击所需的键组合,就这样),有一个标准的 "about" 框,它的特性是自动翻译所有标准菜单项。(试运行 "LANG=es_ES ./hello_world",应用程序的菜单就会以西班牙语出现!)


hello_world.c 的屏幕快照
hello_world.c 的屏幕快照

hello_world.c 的源代码
hello_world.c
1       /* Hello World (Gnome Edition)
2        * Listing 1
3        * This code is public domain, so use it as you please.
4        */
5
6       /* this include will include everything needed for GNOME, including all the
7        * libraries that gnome needs, such as gtk, imlib, etc ...*/
8       #include <gnome.h>
9
10      /* this is usually defined by autoconf but we're just using simple makefiles */
11      #define VERSION "1.0"
12
13      /* "callback" function (signal handler) which will quit the application*/
14      static void
15      exit_hello(GtkWidget *widget, gpointer data)
16      {
17              gtk_main_quit ();
18      }
19
20      /* callback function for when the window closes */
21      static int
22      delete_event(GtkWidget *widget, gpointer data)
23      {
24              gtk_main_quit ();
25              return FALSE; /* false means continue with closing the window */
26      }
27
28      /* a callback for the about menu item, it will display a simple "About"
29       * dialog box standard to all gnome applications
30       */
31      static void
32      about_hello(GtkWidget *widget, gpointer data)
33      {
34              GtkWidget *box;
35              const char *authors[] = {
36                      James Bond,
37                      NULL
38              };
39
40              box = gnome_about_new(/*title: */ "Hello World (Gnome Edition)",
41                                    /*version: */VERSION,
42                                    /*copyright: */ "(C) 1999 Secret Agents Inc.",
43                                    /*authors: */authors,
44                                    /*other comments: */
45                                    "An extremely complicated application which "
46                                    "does absolutely nothing useful",
47                                    NULL);
48              gtk_widget_show(box);
49      }
50
51      /* define the menus here */
52
53      static GnomeUIInfo file_menu [] = {
54              /* some item which is not one of the standard ones, the null
55               * would be the callback, however we don't want to really do anything */
56              GNOMEUIINFO_ITEM_NONE("Something","Just an item which does nothing",NULL),
57              /* standard exit item */
58              GNOMEUIINFO_MENU_EXIT_ITEM(exit_hello,NULL),
59              GNOMEUIINFO_END
60      };
61
62      static GnomeUIInfo help_menu [] = {
63              /* load the helpfiles for this application if available */
64              GNOMEUIINFO_HELP("hello_world"),
65              /* the standard about item */
66              GNOMEUIINFO_MENU_ABOUT_ITEM(about_hello,NULL),
67              GNOMEUIINFO_END
68      };
69
70      /* define the main menubar */
71      static GnomeUIInfo main_menu [] = {
72              GNOMEUIINFO_MENU_FILE_TREE(file_menu),
73              GNOMEUIINFO_MENU_HELP_TREE(help_menu),
74              GNOMEUIINFO_END
75      };
76
77      /* Our main function */
78      int
79      main(int argc, char *argv[])
80      {
81              GtkWidget *app; /* pointer to our main window */
82              GtkWidget *w; /* pointer to some widget */
83
84              /* initialize gnome */
85              gnome_init("hello_world", VERSION, argc, argv);
86
87              /* create main window */
88              app = gnome_app_new("hello_world", "Hello World (Gnome Edition)");
89              /* connect "delete_event" (happens when the window is closed */         
90              gtk_signal_connect(GTK_OBJECT(app), "delete_event",
91                                 GTK_SIGNAL_FUNC(delete_event),
92                                 NULL);
93
94              /* add the menus to the main window */
95              gnome_app_create_menus(GNOME_APP(app), main_menu);
96
97              /* setup appbar (bottom of window bar for status, menu hints and
98               * progress display) */
99              w = gnome_appbar_new(FALSE, TRUE, GNOME_PREFERENCES_USER);
100             gnome_app_set_statusbar(GNOME_APP(app), w);
101
102             /* make menu hints display on the appbar */
103             gnome_app_install_menu_hints(GNOME_APP(app), main_menu);
104
105             /* set up some bogus window contents */
106             w = gtk_label_new("Some really really really random\ntext\ngoes\nhere!");
107
108             /* add those contents to the window */
109             gnome_app_set_contents(GNOME_APP(app), w);
110
111             /* show all the widgets on the main window and the window itself */
112             gtk_widget_show_all(app);
113
114             /* run the main loop */
115             gtk_main();
116
117             return 0;
118     }

现在让我们详细查看 "Hello World" 的情况。因为某些部分是自带说明的,还有一些是由程序员注释说明的,所以我们就着重看一下程序的基本部分。在清单顶部,可以看到我们包括了 gnome.h,该文件依次包括了完整 GNOME 功能性所必需的所有其它库。

在 main 函数中,可以看到以下代码:

84              /* initialize gnome */
85              gnome_init("hello_world", VERSION, argc, argv);

上一行初始化了所有 GNOME 的库、GTK+ 和所有其它必需的库,并对缺省命令行自变量进行语法分析。这种初始化必须在每个 GNOME 应用程序中出现,无一例外。

在清单的稍后一些可以看到以下代码:

87              /* create main window */
88              app = gnome_app_new("hello_world", "Hello World (Gnome Edition)");
89              /* connect "delete_event" (happens when the window is closed */         
90              gtk_signal_connect(GTK_OBJECT(app), "delete_event",
91                                 GTK_SIGNAL_FUNC(delete_event),
92                                 NULL);

以上代码执行两个操作:第一行为 "hello_world" 创建一个新的应用程序(主)窗口,窗口标题是 "Hello World (Gnome Edition)",并将 "app" 设置成指向这个新创建的对象。第二部分 (gtk_signal_connect) 将应用程序与要调用的函数连接起来;在向对象 "app" 发出特定信号 ("delete_event") 时会调用这个函数。这个信号是在用户从窗口管理器中请求关闭窗口时发出的。这里就是我们调用的函数:

20      /* callback function for when the window closes */
21      static int
22      delete_event(GtkWidget *widget, gpointer data)
23      {
24              gtk_main_quit ();
25              return FALSE; /* false means continue with closing the window */
26      }

以上告诉 GTK+ 应该退出 main 循环 (gtk_main_quit),然后返回 FALSE,表示 GTK+ 应该继续关闭窗口。请注意,每个信号都应该有其自己的原型(任何返回值都可以有不同的含义,并且变量列表可以不同)。例如,从菜单项的回调应该类似于 "void function(GtkWidget *, gpointer data)"。有关这些内容的帮助,请参阅 GTK+ 和 GNOME 参考文档中有关可用信号及其正确原型的说明(见 参考资料)。

现在让我们把注意力集中在了解如何定义菜单上。通过使用 GNOME 应用程序框架(GnomeApp 类),可以定义结构 -- 框架构建菜单和绑定必需的信号。菜单是静态结构数组,是用构建菜单所需的正确信息来预置的。为使这个操作更简单,存在帮助程序宏(在 libgnomeui/gnome-app-helper.h 中定义)以便在菜单定义中定义单一项。这里是 "hello_world" 示例的菜单定义(为清楚起见,已从中删除了注释):

53      static GnomeUIInfo file_menu [] = {
54              /* some item which is not one of the standard ones, the null
55               * would be the callback, however we don't want to really do anything */
56              GNOMEUIINFO_ITEM_NONE("Something","Just an item which does nothing",NULL),
57              /* standard exit item */
58              GNOMEUIINFO_MENU_EXIT_ITEM(exit_hello,NULL),
59              GNOMEUIINFO_END
60      };
61
62      static GnomeUIInfo help_menu [] = {
63              /* load the helpfiles for this application if available */
64              GNOMEUIINFO_HELP("hello_world"),
65              /* the standard about item */
66              GNOMEUIINFO_MENU_ABOUT_ITEM(about_hello,NULL),
67              GNOMEUIINFO_END
68      };
69
70      /* define the main menubar */
71      static GnomeUIInfo main_menu [] = {
72              GNOMEUIINFO_MENU_FILE_TREE(file_menu),
73              GNOMEUIINFO_MENU_HELP_TREE(help_menu),
74              GNOMEUIINFO_END
75      };

第一个数组定义了 "File" 菜单(这是样式指南所必需的,并且总应该有 "Exit" 项)。该菜单有一项 -- our own custom item -- 标题为 "Something",提示为 "Just an item which does nothing"。但该项有一个 NULL 回调,因此在单击时绝不会有任何事发生。 "File" 菜单当然有标准退出项,在单击该项时调用 exit_hello 函数(数据自变量是 NULL)。以类似的方法定义帮助菜单,除了如果实际编制并安装了 HTML 帮助文件,第一项可以扩展到标准帮助主题。然后 main_menu 定义菜单栏,它有两个(标准)树。在这样定义了菜单后,需要调用 gnome_app_create_menus(GNOME_APP(app), main_menu)。这将创建菜单栏并把其贴到窗口上。

还创建了 "appbar" (窗口底部一个美化的状态栏),并为其上的菜单项安装提示(长描述)。使用以下代码来做到这一点:

98               * progress display) */
99              w = gnome_appbar_new(FALSE, TRUE, GNOME_PREFERENCES_USER);
100             gnome_app_set_statusbar(GNOME_APP(app), w);
101
102             /* make menu hints display on the appbar */
103             gnome_app_install_menu_hints(GNOME_APP(app), main_menu);

在示例中所做的最后一件重要事情是向窗口添加了一些内容。这只是一个示例,所以我们只是使用以下代码创建了一个带有随意文字的 GtkLabel,并添加到窗口上:

105             /* set up some bogus window contents */
106             w = gtk_label_new("Some really really really random\ntext\ngoes\nhere!");
107
108             /* add those contents to the window */
109             gnome_app_set_contents(GNOME_APP(app), w);

然后显示应用程序窗口(和它包含的所有窗口小部件)并跳到 main 循环函数 (gtk_main) 中,在那里等待事件发生。以下代码就是执行这些操作的:

111             /* show all the widgets on the main window and the window itself */
112             gtk_widget_show_all(app);
113
114             /* run the main loop */
115             gtk_main();

我们已介绍了 GNOME 应用程序的最基本情况。当然可以利用库来做更多事情,我们也会在稍后涉及一些这方面的内容。


编译 GNOME 应用程序

您已经了解如何编写一个简单的 GNOME 应用程序了,现在需要了解如何编译它。有一个特殊的脚本 gnome-config,已设计成为应用程序的编译设置正确的命令行。它需要一个开关("--cflags" 或 "--libs",前者用于获得编译器标志,后者提供链器变量)。还必须指定希望使用哪些库(在示例中是 "gnome" 和 "gnomeui")。那么假设有一个类似于 hello_world.c 的简单应用程序。以下是可以正确编译这个应用程序的简单 Makefile:

 CFLAGS=-g -Wall `gnome-config --cflags gnome gnomeui`
  LDFLAGS=`gnome-config --libs gnome gnomeui`
  all: hello_world
  clean:
    rm -f hello_world core

最后一行上 "rm" 前面的空格由一个 TAB 组成,而不是空格。引号是单反引号。

余下的事由 make 实现。当然,对于复杂的应用程序还需要更复杂的设置过程,但说真的,这不是 GNOME 问题。事实上,一个称为 gIDE 的项目已经在进行以真正保护您不受这种复杂性所影响。


GNOME 编程的其它好处

GNOME 库还为开发者提供一些其它好处。例如,布景窗口小部件可以提供显示图形的一种高级手段,它的用法不只限于图形应用程序。例如,Gnumeric 电子表格使用布景用于其网格。GNOME 应用程序还应该能与会话管理器一起使用,并且在库中这方面有相当多的支持。用于构建多文档界面或 MDI 应用程序(对于大多数带有数据文件的应用程序很有用)的框架比单文档应用程序的框架稍微复杂一点,但 GNOME 中的 MDI 框架尽可能地处理以使这一步简化。如果将数据和用户界面分开,应该能够不太困难地将单文档应用程序转换为 MDI。

GNOME 编程的另一方面就是 CORBA 的使用。GNOME 使用 ORBit 作为它的 orb(一个模块,用于处理应用程序之间的通信)。在有些地方,CORBA 已得到广泛使用,但它的使用还没有达到应普遍的程度。最新的文档模型 Bonobo 仍处在开发阶段,但应用程序,特别是 GNOME Workshop 办公软件项目中的应用程序已开始使用它了。 Bonobo 可以让应用程序比以往更加模块化,并能使程序间的协作范围比当前可能的范围更广。


开发工具

已经开发了一些工具以简化 GNOME 程序员的工作。在这里提到的那些工具还处于开发阶段,但已经可用(但我建议在这些工具达到版本 1.0 之前不要在任务关键型项目中使用它们)。

一个工具是 Glade ,一种界面构建器。它不只创建源代码,还为您创建整个构建环境。将来,它应该与 IDE 集成,以成为一个完全自给自足的开发工具。


使用中的 Glade 界面构建器
使用中的 Glade 界面构建器

另一个“工具” libglade 实际上不是一个程序;它是一个从 Glade 获得描述文件的库,在应用程序启动时构建界面。这是一个对 Glade 代码生成模式有吸引力的替代选择,它在定义和界面修改方面可以有更大的灵活性。

第三个工具 gIDE 为那些还没有自己喜欢的源码编辑器的人们提供了 IDE 的服务。这个工具还将与 Glade 进行集成,以为开发环境提供具竞争力的商业产品及服务。


参考资料

有一个 专用于 GNOME 应用程序开发者的站点。它包含了 API 参考大全、教程、白皮书和其它有帮助的信息。

对 GNOME 开发者有帮助的其它一些站点包括:

关于作者

George (在捷克是 Jiri 或 Jirka)Lebl 出生在捷克斯洛伐克布拉格,现在居住在美国加利福尼亚的圣迭哥,他将在那里获得学位。在使用了几年非 UNIX 操作系统后,他开始使用 Unix,在四年前成为 Unix 的追随者,两年前成为“自由软件”追随者。他在 1997 年秋天参加了 GNOME 项目,最后又成了 C 的追随者。最重要的是,他是一个 VI 使用者。可通过 jirka@5z.com 与他联系。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=52794
ArticleTitle=利用 GNOME 库来简化应用编程
publish-date=09011999
author1-email=jirka@5z.com
author1-email-cc=jirka@5z.com

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。