从 GTK 3.x 迁移到 GTK 4 [src]
GTK 4 是 GTK 的一项重大更新,与 GTK 3.x 相比,它打破了 API 和 ABI。值得庆幸的是,大多数更改并不难适应,并且你可以采取一些步骤来准备 GTK 3.x 应用程序以切换到 GTK 4。在此之后,当你实际切换应用程序以针对 GTK 4 构建时,可能需要进行一些调整。
在 GTK 3.x 中准备
以下章节中概述的步骤假定你的应用程序正在使用 GTK 3.24,这是 GTK 3.x 的最后一个稳定版本。它包含所有必要的 API 和工具,可帮助你将应用程序移植到 GTK 4。如果使用的是旧版本的 GTK 3.x,应先让应用程序构建并使用 3.24 系列中的最新次要版本。
不要使用已弃用的符号
多年来,一些函数,在某些情况下,整个小部件已被弃用。这些弃用在 API 引用页面中明确写明,并附有有关建议替换内容的提示。GTK 3 的 API 引用页面还包含一个所有已弃用符号 的索引。
若要验证程序是否使用了任何已弃用的符号,可以使用定义以从头文件移除已弃用的符号,如下所示:
make CFLAGS+="-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"
请注意,我们 API 的某些部分(例如枚举值)并未得到弃用警告的充分涵盖。在大多数情况下,使用它们将要求你也使用已弃用的函数,这将触发警告。
启用诊断警告
属性和信号的弃用无法在编译时捕获,因为属性和信号是在实例化类型之后安装和使用的。若要捕获运行时组件中的弃用和更改,应在运行应用程序时使用 G_ENABLE_DIAGNOSTIC
环境变量,例如:
G_ENABLE_DIAGNOSTIC=1 ./your-app
不要使用 GTK 特定的命令行参数
GTK 4 不再解析命令行参数。如果你正在使用诸如 --gtk-debug
之类的命令行参数,应改用 GTK_DEBUG
环境变量。如果你正在出于调试目的使用 --g-fatal-warnings
,则应使用 GLib 文档 中指定的 G_DEBUG
环境变量。
不要使用小部件样式属性
GTK 4 中不存在样式属性。你应该停止在自定义 CSS 和代码中使用它们。
检查窗口创建标记
GTK 4 移除了 GDK_WA_CURSOR
标志。相反,只需使用 gdk_window_set_cursor()
在创建窗口后设置窗口的光标即可。 GTK 4 也移除了 GDK_WA_VISUAL
标志,并且始终为窗口使用 RGBA 视觉效果。为了准备好代码,请在创建窗口后使用 gdk_window_set_visual (gdk_screen_get_rgba_visual ())
。 GTK 4 也移除了 GDK_WA_WMCLASS
标志。如果您需要此 X11 特有功能,请直接使用 XSetClassHint()
。
停止使用对 GdkEvent 结构的直接访问
在 GTK 4 中,事件结构不透明且不可变。很多字段已经具有 GTK 3 中的访问器,您可以使用这些访问器来减少在切换时需要进行的移植工作量。
停止使用 gdk_pointer_warp()
扭曲指针是一个令人迷惑和对用户不友好的操作。 GTK 4 不支持此操作。在特殊情况下(例如在实现远程连接 UI 时),必须扭曲指针,在这种情况下,请直接使用诸如 XWarpPointer()
之类的平台 API。
停止使用非-RGBA 视觉效果
GTK 4 始终为其窗口使用 RGBA 视觉效果,您应该确保您的代码能与这种视觉效果配合工作。同时,您应该停止使用 GdkVisual
API,因为此对象在 GTK 4 中不再存在。当处理 RGBA 视觉效果时,其大多数 API 已被弃用且没有用。
停止使用 gtk_widget_set_app_paintable
此操作已在 GTK4 中删除,没有直接替代。但有些用例有替代方法。如果您希望使背景透明,可以使用 CSS 来将背景色设置为例如 rgba(255, 255, 255, 0)
。
停止使用 GtkBox
填充、填满和展开子属性
GTK 4 移除了这些 GtkBox
子属性,所以您应停止使用它们。您可以使用 GtkWidget
‘s margin-*
特性来替换子部件中的 GtkBox:padding
。
填满子属性可以通过为子部件的 GtkWidget:halign
和 GtkWidget:valign
特性设置相应的值来替换。如果您之前将 fill
子属性设置为 TRUE
,您可以通过将 halign
或 valign
特性设置为 GTK_ALIGN_FILL
(根据父级框 — 水平框的 halign
、垂直框的 valign
)来达到同样的效果。
GtkBox
还使用 expand 子属性。它可以通过在子部件上设置 GtkWidget:hexpand
或 GtkWidget:vexpand
来替换。为了匹配 GtkBox
‘s expand 子属性的旧行为,您需要在水平 GtkBox
的子部件上设置 hexpand
,在垂直 GtkBox
的子部件上设置 vexpand
。
需要注意的是,GtkBox
‘s expand
和 fill
子属性以及 GtkWidget
中的子属性之间存在一个微妙但重要的区别:将 GtkWidget:hexpand
或 GtkWidget:vexpand
设置为 TRUE
将向上传播到部件层次结构,所以一个像素级的端口可能要求您在更高的母部件中将扩展标识重置为 FALSE
。
停止使用GtkStyleContext
getter 的 state 参数
在 GtkStyleContext
API 中,诸如 gtk_style_context_get_property()
、gtk_style_context_get()
或 gtk_style_context_get_color()
等 getter,只接受它们的 state 参数的当前状态。您应该更新所有调用者以传递当前状态。
停止使用 gdk_pixbuf_get_from_window()
和 gdk_cairo_set_source_window()
GTK
4 中不支持这些函数。相反,要么使用特定于后端的 API,要么在使用 GTK
4 后使用 Gtk.WidgetClass.snapshot
渲染小组件。
停止使用 GtkButton
的与图像相关的 API
与自动向 GtkButton
添加 GtkImage
,并使用 GtkSetting
控制其可见性相关的函数和属性在 GTK
4 中不受支持。相反,您可以在 GtkButton
中打包一个 GtkImage
,并像控制任何其他小组件一样控制其可见性。如果您只想要向 GtkButton
添加一个已命名的图标,可以使用 gtk_button_new_from_icon_name()
。
停止使用 GtkWidget
事件信号
事件控制器和手势在 GTK
4 中取代了事件信号。
它们中的大多数已经移植到 GTK
3.x,因此您可以为这一更改做好准备。
信号 | 事件控制器 |
---|---|
::event | GtkEventControllerLegacy |
::event-after | GtkEventControllerLegacy |
::button-press-event | GtkGestureClick |
::button-release-event | GtkGestureClick |
::touch-event | 各种触摸手势 |
::scroll-event | GtkEventControllerScroll |
::motion-notify-event | GtkEventControllerMotion |
::delete-event | - |
::key-press-event | GtkEventControllerKey |
::key-release-event | GtkEventControllerKey |
::enter-notify-event | GtkEventControllerMotion |
::leave-notify-event | GtkEventControllerMotion |
::configure-event | - |
::focus-in-event | GtkEventControllerFocus |
::focus-out-event | GtkEventControllerFocus |
::map-event | - |
::unmap-event | - |
::property-notify-event | 被 GdkClipboard 取代 |
::selection-clear-event | 被 GdkClipboard 取代 |
::selection-request-event | 被 GdkClipboard 取代 |
::selection-notify-event | 被 GdkClipboard 取代 |
拖放信号 | GtkDragSource ,GtkDropTarget |
::proximity-in-event | GtkGestureStylus |
::proximity-out-event | GtkGestureStylus |
::visibility-notify-event | - |
::window-state-event | - |
::damage-event | - |
::grab-broken-event | - |
不直接与输入相关的事件信号必须逐一处理
- 如果您使用
::configure-event
和::window-state-event
来保存窗口状态,那么您应该使用相应GtkWindow
属性的属性通知,例如GtkWindow:default-width
、GtkWindow:default-height
、GtkWindow:maximized
或GtkWindow:fullscreened
。 - 如果您使用
::delete-event
在使用窗口的关闭按钮时呈现确认,那么您应该使用GtkWindow::close-request
信号。 - 如果您使用
::map-event
和::unmap-event
来跟踪窗口映射,那么您应该使用GdkSurface:mapped
属性的属性通知。 ::damage-event
信号没有替换,因为损坏事件的唯一使用者是离屏 GDK 曲面,而 GTK 4.x 中没有替换。
设置适当的应用程序 ID
在 GTK 4 中,我们希望应用程序的 GApplication
‘application-id’(因此还有 D-Bus 名称)、桌面文件基本名称和 Wayland 的 xdg-shell app_id
能匹配。为了使用 GTK 3.x 来实现这一点,请调用 g_set_prgname()
并使用你传递给 GtkApplication
的应用程序 ID。如果需要,可以将桌面文件重命名为与应用程序 ID 相匹配。
在完全迁移到 GTK 4 中后,可以删除对 g_set_prgname()
的调用。
你应该知道,更改应用程序 ID 将使你的应用程序在应用程序安装程序中显示为一个新而不同的应用程序。你应该查阅 appstream 文档来了解重命名应用程序的最佳实践。
停止使用 gtk_main()
及相关 API
GTK 4 中移除了 gtk_main_*
家族的 API。推荐的替换项是 GtkApplication
,但你也可以直接使用 GMainContext
API 来迭代 GLib 主循环。gtk_events_pending()
的替换项是 g_main_context_pending()
,gtk_main_iteration()
的替换项是 g_main_context_iteration()
。
在 GTK 4 中,你可以使用此替换项来迭代默认主循环,直到所有窗口关闭
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
g_main_context_iteration (NULL, TRUE);
减少使用 gtk_widget_destroy()
GTK 4 中引入了 gtk_window_destroy()
API。尽管该 API 在 GTK 3 中不可用,但你可以通过只对顶级窗口使用 gtk_widget_destroy()
并使用 gtk_container_remove()
或 g_object_unref()
替换所有其他用法来为该转换做好准备。
停止使用 GtkWidget.destroy vfunc
你可以实现 GObject.dispose,而不是实现 GtkWidget.destroy。
减少使用通用容器 API
GTK 4 中移除了 gtk_container_add()
和 gtk_container_remove()
。尽管在 GTK 3 中并不总是 gtk_container_remove()
的替换项,但你可以使用同类容器特定 API(例如 gtk_grid_attach()
)来替换许多 gtk_container_add()
的用法,并从而减少在转换时需要做的工作量。
检查对图标资源的使用
当将图标用作资源时,GTK 4 的行为在一点上不同于该技术的早前版本:在 $APP_ID/icons/
中的图标直接视为未设置主题的图标,这意味着符号图标也不会改变其颜色。如果你希望自己的图标资源具有图标主题语义,那么就需要将它们放在主题子目录(例如 $APP_ID/icons/16x16/actions
或 $APP_ID/icons/scalable/status
)中。
上述位置也可以在 GTK 3 中正常工作,因此你可以在转换到 GTK 4 之前为该更改做好准备。
在转换时需要做的更改
本节概述了在将自己的应用程序实际针对 GTK 4 构建时需要解决的移植任务。要在 GTK 3 中为这些任务做好准备,目前看来是不可能的,也不切实际。
较大的更改
GTK 4 开发的一些较大的主题难以通过清单项目的形式进行涵盖,因此,我们会提前分别提到这些主题。
子类化
与之前的版本相比,GTK 4 更强调构图和委托而不是子类化。结果是,许多窗口小部件不能再进行子类化。在大多数情况下,您应该直接从 GtkWidget 派生窗口小部件,并使用复杂窗口小部件作为子窗口小部件,而不是派生 它们。
生命周期管理
GTK 4 中的窗口小部件与任何其他对象一样,其父窗口小部件对其持有引用,GTK 对顶级窗口持有引用。 gtk_window_destroy()
将丢弃对顶级窗口的引用,并导致整个窗口小部件层次结构最终确定,除非有其他引用保持窗口小部件 活动。
小部件被释放时会发出 GtkWidget::destroy
信号,因此不能再用于打破引用循环。涉及顶级窗口的引用循环的一个典型迹象是关闭窗口时不会使应用程序 退出。
停止使用 GdkScreen
GdkScreen
对象已在 GTK 4 中移除。它的大多数 API 已在 GTK 3 中得到替换并且已弃用,少数剩余替换已添加到 GdkDisplay
中。
停止使用根窗口
根窗口是一个以 X11 为中心的理念,不在后端中立的 GDK API 中公开。如果您需要与 X11 根窗口交互,可以使用 GdkX11.Display.get_xrootwindow 来获取其 XID。
停止使用 GdkVisual
此对象对当前 GTK 绘图 API 无用,并且已在无 替换的情况下移除。
停止使用 GdkDeviceManager
GdkDeviceManager
对象已在 GTK 4 中移除。它的大多数 API 已在 GTK 3 中得到替换并弃用,转而使用 GdkSeat
。
适应 GdkWindow
API 更改
GdkWindow
已重命名为 GdkSurface
。
在 GTK 4 中,独立顶级窗口和相对于父窗口放置的弹出窗口的两种角色已分离为两个接口,即 GdkToplevel
和 GdkPopup
。分别使用 gdk_surface_new_toplevel()
和 gdk_surface_new_popup()
创建实现这些接口的曲面,并使用 gdk_toplevel_present()
和 gdk_popup_present()
在屏幕上显示它们。 present()
函数以辅助布局结构体的形式接收参数,即 GdkPopupLayout
或 GdkToplevelLayout
。
如果您的代码直接处理曲面,您可能需要对其进行更改,以便在这些接口中调用 API,具体取决于您处理的曲面是顶级曲面还是 弹出曲面。
作为此重组的一部分,仅限 X11 的理念(例如 sticky、keep-below、urgency、skip-taskbar 或窗口组)已被移除或移至 X11 后端 api。如果您需要在 X11 窗口中使用它们,您将不得不使用那些后端 api 或自行设置相应的 X11 属性(如 EWMH 中所指定) 。
子表面目前不受支持。原生窗口和外部子窗口也不再受支持。这些概念会复杂化代码,并且无法跨后端提供支持。
不再提供大量 GdkWindow API。这包括 gdk_window_reparent()
、gdk_window_set_geometry_hints()
、gdk_window_raise()
、gdk_window_restack()
、gdk_window_move()
、gdk_window_resize()
。如果您需要手动控制 X11 窗口的位置或堆栈顺序,则必须使用 Xlib API。
在 GdkSurface
中还进行了一些无关紧要的 API 清理。例如,gdk_surface_input_shape_combine_region()
已重命名为 gdk_surface_set_input_region()
,并且 gdk_surface_begin_resize_drag()
已重命名为 gdk_toplevel_begin_resize()
。
"最小化"窗口状态已重命名为"缩小"
`GdkSurfaceState
枚举的 GDK_TOPLEVEL_STATE_ICONIFIED
值现在是 GdkToplevelState
枚举中的 GDK_TOPLEVEL_STATE_MINIMIZED
。
`GdkWindow
函数 gdk_window_iconify()
和 gdk_window_deiconify()
已分别重命名为 gdk_toplevel_minimize()
和 gdk_toplevel_present()
。
缩小和取消缩小操作的行为没有改变,它们仍然需要基础窗口化系统的支持。
适应 GdkEvent
API 更改
在 GTK 4 中,无法直接访问 GdkEvent
结构。GdkEvent
现在是严格的只读类型,您无法再更改它的任何字段,或构造新事件。所有事件字段都有您必须使用的访问器。
在 GTK 4 中,事件压缩始终处于启用状态,适用于动作和滚动事件。如果您需要查看未合并的动作或滚动记录,请对最新事件使用 gdk_event_get_history()
。
停止使用抓取
GTK 4 不再提供 gdk_device_grab()
或 gdk_seat_grab()
API。如果您需要在用户单击外部(抓取的最常见用法)时关闭弹出窗口,则可以使用 GdkPopup
GdkPopup:autohide
属性。 GtkPopover
也有 GtkPopover:autohide
属性。如果您需要在对话框打开时阻止用户与窗口进行交互,请使用 GtkWindow:modal
属性对话框。
适应坐标 API 更改
GTK 3 中的许多坐标 API 都有 varients,这些 varients 使用 int
参数:gdk_device_get_surface_at_position()
、gdk_surface_get_device_position()
。它们已更改为使用 double
参数,并且已移除 int
varients。相应地更新您的代码。
GTK 4 中已移除所有处理全局(或根)坐标的 API,因为并非所有后端都支持它们。您应使用与表面相对的等效项来替换对这些 API 的使用。此类已移除的 API 的示例包括 gdk_window_get_origin()
、gdk_window_move()
或 gdk_event_get_root_coords()
。
适应 GdkKeymap
GdkKeymap
不再作为一个独立对象存在。
如果您需要访问击键状态,它现在作为代表键盘的 GdkDevice
上的属性公开:GdkDevice:direction
、GdkDevice:has-bidi-layouts
、GdkDevice:caps-lock-state
、GdkDevice:num-lock-state
、GdkDevice:scroll-lock-state
和 GdkDevice:modifier-state
。要获取键盘设备,可以使用
gdk_seat_get_keyboard (gdk_display_get_default_seat (display)
如果您需要访问用于事件处理的已转换键,GdkEvent
现在包括所有已转换的键状态,包括消耗的修饰键、组以及移动级别,因此无需手动调用 gdk_keymap_translate_keyboard_state()
(该函数已删除)。
如果您需要在键码和键值之间进行正向或反向映射,请使用 gdk_display_map_keycode()
和 gdk_display_map_keyval()
,它们是 gdk_keymap_get_entries_for_keycode()
和 gdk_keymap_get_entries_for_keyval()
的替换函数。
适应键盘修饰键处理的变化
GTK 3 认为修饰键的使用因平台而异,并有一个 GdkModifierIntent
API 以便让平台提供有关修饰键预期使用方式的提示。它还推广了使用 <Primary>
代替 <Control>
以指定适应平台约定的加速键。
在 GTK 4 中,已确定修饰键的含义,并希望应用程序将平台约定映射到现有修饰键。在 GTK 4 中预期修饰键的使用方式为
GDK_CONTROL_MASK
(macOS 上的GDK_META_MASK
)- 主加速键
GDK_ALT_MASK
- 助记键
GDK_SHIFT_MASK
- 扩展选择
GDK_CONTROL_MASK
(macOS 上的GDK_META_MASK
)- 修改选择
GDK_CONTROL_MASK|GDK_ALT_MASK
- 禁止文本输入
因此,已删除 GdkModifierIntent
以及相关的 API,且在加速键中首选 <Control>
而非 <Primary>
。
在 macOS 上的 GTK 3 中,<Primary>
修饰键映射到 Command 键。在 GTK 4 中,情况不再如此:<Primary>
同义于 <Control>
。如果您想让您的应用程序在 macOS 上感觉像原生应用,您需要添加使用 <Meta>
修饰键的 macOS 的加速键。
一个相关的更改是 GTK 4 不再支持使用带有名称 Mod1、…、Mod5 的陈旧 X11 ‘real’ 修饰键,且 GDK_MOD1_MASK
已重命名为 GDK_ALT_MASK
,以及 GDK_MOD2_MASK
已重命名为 GDK_META_MASK
。
使用 GdkClipboard
替换 GtkClipboard
GtkClipboard
API 已删除,并由 GdkClipboard
取代。旧 API 和新 API 之间不存在直接的一一映射,因此它无法成为一个机械的替换;新的 API 基于对象类型和 GValue
例如对象属性,而不是不透明标识符,因此应该更容易使用。
例如,下面的示例将条目的内容复制到剪贴板
static void
copy_text (GtkWidget *widget)
{
GtkEditable *editable = GTK_EDITABLE (widget);
// Initialize a GValue with the contents of the widget
GValue value = G_VALUE_INIT;
g_value_init (&value, G_TYPE_STRING);
g_value_set_string (&value, gtk_editable_get_text (editable));
// Store the value in the clipboard object
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
gdk_clipboard_set_value (clipboard, &value);
g_value_unset (&value);
}
而下面的示例将内容粘贴到条目中
static void
paste_text (GtkWidget *widget)
{
GtkEditable *editable = GTK_EDITABLE (widget);
// Initialize a GValue to receive text
GValue value = G_VALUE_INIT;
g_value_init (&value, G_TYPE_STRING);
// Get the content provider for the clipboard, and ask it for text
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
GdkContentProvider *provider = gdk_clipboard_get_content (clipboard);
// If the content provider does not contain text, we are not interested
if (!gdk_content_provider_get_value (provider, &value, NULL))
return;
const char *str = g_value_get_string (&value);
gtk_editable_set_text (editable, str);
g_value_unset (&value);
}
GtkClipboard
中的特定目标类型的便捷 API 已被其对应的 GType 替换
GtkClipboard | GType |
---|---|
gtk_clipboard_request_text() |
G_TYPE_STRING |
gtk_clipboard_request_rich_text() |
GTK_TYPE_TEXT_BUFFER |
gtk_clipboard_request_image() |
GDK_TYPE_PIXBUF |
gtk_clipboard_request_uris() |
GDK_TYPE_FILE_LIST |
注意:GtkTextBuffer
在不同进程中进行 Rich 文本序列化的支持已不再可用。
如果您正在复制图像的内容,建议使用 GDK_TYPE_PAINTABLE
而不是 GDK_TYPE_PIXBUF
,以最大程度地减少潜在的复制次数。
停止使用 gtk_get_current_...
API
函数 gtk_get_current_event()
及其变量已被等效的事件控制器 API 替换:gtk_event_controller_get_current_event()
等。
转换您的 UI 文件
下面概述的许多更改都会影响 .ui
文件。当使用 --3to4
选项调用时,gtk4-builder-tool simplify
命令可以自动执行许多必要的更改。您应该始终查看所产生的更改。
现在,<requires>
标记仅支持 lib
属性的 gtk
值,而不是之前的 gtk+
值。
适应 GtkBuilder API 更改
gtk_builder_connect_signals()
已不复存在。现在,信号始终自动连接。如果您需要向信号中添加用户数据,则必须调用 gtk_builder_set_current_object()
。一个重要的注意事项是,您必须在加载任何 XML 之前执行此操作。这意味着如果您需要使用 gtk_builder_set_current_object()
,则您不能再使用 gtk_builder_new_from_file()
、gtk_builder_new_from_resource()
或 gtk_builder_new_from_string()
。相反,您必须使用香草 gtk_builder_new()
,然后调用 gtk_builder_set_current_object()
,然后使用 gtk_builder_add_from_file()
、gtk_builder_add_from_resource()
或 gtk_builder_add_from_string()
加载 XML。您必须检查返回值是否失败,如果出现问题,则必须使用 g_error()
手动中止。
只有在之前使用 gtk_builder_connect_signals()
时才需要担心此问题。如果您使用模板,则 gtk_widget_init_template()
将为您调用 gtk_builder_set_current_object()
,因此模板的工作方式与之前相同。
适应事件控制器 API 更改
对事件控制器和 GtkGesture
API 的一些更改没有返回 GTK 3,并且在迁移到 GTK 4 时必须予以考虑。其中一个更改是 GtkEventControllerMotion::enter
和 GtkEventControllerMotion::leave
信号已增加新参数。另一个更改是 GtkGestureMultiPress
已重命名为 GtkGestureClick
,并且丢失了其区域属性。现已将 GtkEventControllerFocus
从 GtkEventControllerKey
中拆分出来。
在 GTK 3 中,GtkEventController:widget
是一个仅用于构造的属性,因此在构造 GtkEventController
时会提供一个 GtkWidget
。在 GTK 4 中,GtkEventController:widget
现在是只读的。使用 gtk_widget_add_controller()
将事件控制器添加到小部件中。
在 GTK 3 中,小组件不会拥有其事件控制器,事件控制器不会拥有其小组件,因此开发者负责手动保持事件控制器在其关联小组件的生命周期内处于活动状态。在 GTK 4 中,小组件会拥有其事件控制器。gtk_widget_add_controller()
会接管事件控制器的所有权,因此在将事件控制器添加至小组件后,不再需要存储事件控制器的引用。
虽然通常不需要,但可以在 GTK 3 中通过使用 g_object_unref()
销毁事件控制器来从一个小组件中移除事件控制器。在 GTK 4 中,您必须使用 gtk_widget_remove_controller()
。
焦点处理更改
GtkWidget:can-focus
属性的语义已更改。在 GTK 3 中,此属性仅表示小组件本身不接受键盘输入,但其子组件可能仍会接受(在容器的情况下)。在 GTK 4 中,如果 :can-focus
为 FALSE
,则焦点不能进入小组件或其任何后代,并且默认值已从 FALSE
更改为 TRUE
。此外,还有一个GtkWidget:focusable
属性,它控制单个小组件是否可以接收输入焦点。
gtk4-builder-tool
实用程序,在使用 simplify
命令的 --3to4
选项调用时,将用 :focusable
替换 :can-focus
。
使用 gtk_container_set_focus_vadjustment()
自动将焦点小组件滚动至视图中的功能已与 GtkContainer
一起移除,取而代之的是由可滚动小组件提供。在可滚动对象是 GtkViewport
的常见情况下,请使用 GtkViewport:scroll-to-focus
。
使用用于键盘快捷键的新 API
键盘快捷键和加速器的 API 已在 GTK 4 中更改。
现在用具有全局范围的 GtkShortcutController
代替 GtkAccelGroup
,用 gtk_widget_class_add_shortcut()
、gtk_widget_class_add_binding()
及其变体代替 GtkBindingSet
。在这两种情况下,您可能希望添加可以由快捷键触发操作。
没有直接替代项可以用来使用 GtkAccelMap
加载和保存加速器。但是,由于 GtkShortcutController
实现 GListModel
并且 GtkShortcutTrigger
和 GtkShortcutAction
两个都可以序列化到字符串,因此实现自己保存和加载相对容易。
停止使用 GtkEventBox
GtkEventBox
不再需要,并且已 被移除。
所有小组件都会收到所有 事件。
停止使用 GtkButtonBox
已移除 GtkButtonBox
。改用 GtkBox
。
适应 GtkBox
API 更改
GtkBox pack_start()
和 pack_end()
方法已由 gtk_box_prepend()
和 gtk_box_append()
代替。您还可以根据需要重新排序盒子子项。
适应 GtkWindow
API 更改
在对 GdkSurface
做出更改后,一些特定于 X11 的 GtkWindow
API 已被移除。其中包括 gtk_window_set_position()
、gtk_window_set_geometry_hints()
、gtk_window_set_gravity()
、gtk_window_move()
、gtk_window_parse_geometry()
、gtk_window_set_keep_above()
、gtk_window_set_keep_below()
、gtk_window_begin_resize_drag()
、gtk_window_begin_move_drag()
。很可能,您应该停止使用它们。在某些情况下,您可以退回到使用底层的 GdkToplevel
API(例如,gdk_toplevel_begin_resize()
);或者,您需要从 GtkWindow
获取原生窗口系统界面并调用特定于平台的 API。
GtkWindow
大小控制 API 已经过更改,以便更好地与在帧循环中集成的大小更改方式保持一致。gtk_window_resize()
和 gtk_window_get_size()
已被移除。相反,请使用 gtk_window_set_default_size()
和 gtk_window_get_default_size()
。
调整以符合 GtkHeaderBar
和 GtkActionBar
API 更改
gtk_header_bar_set_show_close_button()
函数已重命名为更准确的名字 gtk_header_bar_set_show_title_buttons()
。相应的 getter 和属性本身也已重命名。现在属性的默认值为 TRUE
,而非 FALSE
。
gtk_header_bar_set_custom_title()
函数已重命名为更准确的名字 gtk_header_bar_set_title_widget()
。相应的 getter 和属性本身也已重命名。
gtk_header_bar_set_title()
函数已连同其对应的 getter 和属性一起移除。默认情况下,GtkHeaderBar
会显示窗口标题,因此如果您要设置标题栏的标题,请考虑改而设置窗口标题。如果您需要显示不同于窗口标题的标题,请使用 GtkHeaderBar:title-widget
属性来添加一个 GtkLabel
,如 GtkHeaderBar
文档中的示例所示。
gtk_header_bar_set_subtitle()
函数已连同其对应的 getter 和属性一起移除。通过将 GtkHeaderBar:title-widget
属性设置为包含两个标签的 GtkBox
,可以复制旧的“subtitle”行为,其中标题标签与 GtkHeaderBar
文档中的示例匹配,而子标题标签类似,但样式类为 "subtitle"
,而非 "title"
。
gtk_header_bar_set_has_subtitle()
函数已连同其对应的 getter 和属性一起移除。通过将 GtkHeaderBar:title-widget
属性设置为包含两个页面的 GtkStack
,可以复制其行为,将 GtkStack:vhomogeneous
属性设置为 TRUE
,其中每个页面包含一个 GtkBox
,带有如上所述的标题和子标题。
GtkHeaderBar
的一些内部结构已被作为公共 API 提供:GtkWindowHandle
和 GtkWindowControls
。如果您对自定义标题栏有特殊需要,这些可能对您有用。
:pack-type
子属性的 GtkHeaderBar
和 GtkActionBar
已被移除。如果您需要以编程方式放置子节点,请使用 gtk_header_bar_pack_start()
和 gtk_header_bar_pack_end()
方法。在 UI 文件中,在 child
元素上使用 type
属性。
gtk4-builder-tool
实用工具可以帮助进行此转换,即 simplify
命令的 --3to4
选项。
适应 GtkStack
、GtkAssistant
和 GtkNotebook
的 API 更改
GtkStack
、GtkAssistant
和 GtkNotebook
的子属性已转换为子元对象。
现在可以使用 g_object_set (gtk_stack_get_page (stack, child), …)
代替 gtk_container_child_set (stack, child, …)
。在 .ui 文件中,必须显式创建 GtkStackPage
对象,并将子部件作为属性。对 GtkNotebook
和 GtkAssistant
的更改类似。
gtk4-builder-tool
可以帮助进行此转换,即 simplify
命令的 --3to4
选项。
适应按钮类层次结构更改
GtkCheckButton
不再派生自 GtkToggleButton
。使用 gtk_check_button_set_active()
代替 gtk_toggle_button_set_active()
。
GtkRadioButton
已被移除,其分组功能已添加到 GtkCheckButton
和 GtkToggleButton
。对传统单选组使用分组复选框,对检视切换器使用分组切换按钮。用于设置按钮组的新 API 是 gtk_check_button_set_group()
和 gtk_toggle_button_set_group()
。
gtk4-builder-tool
可以帮助进行此转换,即 simplify
命令的 --3to4
选项。
适应 GtkScrolledWindow
的 API 更改
GtkScrolledWindow
的构造函数不再将调整作为参数,这些调整几乎总是 NULL
。
适应 GtkBin
的移除
用于单子项容器的抽象基类 GtkBin
已被移除。之前的子类现在直接派生自 GtkWidget
,并且为其子部件具有“子项”属性。要添加子项,请使用“子项”属性的设置程序(例如 gtk_frame_set_child()
)代替 gtk_container_add()
。通过 <child>
在 ui 文件中添加子项仍然有效。
受影响的类:
GtkAspectFrame
GtkButton
(和子类)GtkComboBox
GtkFlowBoxChild
GtkFrame
GtkListBoxRow
GtkOverlay
GtkPopover
GtkRevealer
GtkScrolledWindow
GtkSearchBar
GtkViewport
GtkWindow
(和子类)
如果您具有派生自 GtkBin
的自定义部件,则应将其移植为派生自 GtkWidget
。您必须实现的重要虚函数包括 GObject
dispose 虚函数(以取消子项的父项关联)、Gtk.WidgetClass.compute_expand
(如果您希望您的容器传播展开标志)和 Gtk.WidgetClass.get_request_mode
(如果您希望您的容器支持针对宽度的高度)。
您可能还需要实现 GtkBuildable
接口,以支持通过 ui 文件中的 <child>
添加子项。
适应 GtkContainer
的移除
用于基础容器的抽象基类 GtkContainer
已被移除。之前的子类现在直接派生自 GtkWidget
,并且具有特定于类的 add()
和 remove()
函数。
最显眼的改动是使用 gtk_box_append()
或 gtk_box_prepend()
而非 gtk_container_add()
向 GtkBox
中添加子元素,以及使用特定容器的移除函数(例如:gtk_stack_remove()
而非 gtk_container_remove()
)。在 ui 文件中使用 <child>
添加子元素仍然有效。
受影响的类:
GtkActionBar
GtkBox
(及其子类)GtkExpander
GtkFixed
GtkFlowBox
GtkGrid
GtkHeaderBar
GtkIconView
GtkInfoBar
GtkListBox
GtkNotebook
GtkPaned
GtkStack
GtkTextView
GtkTreeView
没有了 GtkContainer
,无法再定义和使用子属性。如果你有使用子属性的自定义窗口小部件,则必须将其转换成布局管理器提供的布局属性(如果是与布局相关的属性)或以其他方式对其进行处理。一种可能性是使用子元对象,如 GtkAssistantPage
、GtkStackPage
等。
如果你曾经在 ui 文件中使用 <packing>
来定义子属性,则必须切换到 <layout>
来使用相应的布局属性。gtk4-builder-tool
可以通过 simplify
命令的 --3to4
选项来帮助执行此转换。
替换 gtk_container_add()
的方法:
窗口小部件 | 替换 |
---|---|
GtkActionBar |
gtk_action_bar_pack_start() 、 |
GtkBox |
gtk_box_prepend() 、gtk_box_append() |
GtkExpander |
gtk_expander_set_child() |
GtkFixed |
gtk_fixed_put() |
GtkFlowBox |
gtk_flow_box_insert() |
GtkGrid |
gtk_grid_attach() |
GtkHeaderBar |
gtk_header_bar_pack_start() 、gtk_header_bar_pack_end() |
GtkIconView |
- |
GtkInfoBar |
gtk_info_bar_add_child() |
GtkListBox |
gtk_list_box_insert() |
GtkNotebook |
gtk_notebook_append_page() |
GtkPaned |
gtk_paned_set_start_child() 、gtk_paned_set_end_child() |
GtkStack |
gtk_stack_add_child() |
GtkTextView |
gtk_text_view_add_child_at_anchor() 、gtk_text_view_add_overlay() |
GtkTreeView |
- |
停止使用 GtkContainer::border-width
GTK 4 已经移除了 GtkContainer::border-width
属性(以及 GtkContainer
的其他部分)。使用其他方式影响容器间距,例如子窗口小部件上的 CSS 外边距和内边距属性,或者容器上的 CSS border-spacing 属性。
适应 gtk_widget_destroy()
移 除
gtk_widget_destroy()
函数已经被移除。要明确销毁一个顶级窗口,使用 gtk_window_destroy()
。要销毁包含在层次结构中的窗口小部件,使用特定容器的 remove API(例如:gtk_box_remove()
或 gtk_stack_remove()
)将其从父元素中移除。要销毁一个独立的非顶级窗口小部件,使用 g_object_unref()
放弃引用。
适应坐标相关的 API 更改
许多接受或返回坐标的 API 已经从 int
更改为 double
:gtk_widget_translate_coordinates()
、gtk_fixed_put()
、gtk_fixed_move()
。此更改大部分都是透明的,但涉及到输出参数的情况除外:现在你需要传递 double*
,而非 int*
。
适应 GtkStyleContext API 更改
GtkStyleContext API 中的 getter 如 gtk_style_context_get_color()
、gtk_style_context_get_border()
或 gtk_style_context_get_margin()
已不再包含状态参数,始终使用上下文的当前状态。更新所有调用方以省略状态参数。
最常使用的 GtkStyleContext API gtk_style_context_add_class()
已移至 GtkWidget 作为 gtk_widget_add_css_class()
,对应的 gtk_style_context_remove_class()
和 gtk_style_context_has_class()
API 也已移至 GtkWidget。
适应 GtkCssProvider API 更改
在 GTK 4 中,各种 GtkCssProvider
加载函数已不再包含 GError
参数。如果您要处理 CSS 加载错误,请改用 GtkCssProvider::parsing-error
信号。gtk_css_provider_get_named()
已被 gtk_css_provider_load_named()
替换。
停止使用 GtkShadowType 和 GtkRelief 属性
GtkScrolledWindow
、GtkViewport
和 GtkFrame
中的 shadow-type 属性,以及 GtkButton
及其子类中的 relief 属性已移除。GtkScrolledWindow
、GtkButton
和 GtkMenuButton
现已获得布尔 has-frame 属性。
适应 GtkWidget 的大小请求更改
GTK 3 在 GtkWidget 中使用五个不同的虚拟函数来实现大小请求,即 gtk_widget_get_preferred_width()
函数系列。为了简化小组件实现,GTK 4 只使用一个小组件必须实现的虚拟函数 Gtk.WidgetClass.measure
。gtk_widget_measure()
替换各种 gtk_widget_get_preferred_
函数以查询大小。
适应 GtkWidget 的大小分配更改
Gtk.WidgetClass.size_allocate
vfunc 现在将基线作为参数,因此您不再需要调用 gtk_widget_get_allocated_baseline()
来获取它。
已移除 ::size-allocate 信号,因为它容易被误用。如果您需要了解自定义绘制小组件的大小更改,请使用 GtkDrawingArea::resize
或 GtkGLArea::resize
信号。如果您想跟踪顶级窗口的大小,请使用 GtkWindow:default-width
和 GtkWindow:default-height
的属性通知。
切换为 GtkWidget 的子组件 API
在 GTK 4 中,任何小组件都可以有子组件(且 GtkContainer
已不复存在)。有新的 API 可用于在小组件实现中导航小组件树:gtk_widget_get_first_child()
、gtk_widget_get_last_child()
、gtk_widget_get_next_sibling()
、gtk_widget_get_prev_sibling()
。
在您的 CSS 中不要使用 -gtk-gradient
GTK 现在支持线性和径向渐变的标准 CSS 语法,请用它们。
在您的 CSS 中不要使用 -gtk-icon-effect
GTK 现在支持更多功能的 -gtk-icon-filter。
替换
旧 | 替换 |
---|---|
-gtk-icon-effect: dim | -gtk-icon-filter: opacity(0.5) |
-gtk-icon-effect: highlight | -gtk-icon-filter: brightness(1.2) |
在您的 CSS 中不要使用 -gtk-icon-theme
GTK 4 始终使用当前的图标主题,而无法更改此设置。
在您的 CSS 中不要使用 -gtk-outline-...-radius
这些非标准属性已从 GTK CSS 中移除。请仅使用常规边框半径。
适应绘图模型的更改
此区域在从 GTK 3 过渡到 GTK 4 时发生了最激烈的变化。小部件不再使用 draw()
函数将其内容渲染到 cairo 曲面。相反,它们有一个 Gtk.WidgetClass.snapshot
函数,它创建一个或多个 GskRenderNodes 来表示其内容。使用 draw()
函数或 GtkWidget::draw
信号处理程序进行自定义绘制的第三方小部件需要转换为使用 gtk_snapshot_append_cairo()
。
辅助 GtkSnapshot
对象具有有助于创建渲染节点的 API。
如果您正在使用 GtkDrawingArea
进行自定义绘制,那么您需要切换为使用 gtk_drawing_area_set_draw_func()
来设置绘制函数,而不是将处理程序连接到 GtkWidget::draw
信号。
停止使用用于查询 GdkSurfaces 的 API
由于这些窗口不再存在,因此已经移除了一些用于查询专用窗口的 API:gtk_tree_view_get_bin_window()
、gtk_viewport_get_bin_window()
、gtk_viewport_get_view_window()
。
小部件现在默认为可见
GTK 4 中 GtkWidget:visible
的默认值为 TRUE
,因此您不再需要显式显示所有小部件。另一方面,您需要隐藏本来就不打算从开始就可见的小部件。仍然需要显式显示的仅有顶层窗口、对话框和弹出按钮。
从 UI 文件中移除这种不必要的属性分配的一个便捷方法是在它们上运行 gtk4-builder-tool simplify --replace
命令。
函数 gtk_widget_show_all()
、GtkWidget:no-show-all
属性及其 getter 和 setter 已在 GTK 4 中移除,因此您应该停止使用它们。
适应小部件动画隐藏和显示的更改
借助动画显示和消失的小部件(例如 GtkInfoBar
、GtkRevealer
)现在不再为此使用 gtk_widget_show()
和 gtk_widget_hide()
,而是为此获得了专用的 API,您应该使用这些 API,例如 gtk_info_bar_set_revealed()
。
停止将命令行参数传递给 gtk_init
gtk_init()
和 gtk_init_check()
函数不再接受命令行参数。只需在不带参数的情况下调用它们即可。与命令行参数处理纯相关而的其他初始化函数(例如 gtk_parse_args()
和 gtk_get_option_group()
)已消失。
单独初始化 GDK 的 API 也不见了,但你受到它的影响的可能性非常小。
GdkPixbuf 被淡化
大量基于 GdkPixbuf
的 API 已被移除。可用的替换要么使用 GIcon
,要么使用新引入的 GdkTexture
或 GdkPaintable
类。如果你正在处理像素缓冲区,你可以使用 gdk_texture_new_for_pixbuf()
将它们转换为纹理对象(在需要的时候)。
GtkWidget 事件信号被移除
事件控制器和 GtkGestures 已在 GTK 3 中引入以处理多种情况的输入。在 GTK 4 中,用于处理输入的传统窗口小部件信号(如 GtkWidget::motion-event
或 GtkWidget::event
)已被移除。现在,所有事件处理都通过事件控制器来完成。
失效处理已更改
只有 gtk_widget_queue_draw()
用于将小部件标记为需要重新绘制。gtk_widget_queue_draw_rectangle()
或 gtk_widget_queue_draw_region()
等变体不再可用。
停止使用 GtkWidget::draw
GtkWidget::draw
信号已移除。小部件现在需要实现 Gtk.WidgetClass.snapshot
函数。不再能够连接绘制信号处理程序。如果你想继续使用 cairo 来绘制,请使用 gtk_snapshot_append_cairo()
。
窗口内容观察已更改
现在通过使用 GtkWidgetPaintable
对象来观察小部件内容和小部件大小,而不是连接到小部件信号。
监视器处理已更改
现在始终使用 GdkMonitor
而不是监视器编号。gdk_display_get_monitors()
返回可查询或观察的监视器列表,以便将监视器传递给 gtk_window_fullscreen_on_monitor()
等 API。
适应监视器 API 更改
gdk_monitor_get_workarea()
API 已消失。单个后端仍然可以提供此信息,例如使用 GdkX11.Monitor.get_workarea。
如果你使用此信息,你的代码应检查正在使用哪个后端,然后调用适当的后端 API。
适应光标 API 更改
使用新的 gtk_widget_set_cursor()
函数来设置光标,而不是直接在底层窗口上设置光标。这是必需的,因为大多数小部件不再有自己的窗口,从而将任何此类调用变成全局光标更改。
在创建标准光标时,gdk_cursor_new_for_display()
已被移除,您必须使用光标名称而不是 GdkCursorType
。在创建自定义光标时,使用 gdk_cursor_new_from_texture()
。获取光标图像的能力已 移除。
适应图标大小 API 更改
而不是现有可扩展的符号图标大小集,GTK 现在仅支持 GtkIconSize
枚举中的普通和大型图标。实际大小可以通过 CSS 属性 -gtk-icon-size 由主题定义。
如 gtk_image_set_from_icon_name()
的 GtkImage 设置程序不再获取 GtkIconSize
参数。如果您需要覆盖图标大小,可以使用单独的 gtk_image_set_icon_size()
设置程序。
GtkCellRendererPixbuf 的 :stock-size 属性已重命名为 GtkCellRendererPixbuf:icon-size
。
适应 GtkAssistant API 的更改
已删除 :has-padding 属性,并且 GtkAssistant
不再向页面添加填充。您可以轻松地 自己添加。
适应 GtkEntry、GtkSearchEntry 和 GtkSpinButton API 的更改
GtkEditable
接口已变得更加有用,并且 GtkEntry
的核心功能已被分解为 GtkText
小组件。现在,GtkEntry
、GtkSearchEntry
、GtkSpinButton
和新的 GtkPasswordEntry
在内部使用 GtkText
小组件并实现 GtkEditable
。尤其是,这意味着不再可以在搜索条目上使用诸如 gtk_entry_grab_focus_without_selecting()
之类的 GtkEntry
API。
针对可编辑功能使用 GtkEditable
API,针对超出公共接口的特定内容使用特定于小组件的 API。对于密码条目,请使用 GtkPasswordEntry
。例如,gtk_spin_button_set_max_width_chars()
已被赞成使用 gtk_editable_set_max_width_chars()
。
适应 GtkOverlay API 的更改
GtkOverlay :pass-through 子属性已由 GtkWidget:can-target
属性替换。请注意,它们具有相反的含义:pass-through == !can-target。
使用 GtkFixed,而不是 GtkLayout
由于 GtkScrolledWindow
可以处理未实现 GtkScrollable
接口的小组件,通过自动将它们包装到 GtkViewport
中,GtkLayout
是多余的,并且已被现有 GtkFixed
小组件取代。
适应搜索条目更改
搜索条目连接到全局事件的方式已更改;gtk_search_entry_handle_event()
已被放弃,并由 gtk_search_entry_set_key_capture_widget()
和 gtk_event_controller_key_forward()
替换。
适应 GtkScale 更改
GtkScale:draw-value
的默认值已更改为 FALSE
。如果您希望您的刻度绘制值,您现在将不得不显式设置此属性。
gtk4-builder-tool
可以帮助进行此转换,即 simplify
命令的 --3to4
选项。
停止使用 gtk_window_activate_default()
默认小部件的处理方式已更改,现在可以通过在导致激活的小部件上调用 gtk_widget_activate_default()
来激活默认。如果您有一个自定义小部件想要覆盖默认处理,可以在小部件的操作组中提供“default.activate”操作的实现。
停止使用 gtk_widget_grab_default()
函数 gtk_widget_grab_default()
已被删除。如果您需要将一个小部件标记为默认,请直接使用 gtk_window_set_default_widget()
。
停止在 .ui 文件中设置 ::has-default 和 ::has-focus
对 :has-default 和 :has-focus 属性的特殊处理已删除。如果您想在 .ui 文件中定义初始焦点或默认小部件,请设置顶级窗口的 GtkWindow:default-widget
或 GtkWindow:focus-widget
属性。
停止使用 GtkWidget::display-changed 信号
要跟踪当前显示屏,请改用 GtkWidget:root
属性。
GtkPopover::modal 已重命名为 autohide
modal 属性已重命名为 GtkPopover:autohide
。
gtk-builder-tool
可以帮助在 ui 文件中重命名。
gtk_widget_get_surface 已被删除
gtk_widget_get_surface()
已被删除。改用 gtk_native_get_surface()
和 gtk_widget_get_native()
。
gtk_widget_is_toplevel 已被删除
gtk_widget_is_toplevel()
已被删除。改用 GTK_IS_ROOT
、GTK_IS_NATIVE
或 GTK_IS_WINDOW
,具体取决于需要。
gtk_widget_get_toplevel 已被删除
gtk_widget_get_toplevel()
已被删除。改用 gtk_widget_get_root()
或 gtk_widget_get_native()
,具体取决于需要。
GtkEntryBuffer ::deleted-text 已更改
为了允许信号处理程序在已删除之前访问已删除的文本,GtkEntryBuffer::deleted-text
信号已从 G_SIGNAL_RUN_FIRST
更改为 G_SIGNAL_RUN_LAST
。默认处理程序会从 GtkEntryBuffer
中删除文本。
要采用现有代码,请在使用 g_signal_connect_data()
或 g_signal_connect_object()
时使用 g_signal_connect_after()
或 G_CONNECT_AFTER
。
GtkMenu、GtkMenuBar 和 GtkMenuItem 已消失
这些小部件严重依赖于以 X11 为中心的理念,例如覆盖重定向的窗口和抢占,并且很难调整到其他窗口系统。
在 GTK 3 中,可以使用 GtkPopoverMenu 替换菜单。此外,GTK 4 引进了 GtkPopoverMenuBar 来替换菜单栏。这些新小部件只能由菜单模型构建,因此移植工作涉及切换到菜单模型和操作。
表格菜单很少使用并且使菜单代码变得复杂,因此它们尚未被移植到 GtkPopoverMenu
中。如果您需要菜单式弹出窗口中复杂的布局,请考虑直接使用 GtkPopover
。
由于菜单已不复存在,GtkMenuButton
也失去了显示菜单的功能,需要配合 GTK 4 中的弹出窗口一起使用。
GtkToolbar 已被移除
工具栏使用了过时的概念,如需要特殊工具栏小组件。工具栏应该替换为使用包含常规小组件的 GtkBox
,并采取“工具栏”样式 class。
GtkAspectFrame 已不再是框架
GtkAspectFrame
不再派生自 GtkFrame
,也不再在其子元素周围放置标签和框架。不过,它仍然允许您控制子元素的宽高比。
停止使用自定义工具提示窗口
在 GTK 4 中,工具提示不再使用 GtkWindow
,并且不再可能为工具提示提供自定义窗口。不过,仍然可以通过 gtk_tooltip_set_custom()
用自定义小组件替换工具提示的内容。
切换到新的拖放 API
GTK 4 中的源端拖放 API 已更改为使用事件控制器,GtkDragSource
。您无需调用 gtk_drag_source_set()
并连接到 GtkWidget
信号,而是创建 GtkDragSource
对象,将其附加到小组件,并连接到 GtkDragSource
信号。如果您想手动开始拖动,不要在小组件上调用 gtk_drag_begin()
,请改为调用 gdk_drag_begin()
。::drag-data-get
信号已替换为 GtkDragSource::prepare
信号,其为拖动 操作返回 GdkContentProvider
。
GTK 4 中的目标端拖放 API 也已更改为使用事件控制器,即 GtkDropTarget
。您无需调用 gtk_drag_dest_set()
并连接到 GtkWidget
信号,而是创建 GtkDropTarget
对象,将其附加到小组件,并连接到 GtkDropTarget
信号。::drag-motion
信号已重命名为 GtkDropTarget::accept
,并且您无需使用 ::drag-data-received
,而是需要在 GdkDrop
对象上使用异步读取方法,如 gdk_drop_read_async()
或 gdk_drop_read_value_async()
。
适应 GtkIconTheme API 更改
gtk_icon_theme_lookup_icon()
现在返回 GtkIconPaintable
对象,而不是 GtkIconInfo
。它总是返回请求大小的可绘制对象,且永不失败。一些不再相关的查找标志和 API 变体已得到 移除。
请注意,尽管 GTK 4 正在转向 GdkPaintable
作为可绘制内容的主要 API,但这只是作为“纯粹”的内容生成器,因此 GtkIconPaintable
形式的符号形图标不会根据呈现它的背景进行颜色调整。要正确呈现以 GtkIconPaintable
形式提供的符号形图标(可以通过 gtk_icon_paintable_is_symbolic()
进行检查),您必须调用 gtk_icon_paintable_get_icon_name()
,并在 GtkImage
上设置图标名称。
适应 GtkImage 的更改
GtkPicture
‘ 的行为被从 GtkImage
“拆分了出来”,因为后者涵盖了太多用例;如果你正在加载图标,GTK3 和 GTK4 中的 GtkImage
是完全等效的。如果你正在加载更复杂的图像资产,例如图片或缩略图,则 GtkPicture
是合适的 窗口小组件。
一个值得注意的区别是,虽然 GtkImage
的大小由 GTK 计算,GtkPicture
允许你决定 尺寸。
更新到 GtkFileChooser API 更改
GtkFileChooser
移动到基于 GFile 的 API。如果你需要转换路径或 URI,请使用 g_file_new_for_path()
、g_file_new_for_commandline_arg()
或 g_file_new_for_uri()
;类似地,如果你需要从 GFile
中获取路径、名称或 URI,请使用 g_file_get_path()
、g_file_get_basename()
或 g_file_get_uri()
。由于移除了基于路径和 URI 的函数,“仅本地”属性已被移除;GFile 可以用于访问非本地以及本地 资源。
已移除 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
操作。请改用 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
。如果需要新文件夹,用户可以创建 一个。
已从 GtkFileChooser
中删除“confirm-overwrite”信号和“do-overwrite-confirmation”属性。当使用 GTK_FILE_CHOOSER_ACTION_SAVE
时文件选择器窗口小组件会自动处理覆盖文件的确认。
GtkFileChooser
不再支持自定义附加窗口小组件。如果你需要添加附加窗口小组件,请改用 gtk_file_chooser_add_choice()
。
GtkFileChooser
不再支持自定义预览窗口小组件。
停止使用阻塞对话框函数
GtkDialog
、GtkNativeDialog
和 GtkPrintOperation
使用嵌套的主循环移除了其阻塞 API。嵌套的主循环在与不受工具包或应用程序开发人员控制的其他事件源(IPC、可访问性、网络操作)耦合时会出现重入问题和其他难以调试的问题。此外,“停止世界”函数不符合 GTK 的事件驱动编程模型。
你可以通过指定 GtkDialog
必须使用 gtk_window_set_modal()
或 GTK_DIALOG_MODAL
标记成为模态并连接到 GtkDialog::response
信号来替换对 gtk_dialog_run()
的调用。
停止使用 GtkBuildable API
除用于检索可构建 ID 的 getter 函数外,所有 GtkBuildable
API 均变为私有的。如果你正在使用 gtk_buildable_get_name()
,应该用 gtk_buildable_get_buildable_id()
替换它。
适应 GtkAboutDialog API 更改
GtkAboutDialog
现在直接派生自 GtkWindow
,GtkDialog
API 不能再用于 它。
适应 GtkTreeView 和 GtkIconView 工具提示上下文更改
用于在 GtkWidget::query-tooltip
信号内检索来自 GtkTreeView
和 GtkIconView
的数据的 getter 函数不再将指针坐标作为输入参数,而是作为正常输入 的。
请参见:gtk_tree_view_get_tooltip_context()
,gtk_icon_view_get_tooltip_context()
适应 GtkPopover 更改
在 GTK 3 中,可以使用 `relative-to` 属性将 `GtkPopover` 附加到任何小组件。这在 GTK 4 中不再可能。父小组件必须知道其弹出式子小组件并管理其大小分配。因此,只有具有专用弹出式支持的小组件才能拥有它们,例如 GtkMenuButton
或 GtkPopoverMenuBar
。
如果要制作带附加弹出式的自定义小组件,则需要在 Gtk.WidgetClass.size_allocate
vfunc 中调用 gtk_popover_present()
,以便更新弹出式的定位。
停止使用 GtkFileChooserButton
由于用户交互存在缺陷,因此移除了 `GtkFileChooserButton` 小组件。您可以用一个简单的 `GtkButton` 替换它,该 `GtkButton` 在单击时显示 GtkFileChooserNative
对话框;文件选择完成后,您可以使用所选文件更新 `GtkButton` 的标签。
适应已更改的 GtkSettings 属性
在 GTK 3 中,`GtkSettings` 的 GtkSettings:gtk-cursor-aspect-ratio
属性是一个 `float`。在 GTK 4 中,此属性已更改为 `double`。
在切换后需要考虑的更改
GTK 4 具有多项新功能,在最初迁移尘埃落定后,你可能希望利用这些功能。
考虑移植到新的列表小组件
在 GTK 2 和 3 中,`GtkTreeModel` 和 `GtkCellRenderer` 以及使用这些的小组件是显示数据和列表的主要方式。 GTK 4 为此目的引入了一系列新小组件,这些小组件使用列表模型(而非树模型)和 p 小组件(而非单元格渲染器)。
要了解有关新列表小组件的更多信息,你可以阅读 列表小组件概述。