基于 GTK+ 的 GNOME 编程入门
在图形用户界面(GUI)编程中,GTK+ 和 GNOME 库为开发者提供了强大的工具集,用于创建功能丰富、美观易用的应用程序。本文将详细介绍如何使用 GTK+ 和 GNOME 库进行编程,包括创建窗口、菜单和对话框等常见 GUI 元素。
1. GTK+ 与 GNOME 概述
GTK+ 是一个跨平台的 GUI 工具包,设计为桌面中立,可轻松移植到 Windows 或其他窗口系统。然而,GTK+ 缺乏将程序与桌面集成的功能,如保存程序配置、显示帮助文件或编写小程序。GNOME 库则包含了扩展 GTK+ 的 GNOME 小部件,用更易用的小部件替换了部分 GTK+ 小部件。
在使用 GNOME 库之前,需要在程序开始时进行初始化,就像使用 GTK+ 时调用
gtk_init
一样。可以使用
gnome_program_init
函数进行初始化:
GnomeProgram* gnome_program_init (const char *app_id, const char *app_version,
const GnomeModuleInfo *module_info,
int argc, char **argv,
const char *first_property_name,
...);
该函数接受应用程序 ID、版本号、模块信息、命令行参数和应用程序属性等参数。可选的属性列表允许设置一些选项,如查找位图图形的目录。
2. 创建 GNOME 窗口
下面是一个简单的 GNOME 程序示例,创建一个
GnomeApp
窗口:
#include <gnome.h>
int main (int argc, char *argv[])
{
GtkWidget *app;
gnome_program_init (“gnome1”, “1.0”, MODULE, argc, argv, NULL);
app = gnome_app_new (“gnome1”, “The Window Title”);
gtk_widget_show(app);
gtk_main ();
return 0;
}
编译时需要包含 GNOME 头文件,并通过
pkg-config
传递
libgnomeui
和
libgnome
:
$ gcc gnome1.c –o gnome1 `pkg-config --cflags --libs libgnome-2.0 libgnomeui-2.0`
GnomeApp
小部件扩展了
GtkWindow
,方便添加菜单、工具栏和底部状态栏。由于它继承自
GtkWindow
,可以使用任何
GtkWindow
函数。
3. 创建 GNOME 菜单
在 GNOME 中创建下拉菜单非常简单。每个菜单由
GNOMEUIInfo
结构体数组表示,数组中的每个元素对应一个菜单项。例如,有文件、编辑和视图菜单时,将有三个数组描述每个菜单的内容。定义完每个单独的菜单后,通过在另一个
GNOMEUIInfo
结构体数组中引用这些数组来创建菜单栏。
GNOMEUIInfo
结构体定义如下:
typedef struct {
GnomeUIInfoType type;
gchar const *label;
gchar const *hint;
gpointer moreinfo;
gpointer user_data;
gpointer unused_data;
GnomeUIPixmapType pixmap_type;
gconstpointer pixmap_info;
guint accelerator_key;
GdkModifierType ac_mods;
GtkWidget *widget;
} GnomeUIInfo;
其中,
type
定义了后续菜单项的类型,有 10 种
GnomeUIInfoType
可供选择,如下表所示:
| GnomeUIInfoType | 描述 |
| — | — |
| GNOME_APP_UI_ENDOFINFO | 表示这是数组中的最后一个菜单项 |
| GNOME_APP_UI_ITEM | 普通菜单项或单选按钮(如果前面有 GNOME_APP_UI_RADIOITEMS 条目) |
| GNOME_APP_UI_TOGGLEITEM | 切换按钮或复选框菜单项 |
| GNOME_APP_UI_RADIOITEMS | 单选按钮组 |
| GNOME_APP_UI_SUBTREE | 表示此元素是子菜单。将 moreinfo 设置为指向子菜单数组 |
| GNOME_APP_UI_SEPARATOR | 在菜单中插入分隔线 |
| GNOME_APP_UI_HELP | 创建用于帮助菜单的帮助主题列表 |
| GNOME_APP_UI_BUILDER_DATA | 指定后续条目的构建器数据 |
| GNOME_APP_UI_ITEM_CONFIGURABLE | 可配置的菜单项 |
| GNOME_APP_UI_SUBTREE_STOCK | 与 GNOME_APP_UI_SUBTREE 相同,只是标签文本应在 gnome-libs 目录中查找 |
| GNOME_APP_UI_INCLUDE | 与 GNOME_APP_UI_SUBTREE 相同,只是菜单项包含在当前菜单中,而不是作为子菜单 |
下面是一个创建菜单的示例代码:
#include <gnome.h>
void closeApp ( GtkWidget *window, gpointer data)
{
gtk_main_quit();
}
void item_clicked(GtkWidget *widget, gpointer user_data)
{
printf("Item Clicked!\n");
}
static GnomeUIInfo submenu[] = {
{GNOME_APP_UI_ITEM, "SubMenu", "SubMenu Hint",
GTK_SIGNAL_FUNC(item_clicked), NULL, NULL, 0, NULL, 0, 0, NULL},
{GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, NULL}
};
static GnomeUIInfo menu[] = {
{GNOME_APP_UI_ITEM, "Menu Item 1", "Menu Hint",
NULL, NULL, NULL, 0, NULL, 0, 0, NULL},
{GNOME_APP_UI_SUBTREE, "Menu Item 2", "Menu Hint", submenu,
NULL, NULL, 0, NULL, 0, 0, NULL},
{GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, NULL}
};
static GnomeUIInfo menubar[] = {
{GNOME_APP_UI_SUBTREE, "Toplevel Item", NULL, menu, NULL,
NULL, 0, NULL, 0, 0, NULL},
{GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, NULL}
};
int main (int argc, char *argv[])
{
GtkWidget *app;
gnome_program_init ("gnome1", "0.1", LIBGNOMEUI_MODULE,
argc, argv,
GNOME_PARAM_NONE);
app = gnome_app_new("gnome1", "Menus, menus, menus");
gtk_window_set_default_size ( GTK_WINDOW(app), 300, 200);
g_signal_connect ( GTK_OBJECT (app), "destroy",
GTK_SIGNAL_FUNC ( closeApp), NULL);
gnome_app_create_menus ( GNOME_APP(app), menubar);
gtk_widget_show(app);
gtk_main();
return 0;
}
运行该程序可以看到菜单栏、子菜单和回调函数的效果。
由于
GnomeUIInfo
结构体包含 11 个条目,大多数情况下为 NULL 或零值,编写时容易出错。为了简化操作,GNOME 定义了宏来自动生成这些结构体,并添加图标和键盘快捷键。有两组宏,一组用于定义单个菜单项,另一组用于顶层定义:
#include <libgnomeui/libgnomeui.h>
#define GNOMEUIINFO_MENU_OPEN_ITEM (cb, data)
#define GNOMEUIINFO_MENU_SAVE_ITEM (cb, data)
#define GNOMEUIINFO_MENU_SAVE_AS_ITEM (cb, data)
#define GNOMEUIINFO_MENU_PRINT_ITEM (cb, data)
#define GNOMEUIINFO_MENU_PRINT_SETUP_ITEM(cb, data)
#define GNOMEUIINFO_MENU_CLOSE_ITEM (cb, data)
#define GNOMEUIINFO_MENU_EXIT_ITEM (cb, data)
#define GNOMEUIINFO_MENU_QUIT_ITEM (cb, data)
#define GNOMEUIINFO_MENU_CUT_ITEM (cb, data)
#define GNOMEUIINFO_MENU_COPY_ITEM (cb, data)
#define GNOMEUIINFO_MENU_PASTE_ITEM (cb, data)
#define GNOMEUIINFO_MENU_SELECT_ALL_ITEM(cb, data)
#define GNOMEUIINFO_MENU_FILE_TREE (tree)
#define GNOMEUIINFO_MENU_EDIT_TREE (tree)
#define GNOMEUIINFO_MENU_VIEW_TREE (tree)
#define GNOMEUIINFO_MENU_SETTINGS_TREE (tree)
#define GNOMEUIINFO_MENU_FILES_TREE (tree)
#define GNOMEUIINFO_MENU_WINDOWS_TREE (tree)
#define GNOMEUIINFO_MENU_HELP_TREE (tree)
#define GNOMEUIINFO_MENU_GAME_TREE (tree)
下面是使用宏创建菜单的示例:
#include <gnome.h>
static GnomeUIInfo filemenu[] = {
GNOMEUIINFO_MENU_NEW_ITEM ("New", "Menu Hint", NULL, NULL ),
GNOMEUIINFO_MENU_OPEN_ITEM (NULL, NULL),
GNOMEUIINFO_MENU_SAVE_AS_ITEM (NULL, NULL),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_EXIT_ITEM (NULL, NULL),
GNOMEUIINFO_END
};
static GnomeUIInfo editmenu[] = {
GNOMEUIINFO_MENU_FIND_ITEM (NULL, NULL),
GNOMEUIINFO_END
};
static GnomeUIInfo menubar[] = {
GNOMEUIINFO_MENU_FILE_TREE (filemenu),
GNOMEUIINFO_MENU_EDIT_TREE (editmenu),
GNOMEUIINFO_END
};
int main (int argc, char *argv[])
{
GtkWidget *app, *toolbar;
gnome_program_init ("gnome1", "0.1", LIBGNOMEUI_MODULE,
argc, argv,
GNOME_PARAM_NONE);
app = gnome_app_new("gnome1", "Menus, menus, menus");
gtk_window_set_default_size ( GTK_WINDOW(app), 300, 200);
gnome_app_create_menus ( GNOME_APP(app), menubar);
gtk_widget_show(app);
gtk_main();
return 0;
}
使用宏可以显著减少代码量,使菜单代码更易读。
4. 创建对话框
对话框是 GUI 应用程序中与用户交互和通知重要事件的重要部分。GTK+ 提供了从
GtkWindow
派生的特殊对话框小部件,使编程更加方便。
4.1 GtkDialog
GtkDialog
是
GtkWindow
的子类,继承了其所有功能和属性。它将窗口分为两部分,一部分用于小部件内容,另一部分用于底部的按钮。可以使用
gtk_dialog_new_with_buttons
函数创建对话框:
GtkWidget* gtk_dialog_new_with_buttons (const gchar *title,
GtkWindow *parent,
GtkDialogFlags flags,
const gchar *first_button_text,
...);
该函数创建一个带有标题和按钮的对话框窗口。
parent
参数应指向应用程序的主窗口,以确保对话框与主窗口关联,并在主窗口最小化时一同最小化。
flags
参数决定了对话框的属性组合,可使用按位或运算符进行组合,例如
(GTK_DIALOG_MODAL|GTK_DIALOG_NO_SEPARATOR)
表示既是模态对话框又没有分隔线。
下面是一个创建带有 OK 和 Cancel 按钮的对话框示例:
GtkWidget *dialog = gtk_dialog_new_with_buttons ("Important question",
parent_window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
NULL);
创建对话框后,需要向其中添加内容。
GtkDialog
包含一个现成的
GtkVBox
用于填充小部件,可以通过
GTK_DIALOG(dialog)->vbox
获取指针。
4.2 模态对话框
模态对话框会阻止用户在做出响应之前进行其他操作,适用于用户即将进行有严重后果的操作或报告错误和警告消息的情况。可以通过设置
GTK_DIALOG_MODAL
标志并调用
gtk_widget_show
使对话框成为模态对话框,但更好的方法是使用
gtk_dialog_run
函数:
typedef enum
{
GTK_RESPONSE_NONE = -1,
GTK_RESPONSE_REJECT = -2,
GTK_RESPONSE_ACCEPT = -3,
GTK_RESPONSE_DELETE_EVENT = -4,
GTK_RESPONSE_OK = -5,
GTK_RESPONSE_CANCEL = -6,
GTK_RESPONSE_CLOSE = -7,
GTK_RESPONSE_YES = -8,
GTK_RESPONSE_NO = -9,
GTK_RESPONSE_APPLY = -10,
GTK_RESPONSE_HELP = -11
} GtkResponseType;
GtkWidget *dialog = create_dialog();
int result = gtk_dialog_run(GTK_DIALOG(dialog));
switch (result)
{
case GTK_RESPONSE_ACCEPT:
delete_file();
break;
case GTK_RESPONSE_REJECT:
do_nothing();
break;
default:
dialog_was_cancelled ();
break;
}
gtk_widget_destroy (dialog);
gtk_dialog_run
函数会停止程序执行,直到用户按下按钮或对话框被销毁,并返回一个整数结果,表示用户按下的按钮。可以使用
switch
语句根据结果执行相应的逻辑。
4.3 非模态对话框
非模态对话框的工作方式略有不同。创建方法与模态对话框相同,但不使用
gtk_dialog_run
,而是连接回调函数到
GtkDialog
的 “response” 信号:
void dialog_button_clicked (GtkWidget *dialog, gint response, gpointer user_data)
{
switch (response)
{
case GTK_RESPONSE_ACCEPT:
do_stuff();
break;
case GTK_RESPONSE_REJECT:
do_nothing();
break;
default:
dialog_was_cancelled ();
break;
}
gtk_widget_destroy(dialog);
}
int main()
{
...
GtkWidget *dialog = create_dialog();
g_signal_connect ( GTK_OBJECT (dialog), "response",
GTK_SIGNAL_FUNC (dialog_button_clicked), user_data );
gtk_widget_show(dialog);
...
}
非模态对话框可能会出现一些问题,因为用户不必立即响应,可能会最小化并忘记对话框。需要考虑用户在关闭第一个实例之前尝试再次打开对话框的情况,可以检查对话框指针是否为 NULL,如果不为 NULL 则调用
gtk_window_present
重新显示现有对话框。
4.4 GtkMessageDialog
对于非常简单的对话框,
GtkDialog
可能过于复杂。
GtkMessageDialog
可以在一行代码中创建消息对话框:
GtkWidget* gtk_message_dialog_new (GtkWindow *parent, GtkDialogFlags flags,
GtkMessageType type,
GtkButtonsType buttons,
const gchar *message_format,
...);
该函数创建一个带有图标、标题和可配置按钮的对话框。
type
参数根据对话框的用途设置库存图标和标题,有四种常见类型:
-
GTK_MESSAGE_INFO
-
GTK_MESSAGE_WARNING
-
GTK_MESSAGE_QUESTION
-
GTK_MESSAGE_ERROR
还可以选择
GTK_MESSAGE_OTHER
值。
buttons
参数可以传递
GtkButtonsType
,而不是单独列出每个按钮,常见的
GtkButtonsType
如下表所示:
| GtkButtonsType | 描述 |
| — | — |
| GTK_BUTTONS_OK | 一个 OK 按钮 |
| GTK_BUTTONS_CLOSE | 一个 Close 按钮 |
| GTK_BUTTONS_CANCEL | 一个 Cancel 按钮 |
| GTK_BUTTONS_YES_NO | Yes 和 No 按钮 |
| GTK_BUTTONS_OK_CANCEL | OK 和 Cancel 按钮 |
| GTK_BUTTONS_NONE | 没有按钮 |
通过以上介绍,你可以使用 GTK+ 和 GNOME 库创建功能丰富的 GUI 应用程序,包括窗口、菜单和对话框等常见元素。在实际开发中,可以根据需求选择合适的小部件和方法,提高开发效率和用户体验。
基于 GTK+ 的 GNOME 编程入门
5. 总结与实践建议
在前面的内容中,我们详细介绍了如何使用 GTK+ 和 GNOME 库进行 GUI 编程,包括创建窗口、菜单和对话框等重要元素。下面为大家总结一些关键要点,并给出实践建议。
5.1 关键要点总结
- GTK+ 与 GNOME 特性 :GTK+ 是跨平台的 GUI 工具包,具有桌面中立性,但缺乏与桌面集成的功能;GNOME 库扩展了 GTK+,提供了更易用的小部件和方便的菜单、对话框创建方式。
-
窗口创建
:使用
GnomeApp可以轻松创建带有菜单、工具栏和状态栏的窗口,初始化时需要调用gnome_program_init函数。 -
菜单创建
:可以使用
GnomeUIInfo结构体手动创建菜单,也可以使用 GNOME 提供的宏来简化操作,使代码更易读和维护。 -
对话框创建
:GTK+ 提供了
GtkDialog和GtkMessageDialog用于创建不同类型的对话框,包括模态和非模态对话框。模态对话框使用gtk_dialog_run函数,非模态对话框则通过连接回调函数到 “response” 信号来处理用户响应。
5.2 实践建议
- 代码复用 :在创建菜单和对话框时,尽量使用 GNOME 提供的宏和函数,避免手动编写复杂的结构体和代码,提高代码的复用性和可维护性。
-
错误处理
:在使用对话框时,要考虑各种可能的用户响应,使用
switch语句进行全面的错误处理,确保程序的健壮性。 - 用户体验 :合理使用模态和非模态对话框,根据不同的场景选择合适的对话框类型,以提高用户体验。例如,在用户进行重要操作时使用模态对话框,避免用户误操作。
6. 流程图与操作步骤梳理
为了帮助大家更好地理解和应用前面介绍的知识,下面为大家提供创建菜单和对话框的流程图以及详细操作步骤。
6.1 创建菜单的流程图
graph TD;
A[初始化 GNOME 库] --> B[定义菜单项结构体数组];
B --> C[定义菜单栏结构体数组];
C --> D[创建 GnomeApp 窗口];
D --> E[设置窗口大小和关闭回调];
E --> F[使用 gnome_app_create_menus 创建菜单];
F --> G[显示窗口并进入主循环];
6.2 创建菜单的操作步骤
-
初始化 GNOME 库
:调用
gnome_program_init函数进行初始化。 -
定义菜单项结构体数组
:可以使用
GnomeUIInfo结构体手动定义,也可以使用 GNOME 提供的宏。 - 定义菜单栏结构体数组 :引用菜单项结构体数组来定义菜单栏。
-
创建 GnomeApp 窗口
:使用
gnome_app_new函数创建窗口。 -
设置窗口大小和关闭回调
:使用
gtk_window_set_default_size设置窗口大小,使用g_signal_connect连接关闭回调函数。 -
创建菜单
:使用
gnome_app_create_menus函数创建菜单。 -
显示窗口并进入主循环
:使用
gtk_widget_show显示窗口,使用gtk_main进入主循环。
6.3 创建对话框的流程图
graph TD;
A[创建对话框] --> B{模态对话框?};
B -- 是 --> C[使用 gtk_dialog_run 等待用户响应];
B -- 否 --> D[连接回调函数到“response”信号];
C --> E[根据响应结果执行相应逻辑];
D --> E;
E --> F[销毁对话框];
6.4 创建对话框的操作步骤
-
创建对话框
:使用
gtk_dialog_new_with_buttons或gtk_message_dialog_new函数创建对话框。 -
判断对话框类型
:如果是模态对话框,使用
gtk_dialog_run函数等待用户响应;如果是非模态对话框,连接回调函数到 “response” 信号。 -
处理用户响应
:根据用户按下的按钮,使用
switch语句执行相应的逻辑。 -
销毁对话框
:使用
gtk_widget_destroy函数销毁对话框。
通过以上的总结、建议和流程图,相信大家对使用 GTK+ 和 GNOME 库进行 GUI 编程有了更清晰的认识。在实际开发中,不断实践和探索,将这些知识运用到项目中,提高自己的编程能力。
基于GTK+的GNOME编程入门指南
超级会员免费看
6645

被折叠的 条评论
为什么被折叠?



