GNOME 图形编程与 GTK+ 工具包详解
1. Cairo 库概述
Cairo 是一个用 C 语言编写的绘图库,旨在为所有输出媒体生成一致的输出,并在可用时利用显示硬件加速(例如通过 X Render 扩展)。其 API 提供了类似于 PostScript 和 PDF 的图形操作,包括:
- 绘制和填充三次贝塞尔曲线。
- 变换和合成半透明图像。
- 抗锯齿文本渲染。
任何仿射变换都能改变所有绘图操作,如缩放、旋转、剪切等。Cairo 是免费软件,可根据 GNU LGPL 2.1 版本或 Mozilla Public License (MPL) 1.1 版本的条款进行再分发和修改。
2. Cairo 的绑定
Cairo 支持多种编程语言的绑定,包括 C++、C# 以及其他 CLI 语言,如 Delphi、Eiffel、Factor、Harbour、Haskell、Julia、Lua、Perl、PHP、Python、Ruby、Rust、Scheme、Smalltalk 等。此外,它还能与 GUI 工具包集成,例如 GTK 从 2005 年的 2.8 版本开始使用 Cairo 渲染大部分图形控制元素,从 3.0 版本起,所有渲染都通过 Cairo 完成。
Cairo 支持多种后端输出,包括通过 Xlib 和 XCB 输出到 X Window 系统、Win32 GDI、OS X Quartz Compositor、BeOS API、OS/2、OpenGL 上下文、本地图像缓冲区、PNG 文件、PDF、PostScript、DirectFB 和 SVG 文件等。目前还有针对 OpenVG、Qt、Skia 和 Microsoft 的 Direct2D 等图形 API 的后端正在开发中。
3. Cairo 的应用
Cairo 在开源社区中以提供跨平台的高级 2D 绘图支持而闻名,以下是一些使用 Cairo 的项目:
- Mono 项目(包括 Moonlight)从早期就开始使用 Cairo 为其 GDI+ (libgdip lus) 和 System.Drawing 命名空间的后端提供支持。
- Mozilla 项目在其 Gecko 布局引擎中使用 Cairo 来渲染 Mozilla 产品的图形输出。例如,Gecko 1.8 用于渲染 SVG 和
<canvas>
内容,Gecko 1.9 则将 Cairo 用作渲染网页内容和用户界面的图形后端。
- WebKit 框架在所有 GTK 和 EFL 端口渲染中使用 Cairo,并为 SVG 和
<canvas>
内容提供支持。
- Poppler 库使用 Cairo 渲染 PDF 文档,能够绘制抗锯齿矢量图形和透明对象。
- 矢量图形应用 Inkscape 使用 Cairo 库进行轮廓模式显示以及处理 PDF 和 PostScript。
4. GdkPixbuf 库
GdkPixbuf 是一个用于加载各种格式图形资源(如图标)的库,它可以加载多种格式的图像数据,并将其存储为内存中的线性缓冲区。这些缓冲区可以进行缩放、合成、修改、保存或渲染。GdkPixbuf 支持的图像格式包括 PNG、JPEG、TIFF、TGA 和 GIF 等。此外,你还可以编写一个 GdkPixbuf-loader 模块并将其安装到指定位置,以支持加载特定的文件格式。GTK 工具包使用 GdkPixbuf 来加载图形资源。
4.1 构建 GdkPixbuf
构建 GdkPixbuf 需要安装以下组件:
- 符合 C99 标准的编译器和工具链。
- Meson。
- Glib 的开发文件。
根据你要支持的图像格式,还需要安装 libpng、libjpeg 和 libtiff 的开发文件。此外,可能还需要 shared-mime-info、GObject Introspection、GI-DocGen 和 mediaLib 的开发文件。
4.2 安装 GdkPixbuf
可以使用 Meson 来配置 GdkPixbuf 的构建。根据不同的平台,你可以使用 Ninja、Visual Studio 或 XCode 来构建项目。通常,在大多数平台上,可以使用以下命令在默认前缀下构建和安装 GdkPixbuf:
$ meson setup _build.
$ Meson compile -C _build
$ Meson install -C _build
你可以使用 Meson 的
--prefix
参数在配置时控制安装前缀,也可以在构建目录中使用
Meson configure
来检查当前的构建配置并更改其选项。
4.3 构建选项
在使用 Meson 时,可以使用以下命令行选项:
-
-Dgtk_doc=true
:构建 API 参考文档。
-
-Drelocatable=true
:启用应用程序包重定位支持。
5. ATK 库
Accessibility Toolkit (ATK) 是 GNOME 项目的一个开源软件库,为软件提供实现无障碍支持的 API。通常用客户端 - 服务器架构来解释无障碍框架,辅助技术(如屏幕阅读器)作为客户端,计算机应用程序作为服务器,它们通常使用平台的 IPC 技术进行通信。
在 GNOME 中,由于底层技术的历史原因,有两种类型的 API:客户端的 Assistive Technology Service Provider Interface (AT - SPI) 和服务器端的 ATK。ATK 提供抽象头文件,帮助开发人员使他们的 GUI 工具包具有无障碍性。GNOME Accessibility Implementation Library (GAIL) 曾是 ATK 为 GTK + 定义的无障碍接口实现,从 GNOME 3.2 开始,GAIL 合并到 GTK + 中,现已弃用。除了 GTK + ,其他 GUI 工具包和应用程序(如 OpenOffice - LibreOffice、Mozilla 的 Gecko、Clutter 和 WebKitGTK +)也实现了 ATK 以支持无障碍访问。
6. GTK + 工具包
GTK + 代表 GIMP Toolkit,可用于编写现代 GUI 界面。它完全用 C 语言编写,许多 Linux 桌面环境(如 GNOME 和 XFCE)都使用 GTK + 构建。GTK + 应用程序不仅可以在 Linux 平台上运行,还可以移植到非 UNIX/Linux 平台。
GTK 基于以下几个库:
- ATK:用于创建无障碍工具。
- Glib:提供通用的实用功能,如线程、动态加载、事件循环和低级数据结构等。
- GObject:为 C 语言提供面向对象的支持,通过宏实现多态和继承等面向对象原则。
- GdkPixBuf:提供图像控制功能。
- GDK (GIMP Drawing Toolkit):在 Xlib 之上提供低级绘图功能。
- Pango:帮助进行内容和布局渲染。
- Xlib:为 Linux 系统提供低级图形支持。
7. GTK + 的数据类型
在使用 GTK 编写代码时,许多基本数据类型都以 “g” 为前缀,这些类型可分为四类:
| 类别 | 具体类型 |
| ---- | ---- |
| 非标准 C 类型 | gboolean, gsize, gssize |
| 跨平台大小一致的整数类型 | gint8, guint8, gint16, guint16, gint32, guint32, gint64, guint64 |
| 比标准 C 类型更易用的类型 | gpointer, gconstpointer, guchar, guint, gushort, gulong |
| 与标准 C 类型完全对应的类型 | gchar, gint, gshort, glong, gfloat, gdouble |
这些类型确保代码可以在任何平台上使用,无需进行修改,有助于实现平台无关性。
8. GTK + 的对象层次结构
GTK + 中的对象具有层次结构,例如 GtkWindow 继承自 GtkBin,而 GtkBin 是 GtkContainer 的子类。GtkBin 是一个只有一个子控件的容器,许多 GTK + 控件都是 GtkBin 的子类,包括 GtkWindow、GtkButton、GtkFrame、GtkHandleBox 和 GtkScrolledWindow 等。
GtkContainer 用于嵌套控件以构建 GTK + 用户界面,它可以包含其他控件。GtkWidget 是所有 GTK + 控件的基类,负责管理控件的生命周期、状态和样式。GInitiallyUnowned 是一种具有浮动引用的对象类型,而 GObject 是基础对象类型。
以下是 GtkBin 的继承关系图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(GObject):::process --> B(GInitiallyUnowned):::process
B --> C(GtkWidget):::process
C --> D(GtkContainer):::process
D --> E(GtkBin):::process
E --> F(GtkWindow):::process
E --> G(GtkButton):::process
E --> H(GtkFrame):::process
E --> I(GtkHandleBox):::process
E --> J(GtkScrolledWindow):::process
9. GTK + 列表控件
GtkList 控件用作 GtkListItem 控件的垂直容器,它有一个用于接收事件的窗口,背景颜色通常为白色。GtkList 直接继承自 GtkContainer,可以使用
GTK_CONTAINER(List)
宏进行处理。
GtkList 结构体中有两个重要字段:
struct _GtkList
{
[...]
GList *selection;
guint selection_mode;
[...]
};
-
selection字段指向当前所有选中项的链表,如果没有选中项则为NULL。 -
selection_mode指定了 GtkList 的选择模式,有以下几种: -
GTK_SELECTION_SINGLE:要么为NULL,要么包含一个指向单个选中项的 GList 指针。 -
GTK_SELECTION_BROWSE:如果列表中没有控件或只有无效控件,则为NULL;否则包含一个指向一个 GList 结构的指针,即恰好一个列表项。 -
GTK_SELECTION_MULTIPLE:如果没有选中列表项则为NULL,否则为指向第一个选中项的 GList 指针。 -
GTK_SELECTION_EXTENDED:始终为NULL,默认选择模式为GTK_SELECTION_MULTIPLE。
10. GTK + 常用控件
GTK + 工具包中的控件是 GUI 应用程序的构建块,以下是一些常用控件的介绍:
-
GtkLabel
:用于显示少量文本,通常用于为其他控件(如 GtkButton)添加标签。
-
GtkSpinner
:显示一个图标大小的旋转动画,常用于替代 GtkProgressBar 来显示不确定的活动。可以使用
gtk_spinner_start()
启动动画,使用
gtk_spinner_stop()
停止动画。
-
GtkStatusbar
:位于应用程序主窗口的底部,用于提供应用程序状态的常规信息。GTK 中的状态栏维护一个消息栈,栈顶的消息将当前显示。
-
GtkImage
:用于显示图像,可以使用
gtk_image_new_from_file()
从文件加载图像,例如:
GtkWidget *image = gtk_image_new_from_file ("my_file.png");
- GtkTextView :用于显示 GtkTextBuffer 的内容。
- GtkMediaControls :用于显示视频控件,通常作为 GtkVideo 的一部分使用。
-
GtkCalendar
:显示一个月的公历日历。可以使用
gtk_calendar_new()创建一个日历,使用gtk_calendar_select_day()更改当前显示的日期,使用gtk_calendar_mark_day()在特定日期上放置标记,使用gtk_calendar_unmark_day()移除标记,使用gtk_calendar_clear_marks()清除所有标记,使用gtk_calendar_get_date()获取所选日期。 - GtkWindowControls :显示窗口框架控件,如最小化、最大化、关闭按钮和窗口图标。通常需要与另一个相反方向的 GtkWindowControls 配对使用。
此外,还有其他显示控件(如 GtkAccelLabel、GtkProgressBar、GtkInfoBar 等)、按钮和切换控件(如 GtkButton、GtkCheckButton、GtkRadioButton 等)、数值/文本数据输入控件(如 GtkEntry、GtkEntryBuffer、GtkEntryCompletion 等)、菜单和工具栏控件(如 GtkComboBox、GtkMenu、GtkToolbar 等)以及布局容器(如 GtkGrid、GtkBox、GtkAlignment 等)。这些控件共同构成了丰富的 GTK + GUI 开发工具集。
GNOME 图形编程与 GTK+ 工具包详解
11. 其他常用 GTK+ 控件
除了前面介绍的常用控件,GTK+ 还有许多其他实用的控件,下面将继续为大家详细介绍。
11.1 按钮和切换类控件
- GtkButton :当按钮被按下时会触发回调函数,它可以容纳任何有效的子控件,最常用的子控件是 GtkLabel。
// 示例代码,创建一个包含标签的按钮
GtkWidget *button = gtk_button_new_with_label("Click me");
-
GtkCheckButton
:带有离散切换按钮的控件。可以使用
gtk_check_button_new()或gtk_check_button_new_with_label()创建,通过gtk_check_button_set_active()设置状态,使用gtk_check_button_get_active()获取状态。
// 创建一个带标签的复选框按钮
GtkWidget *check_button = gtk_check_button_new_with_label("Check me");
gtk_check_button_set_active(GTK_CHECK_BUTTON(check_button), TRUE);
- GtkRadioButton :用于从多个复选按钮中进行选择,同一组的单选按钮只能有一个被选中。
// 创建一组单选按钮
GtkWidget *radio_button1 = gtk_radio_button_new_with_label(NULL, "Option 1");
GtkWidget *radio_button2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), "Option 2");
- GtkToggleButton :创建能保持其状态的按钮,按下后会保持按下状态,再次按下则恢复。
- GtkLinkButton :创建绑定到 URL 的按钮,点击后会打开指定的 URL。
// 创建一个链接按钮
GtkWidget *link_button = gtk_link_button_new("https://www.example.com");
- GtkScaleButton :点击后会弹出一个刻度条。
- GtkVolumeButton :点击后会弹出音量控制条。
- GtkSwitch :类似“电灯开关”样式的切换按钮。
11.2 数值/文本数据输入类控件
-
GtkEntry
:单行文本输入字段,默认支持大量的键绑定。当输入密码等敏感信息时,可以使用
gtk_entry_set_visibility()进入“密码模式”。
// 创建一个单行文本输入框
GtkWidget *entry = gtk_entry_new();
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); // 设置为密码模式
- GtkEntryBuffer :用于存储 GtkEntry 显示的文本内容,一个 GtkEntryBuffer 对象可以被多个 GtkEntry 共享,共享文本内容但不共享光标位置、可见性属性、图标等。
// 创建一个文本缓冲区
GtkEntryBuffer *buffer = gtk_entry_buffer_new("Initial text", -1);
GtkWidget *entry1 = gtk_entry_new_with_buffer(buffer);
GtkWidget *entry2 = gtk_entry_new_with_buffer(buffer);
- GtkEntryCompletion :与 GtkEntry 结合使用,提供自动完成功能。它实现了 GtkCellLayout 接口,允许用户在完成匹配的 GtkTreeView 中添加额外的单元格。
// 创建自动完成对象
GtkEntryCompletion *completion = gtk_entry_completion_new();
GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING);
// 添加完成项
gtk_list_store_insert_with_values(store, NULL, 0, 0, "Apple", -1);
gtk_list_store_insert_with_values(store, NULL, 1, 0, "Banana", -1);
gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
gtk_entry_completion_set_text_column(completion, 0);
GtkWidget *entry = gtk_entry_new();
gtk_entry_set_completion(GTK_ENTRY(entry), completion);
- GtkScale :是 GtkHScale 和 GtkVScale 的基类,用于选择一个范围内的值。
- GtkHScale :水平滑块控件,用于选择一个范围内的值。
// 创建一个水平滑块
GtkAdjustment *adjustment = gtk_adjustment_new(50, 0, 100, 1, 10, 0);
GtkWidget *hscale = gtk_hscale_new(adjustment);
- GtkVScale :垂直滑块控件,用于选择一个范围内的值。
- GtkSpinButton :允许用户通过点击两个箭头来增加或减少显示的值,主要属性通过调整器(adjustment)来设置。
// 创建一个微调按钮
GtkAdjustment *adjustment = gtk_adjustment_new(50, 0, 100, 1, 10, 0);
GtkWidget *spin_button = gtk_spin_button_new(adjustment, 1, 0);
- GtkEditable :文本编辑控件的接口,包含用于操作可编辑控件的函数、大量用于键绑定的动作信号以及应用程序可以连接以修改控件行为的其他信号。
11.3 菜单和工具栏类控件
-
GtkComboBox
:用于从列表项中进行选择,使用模型 - 视图模式,列表项在树模型中指定,选项的显示可以通过单元格渲染器进行调整。如果设置
GtkComboBox:has - entry属性为TRUE,则可以包含一个 GtkEntry,通过gtk_combo_box_get_child()访问。
// 创建一个组合框
GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING);
gtk_list_store_insert_with_values(store, NULL, 0, 0, "Option 1", -1);
gtk_list_store_insert_with_values(store, NULL, 1, 0, "Option 2", -1);
GtkWidget *combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), renderer, "text", 0, NULL);
- GtkComboBoxText :简单的纯文本组合框。
- GtkMenu :菜单控件。
// 创建一个菜单
GtkWidget *menu = gtk_menu_new();
GtkWidget *menu_item = gtk_menu_item_new_with_label("File");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
- GtkMenuBar :GtkMenuShell 的子类,用于容纳 GtkMenuItem 控件。
// 创建一个菜单栏
GtkWidget *menu_bar = gtk_menu_bar_new();
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_item);
- GtkMenuItem :菜单项控件。
- GtkImageMenuItem :带有图标的菜单项。
- GtkRadioMenuItem :从多个复选菜单项中进行选择。
- GtkCheckMenuItem :带有复选框的菜单项。
- GtkSeparatorMenuItem :用于菜单中的分隔线。
- GtkTearoffMenuItem :可撕下并重新附着菜单的菜单项。
- GtkToolShell :包含 GtkToolItem 控件的容器接口。
- GtkToolbar :创建包含按钮和其他控件的工具栏。
// 创建一个工具栏
GtkWidget *toolbar = gtk_toolbar_new();
GtkToolItem *tool_button = gtk_tool_button_new(NULL, "Button");
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
- GtkToolItem :添加到 GtkToolShell 的控件基类。
- GtkToolPalette :带有分类的工具调色板。
- GtkToolItemGroup :工具调色板中的子容器。
- GtkSeparatorToolItem :用于分隔工具栏中其他组的工具栏项。
- GtkToolButton :GtkToolItem 的子类,用于显示按钮。
- GtkMenuToolButton :包含一个带有额外下拉菜单的按钮的 GtkToolItem。
- GtkToggleToolButton :带有切换按钮的 GtkToolItem。
- GtkRadioToolButton :包含单选按钮的工具栏项。
12. 布局容器控件
布局容器控件在 GTK+ 中用于组织和排列其他控件,下面为大家介绍几种常见的布局容器。
12.1 GtkGrid
GtkGrid 是一个容器,它将子控件排列成行列形式,支持任意位置和水平 - 垂直跨度。可以使用
gtk_grid_attach()
添加子控件,子控件可以跨越多行或多列,使用
gtk_grid_attach_next_to()
在现有子控件旁边添加子控件,使用
gtk_grid_remove()
从网格中移除子控件。
// 创建一个网格布局
GtkWidget *grid = gtk_grid_new();
GtkWidget *button1 = gtk_button_new_with_label("Button 1");
GtkWidget *button2 = gtk_button_new_with_label("Button 2");
// 将按钮添加到网格中
gtk_grid_attach(GTK_GRID(grid), button1, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), button2, 1, 0, 1, 1);
12.2 GtkBox
GtkBox 控件将子控件排列成单行或单列,具体是行还是列取决于
GtkOrientable:orientation
属性的值。在同一维度上,所有子控件分配相同的大小,但可以使用
GtkWidget:halign
和
GtkWidget:valign
属性影响子控件的分配。
// 创建一个水平盒子布局
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
GtkWidget *label1 = gtk_label_new("Label 1");
GtkWidget *label2 = gtk_label_new("Label 2");
gtk_box_pack_start(GTK_BOX(hbox), label1, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), label2, TRUE, TRUE, 0);
12.3 其他布局容器
- GtkAlignment :用于控制其子控件的对齐方式和大小。
- GtkAspectFrame :将其子控件约束到特定的纵横比。
- GtkHBox :水平容器盒子,是 GtkBox 的子类。
- GtkVBox :垂直容器盒子,是 GtkBox 的子类。
- GtkButtonBox :是 GtkHButtonBox 和 GtkVButtonBox 的基类。
- GtkHButtonBox :用于水平排列按钮的容器。
- GtkVButtonBox :用于垂直排列按钮的容器。
- GtkFixed :允许你在固定坐标位置放置控件的容器。
// 创建一个固定布局
GtkWidget *fixed = gtk_fixed_new();
GtkWidget *button = gtk_button_new_with_label("Fixed Button");
gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50);
- GtkPaned :具有两个可调整窗格的控件基类。
- GtkHPaned :水平排列两个窗格的容器。
- GtkVPaned :垂直排列两个窗格的容器。
- GtkLayout :包含子控件和自定义绘图的无限滚动区域。
13. GTK+ 控件关系总结
为了更清晰地呈现 GTK+ 中各控件之间的关系,下面给出一个简单的 mermaid 流程图:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(GTK+ 控件):::process --> B(显示控件):::process
A --> C(按钮和切换控件):::process
A --> D(数值/文本数据输入控件):::process
A --> E(菜单和工具栏控件):::process
A --> F(布局容器控件):::process
B --> B1(GtkLabel):::process
B --> B2(GtkSpinner):::process
B --> B3(GtkStatusbar):::process
B --> B4(GtkImage):::process
C --> C1(GtkButton):::process
C --> C2(GtkCheckButton):::process
C --> C3(GtkRadioButton):::process
D --> D1(GtkEntry):::process
D --> D2(GtkEntryBuffer):::process
D --> D3(GtkEntryCompletion):::process
E --> E1(GtkComboBox):::process
E --> E2(GtkMenu):::process
E --> E3(GtkToolbar):::process
F --> F1(GtkGrid):::process
F --> F2(GtkBox):::process
F --> F3(GtkFixed):::process
通过以上对 Cairo 库、GdkPixbuf 库、ATK 库以及 GTK+ 工具包中各种控件和布局容器的详细介绍,我们可以看到 GNOME 图形编程为开发者提供了丰富而强大的工具集。无论是创建简单的桌面应用还是复杂的图形界面,这些工具都能帮助开发者高效地完成任务。希望大家在实际开发中能够灵活运用这些知识,打造出优秀的 GNOME 应用程序。
超级会员免费看

293

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



