openSUSE:YaST 开发杂项按钮顺序
YaST 和 KDE 与 GNOME 按钮顺序
摘要
KDE 和 GNOME 使用不同的按钮顺序。YaST 需要在两种环境中运行。为了正确支持这一点,按钮需要放置在一个可以根据桌面环境处理按钮顺序的窗口部件中,并且这些按钮需要被分配一个合适的按钮角色。
对于 YCP 开发人员来说,在大多数情况下,用一个 `ButtonBox()` 替换包含按钮的 `HBox()` 就足够了。
关于按钮顺序
按钮顺序对于具有多个按钮的弹出对话框很重要。通常有一个肯定的答案,例如 [确定],它将使用用户在该对话框中所做的任何更改并使用这些值继续。
为了可用性,如果有多个按钮,应该有一个按钮作为“安全退出”(通常是 [取消],它在不更改任何内容的情况下关闭对话框)。
KDE 按钮顺序
KDE 使用与 Windows 相同的按钮顺序:肯定的按钮(通常是 [确定])是最左边的。如果有 [应用] 按钮,它是下一个,然后是 [取消] 作为“安全退出”按钮。如果有 [帮助] 按钮,它是最右边的按钮。
这种理念遵循大多数西方语言中常见的阅读顺序:从左到右。肯定的确认(“确定”)被认为是常用按钮,因此它被放置在阅读顺序的第一位。
这是与按钮顺序讨论相关的最简单的情况。
在此示例中,[继续] 按钮是肯定的确认。
[是] 在这里是肯定的确认。
[应用] 也是肯定的确认,尽管它会使对话框保持打开状态。
“自定义”按钮(此处:[执行某事] 和 [执行更多])放置在具有预定义角色的按钮之间(在 [确定]、[应用]、[取消] 的右侧,在 [帮助] 的左侧)。
此对话框也略微调整大小,以显示如何使用多余的空间:按钮水平居中。
GNOME 按钮顺序
GNOME 使用类似于 MacOS 的按钮顺序:肯定的按钮是最右边的。“安全退出”(“取消”)在该按钮的左侧。
总体思路是 [确定] 和 [取消] 的位置始终相同,并且对话框的右下角是一个非常显眼的位置。它也与具有 [下一步] 按钮的“向导”式对话框一致:肯定的确认始终位于右下角。
这也是为什么如果按钮需要的空间更多,按钮会右对齐的原因。
简单示例
[继续] 在此示例中是肯定的答案。
显然,这很令人困惑:人们总是问“是或否”,从不问“否或是”。这种反转的顺序违反直觉。但它在 GNOME 中用于保持一致性:肯定的确认(“是”)始终是最右边的按钮。
请注意,即使在这种情况下,[取消] 也放置在 [确定] 旁边,即使 [应用] 也是另一个肯定的答案。
GNOME 很少使用 [应用] 按钮:大多数 GNOME 应用程序使用“即时应用”,这意味着更改在对话框中进行时立即生效。
YaST 仅在少数情况下使用 [应用],但正在使用它;在可能格式化硬盘驱动器的程序中使用“即时应用”会很尴尬。
略微调整大小以显示如何右对齐按钮(如果有多余的空间)。
YaST UI 中的按钮顺序
YaST UI 现在支持一个专用的 ButtonBox 窗口部件,它可以自行处理按钮顺序。
在大多数情况下,YCP 代码的迁移就像用一个 ButtonBox 替换保存对话框按钮的 HBox 窗口部件一样简单。
旧的 YCP 代码
`HBox(
`PushButton(`id(`ok ), _( "&OK" ) ),
`PushButton(`id(`cancel), _( "&Cancel" ) )
)
新的 YCP 代码
`ButtonBox(
`PushButton(`id(`ok ), _( "&OK" ) ),
`PushButton(`id(`cancel), _( "&Cancel" ) )
)
更多 YCP 示例
按钮角色
通常,YCP 代码需要指定按钮具有什么角色
- okButton
- cancelButton
- applyButton
- helpButton
- customButton(其他所有)
okButton 是一个也关闭对话框的对话框的肯定答案。它可能标记为 [确定],但有时也标记为 [继续] 或 [是]。
在某些情况下,使用直接描述对话框做什么的动词是有意义的;例如,在打印对话框中,它可能标记为 [打印],在文件保存对话框中,它可能标记为 [保存] 等。
cancelButton 是“安全退出”。通常是 [取消]。在 [是] / [否] 对话框中,它是 [否]。应避免其他标签。
applyButton 是使用对话框的值的肯定答案,但不关闭对话框。如果对话框有这样的按钮,它应该始终是 [应用]。
helpButton 是调用此对话框的在线帮助的按钮。如果对话框有这样的按钮,它应该始终是 [帮助]。
customButton 是所有不具有上述预定义角色的其他按钮的角色。对话框可以有任意数量的 customButton,而所有其他角色在该对话框中都应该是唯一的。
YCP 代码可以将这些角色中的任何一个作为窗口部件选项分配给 PushButton 窗口部件
`PushButton(`id(`print), `opt(`okButton), _( "&Print" ) )
通常没有必要显式指定 `opt(`customButton); 这是默认值。仅在以下启发式方法猜测错误时才指定它。在这种情况下,`opt(`customButton) 会覆盖猜测。
自动分配按钮角色的启发式方法
YaST UI 具有一些内置逻辑来自动识别许多常见按钮。
按按钮标签
使用众所周知的按钮标签,就像使用自动将功能键分配给按钮一样:UI::SetFunctionKeys() 函数将(翻译后的!)按钮标签映射到功能键
| 按钮标签 | 功能键 | 按钮角色 |
|---|---|---|
| [确定] | F10 | okButton |
| [是] | F10 | okButton |
| [继续] | F10 | okButton |
| [取消] | F9 | cancelButton |
| [否] | F9 | cancelButton |
| [帮助] | F1 | helpButton |
请参阅 Label.ycp 中的 Label::DefaultFunctionKeyMap()
它的优点是即使使用翻译的标签(如果正确使用)也能工作。
按功能键
显式使用 `opt(`key_F10), `opt(`key_F9), 或 `opt(`key_F1) 具有类似的效果
| 功能键 | 按钮角色 |
|---|---|
| `opt(`key_F10) | okButton |
| `opt(`key_F9) | cancelButton |
| `opt(`key_F1) | helpButton |
按窗口部件 ID
使用一些常见的窗口部件 ID 来确定按钮的角色
| 窗口部件 ID | 按钮角色 | |||
|---|---|---|---|---|
| `id(`ok) | `id(`OK) | `id("ok") | `id("OK") | okButton |
| `id(`yes) | `id(`Yes) | `id("yes") | `id("Yes") | okButton |
| `id(`continue) | `id(`Continue) | `id("continue") | `id("CoNTiNue") | okButton |
| `id(`accept) | `id("accept") | okButton | ||
| `id(`cancel) | `id("cancel") | cancelButton | ||
| `id(`no) | `id("no") | cancelButton | ||
| `id(`apply) | `id("apply") | applyButton | ||
| `id(`help) | `id("help") | helpButton |
(所有 ID 均不区分大小写)
请参阅 YCPDialogParser.cc 中的 YCPDialogParser::parseButtonBox()
它的优点是不依赖于翻译的按钮标签和 UI::SetFunctionKeys()。
但它也可能出错。在这种情况下,可能需要显式使用 `opt(`customButton) 来覆盖自动分配的按钮角色。检查 y2log 中是否有如下行
Guessed button role YApplyButton for YPushButton "Apply" at 0x80c01b4 from widget ID
选择按钮顺序
- NCurses UI:使用 KDE 按钮顺序
- Gtk UI:使用 GNOME 按钮顺序
- Qt UI:默认使用 KDE 按钮顺序,但也可以使用 GNOME 按钮顺序
- $DESKTOP_SESSION 环境变量
- $WINDOWMANAGER 环境变量
- $Y2_BUTTON_ORDER 环境变量
- --gnome-button-order (y2base 的命令行参数)
- --kde-button-order (y2base 的命令行参数)
$DESKTOP_SESSION 和 $WINDOWMANAGER 由桌面环境设置。$Y2_BUTTON_ORDER 旨在供希望覆盖前者选择的任何默认值的专家用户使用:将其设置为“kde”或“gnome”(不区分大小写)。
ButtonBox 窗口部件详情
ButtonBox 只能拥有 PushButton 子窗口部件。它会拒绝其他任何内容。这是设计使然:ButtonBox 负责边距、间距和对齐方式。任何其他窗口部件(例如 HSpacing、HStretch、Right、Left、Center 等)只会碍事。
通常,ButtonBox 应该拉伸对话框的整个宽度。它应该是对话框中最底部的窗口部件。
调整大小后,如果空间不足,ButtonBox 窗口部件将首先放弃边距和间距,然后再尝试调整按钮大小。如果仍然没有足够的空间,它将(在 GNOME 按钮顺序中)放弃尝试使所有按钮具有相同宽度的约束。
完整性检查
如果 ButtonBox 具有多个按钮,它将执行完整性检查:它会检查是否只有一个 okButton 和一个 cancelButton。可以有一个 applyButton 和一个 helpButton,但可以有任意数量的 customButton。
如果违反了任何这些约束,它将抛出一个异常,这将导致 UI::OpenDialog() 失败(即返回 false)。
在极少数情况下,放松完整性检查是有意义的。
多个按钮,但没有 cancelButton,只有 okButton
在这种情况下,使用 `opt(`relaxSanityCheck)
`ButtonBox(`opt(`relaxSanityCheck),
`PushButton(`id(`ok ), _( "&OK" ) ),
`PushButton(`id(`cancel), _( "&Details" ) )
)
明智地使用它。









