2.3 GTK 中的动作(action)概述
本节详细介绍 GTK 如何使用动作将可激活的用户界面元素与回调函数关联起来。GTK 从 GIO 库继承了用于描述抽象动作和菜单的 GAction 和 GMenu 底层架构。
2.3.1 动作的基础知识
GAction 本质上是一种机制,用于向工具包告知程序中的某项功能,并为该功能命名。
动作完全是功能性的,不包含任何展示性信息。
一个动作关联着四方面信息:
• 作为标识符的名称(通常是全小写、未翻译的英文字符串)
• 一个启用标志,指示该动作是否可被激活(类似控件的“sensitive”属性)
• 可选的状态值,针对有状态动作(如用于切换的布尔值)
• 可选的参数类型,在激活动作时使用
动作支持两种操作。可以激活它,这需要传递一个正确类型的参数;还可以请求(针对有状态动作)将动作的状态更改为正确类型的新状态值。
关于动作有以下规则:
• 名称是不可变的(即永远不会改变),且绝不会为 NULL
• 启用标志可以更改
• 参数类型是不可变的
• 参数类型是可选的:可以为 NULL
• 如果参数类型为 NULL,那么激活动作时必须不带参数(即使用 NULL 的 GVariant 指针)
• 如果参数类型非 NULL,那么参数必须是该类型
• 状态可以改变,但不能改变类型
• 如果动作在创建时是有状态的,那么它将始终具有状态,且状态类型始终完全相同(如布尔型或字符串型)
• 如果动作在创建时是无状态的,那么它永远不会有状态
• 只能对有状态动作请求状态更改,且请求更改后的状态值必须与现有状态的类型相同
动作不包含任何展示性信息,如标签、图标或从中创建控件的方式。
2.3.2 动作状态(Action state)与参数
应用程序中的大多数动作都是无参数的无状态动作。这类动作通常表现为没有特殊装饰的菜单项,例如“退出(quit)”动作。
有状态动作用于表示具有某种紧密关联状态的动作。“全屏(fullscreen)”动作就是一个很好的例子:当全屏选项激活时,菜单项旁会显示一个勾选标记。这类动作通常称为切换动作(toggle action),它具有布尔状态。按照惯例,切换动作在激活时没有参数类型——激活动作总会切换其状态。
另一种常见情况是动作代表某一类型的可能值枚举(通常是字符串类型)。这类动作常被称为单选动作(radio action),在用户界面中通常以单选按钮、单选菜单项或组合框的形式呈现。例如“文本对齐(text-justify)”动作,其可能的状态值为“左(left)”“中(center)”“右(right)”。按照惯例,这类动作的参数类型与其状态类型相同,传入特定参数值激活动作,等价于将其状态更改为该值。
这种处理单选按钮的方式与许多其他动作系统(如 GtkAction)不同。在 GAction 中,“文本对齐”仅对应一个动作,“左”“中”“右”是该动作的可能状态,而非三个独立的“左对齐”“居中对齐”“右对齐”动作。
最后一种常见的动作类型是带参数的无状态动作。这类动作通常用于“打开书签(open-bookmark)”等场景,动作的参数为待打开书签的标识符。
由于某些类型的动作必须带参数才能调用,因此在需要调用动作的地方(如设置特定状态的单选按钮,或打开特定书签的菜单项),指定参数往往至关重要。在这些场景中,动作参数所使用的值通常称为动作的目标(target)。
尽管切换动作具有状态,但它没有参数。因此,引用切换动作时无需指定目标值——激活时它总会进行状态切换。
大多数支持使用 GAction 的 API(如 GMenuModel 和 GtkActionable)都允许使用详细动作名(detailed action names)。这是一种通过单个字符串同时指定动作名和动作目标的便捷方式。
如果动作目标是不包含特殊字符的字符串(即仅含字母、数字、“-”和“.”),可以使用“justify::left”形式的详细动作名,其中“justify”是动作名,“left”是目标值。
如果动作目标不是字符串,或包含特殊字符,则可以使用更通用的格式“action-name(5)”,其中“5”可以是任何有效的文本格式 GVariant(即能被 g_variant_parse() 解析的字符串)。例如“open-bookmark('http://gnome.org/')”。
可以使用 g_action_parse_detailed_name() 和 g_action_print_detailed_name() 在详细动作名与拆分的动作名、目标值之间进行转换,但通常不需要手动操作。大多数 API 都会提供两种方式来指定带目标的动作。
2.3.3 动作作用域(Action scope)
动作始终作用于特定的操作对象。
在 GTK 中,动作的作用域通常是应用程序或窗口,但任何控件都可以关联动作。
作用域为窗口的动作应是那些专门影响该窗口的动作,例如“全屏”“关闭”,或者当窗口包含文档时的“保存”“打印”等动作。
作用域为应用程序的动作是那些影响整个应用程序而非特定窗口的动作,例如“关于”“偏好设置”等。
如果某个动作的作用域是窗口,那么它仅作用于特定窗口。换句话说:如果应用程序有一个适用于窗口的“全屏”动作,且应用程序包含三个窗口,那么就会有三个“全屏”动作——每个窗口对应一个。
为每个窗口设置独立的动作,既可以让每个窗口的动作实例拥有独立的状态,也能按窗口分别控制动作的启用状态。
可以通过 GActionMap 接口或 gtk_widget_insert_action_group() 函数,将动作添加到相应的作用域(应用程序、窗口或控件)中。对于控件类的所有实例都相同的动作,可以使用 gtk_widget_class_install_action() 函数在全局范围内添加。
2.3.4 动作组(Action group)与动作映射(Action map)
动作很少单独出现。相关联的动作通常会组合成组,由 GActionGroup 接口的实例来表示。
动作映射是动作组的一种变体,允许在查找动作时更改动作的名称。在 GTK 中,惯例是为动作名称添加前缀以指示动作的作用域,例如“app.”表示应用程序作用域的动作,“win.”表示窗口作用域的动作。
在引用 GActionMap 上的动作时,只需使用动作本身的名称(即“quit”,而非“app.quit”)。“app.quit”这种形式仅在从 GMenu 或 GtkActionable 控件等无法预先知晓动作作用域的地方引用动作时使用。
GtkApplication 和 GtkApplicationWindow 实现了 GActionMap 接口,因此可以直接向它们添加动作。对于其他控件,可使用 gtk_widget_insert_action_group() 函数为其添加动作。
如果要同时插入多个动作,使用 GActionEntry 通常更快捷简便。
2.3.5 将动作与控件连接
任何实现了 GtkActionable 接口的控件,只需设置 ::action-name 属性,即可与一个动作连接。如果该动作带有参数,还需要设置 ::action-target 属性。实现了 GtkActionable 接口的控件包括 GtkSwitch、GtkButton 及其各自的子类。
获取与动作连接的控件的另一种方式是,使用 GMenu 菜单模型创建菜单。GMenu 提供了一种抽象方式来描述典型菜单:由嵌套组构成的菜单项,每个菜单项可以包含标签、图标和动作。
在 GTK 中,GMenu 的一种典型用法是通过 gtk_application_set_menubar() 来设置应用程序的菜单栏。另一种可能更常见的用法是,通过 gtk_menu_button_set_menu_model() 为菜单按钮创建弹出菜单。
与传统菜单不同,从菜单模型创建的菜单不会为菜单项关联键盘全局键。相反,GtkApplication 提供了 gtk_application_set_accels_for_action() 接口,用于将键盘快捷键与动作关联起来。
2.3.6 激活(Activation)
当与动作相连的控件被激活时,GTK 会沿着控件层级结构向上查找,寻找匹配的动作,最终会查找到 GtkApplication 为止,进而确定要激活的动作。
2.3.7 内置动作
GTK 在多个地方会为自身功能使用动作。这些内置动作有时可被应用程序激活,因此在创建自定义动作时,应避免与之发生命名冲突。
| default.activate | 激活上下文中的默认控件(通常是 GtkWindow、GtkDialog 或 GtkPopover) |
| clipboard.cut, clipboard.copy, clipboard.paste | 在输入框、文本视图和标签上执行的剪贴板操作,通常用于上下文菜单中 |
| selection.delete, selection.select-all | 在输入框、文本视图和标签上执行的选择操作 |
| color.select, color.customize: | 在 GtkColorChooserWidget 中对颜色进行操作。这些动作较为特殊,因为它们具有非简单的参数类型(dddd)。 |
通过网盘分享的知识:GTK 4 Reference Manual
链接: https://pan.baidu.com/s/57mKoejMZPrxs_wh3a7Kj9g
--来自百度网盘超级会员v7的分享
浙公网安备 33010602011771号