Windows 原生 Ribbon 第三部分:按钮和菜单






4.89/5 (15投票s)
本文演示了 Ribbon 的新按钮和菜单功能
目录
引言
在之前的 Ribbon 文章中,我们已经了解了几种 Ribbon 控件:普通按钮和切换按钮。我们还学习了如何创建一个在用户点击应用程序菜单按钮时显示的命令菜单。Ribbon 还有其他类型的按钮——下拉按钮和拆分按钮——它们在点击时会显示菜单。菜单还有一些我们尚未介绍的视觉特性。本文将展示如何使用这些新型按钮和更炫酷的菜单。
与之前一样,构建示例代码的最低系统要求是 Visual Studio 2008、WTL 8.0 和 Windows 7 SDK。如果您运行的是 Windows 7 或 Server 2008 R2,则已具备所需的一切。如果您使用的是 Vista 或 Server 2008,则必须安装 Service Pack 2 和操作系统的 平台更新 才能使用 Ribbon。
示例应用程序
通常,我会在文章末尾讨论示例代码,但我将使用屏幕截图来说明我将要讨论的控件,所以我们应该直接深入示例应用程序。该应用程序在窗口的客户端区域打印文本消息,而 Ribbon 控件允许您更改前景色和背景色。这是前景选项卡的截图。
在本文的讲解过程中,我将演示如何在菜单中排列这些颜色按钮。
下拉按钮
我们要看的第一种新类型的按钮是下拉按钮。它的属性设置方式与普通按钮相同,都使用 <Command>
标签。区别在于,当您点击它时,Ribbon 会显示一个菜单。
让我们看看如何将下拉按钮添加到上面图片中前景选项卡。这是新按钮的 <Command>
标签。
<!-- In the Application.Commands section: -->
<Command Name="cmdFGColorDropdown" Symbol="RIDC_FGCOLOR_DROPDOWN" Keytip="M"
LabelTitle="&List o' colors" TooltipTitle="Color list"
TooltipDescription="Choose a foreground color from this menu" />
这些都是我们之前见过的标准内容。接下来,我们将向选项卡添加一个新组,并将下拉按钮放入该组中。
<!-- In the Ribbon.Tabs section: -->
<Tab CommandName="tabForeground">
<Group CommandName="grpFGButtons" SizeDefinition="EightButtons-LastThreeSmall">
<!-- Omitted: The group of buttons shown above -->
</Group>
<Group CommandName="grpFGDropdown" SizeDefinition="OneButton">
<DropDownButton CommandName="cmdFGColorDropdown">
<!-- Menu contents go here -->
</DropDownButton>
</Group>
</Tab>
这里我们看到一个新 XML 元素 <DropDownButton>
,它(正如您所料)会在组中创建一个下拉按钮。您可以通过添加一个子 <MenuGroup>
标签来指定菜单中的内容。在 <MenuGroup>
中,您为每个菜单项编写一个控件标签,例如 <Button>
或 <ToggleButton>
。您可以通过使用嵌套的 <DropDownButton>
标签来创建子菜单。
下面是一个包含前三个前景色命令的菜单示例。
<!-- In the Application.Commands section: -->
<Command Name="cmdFgColorBlack" LabelTitle="&Black" />
<Command Name="cmdFgColorWhite" LabelTitle="&White" />
<Command Name="cmdFgColorRed" LabelTitle="&Red" />
<!-- In the Ribbon.Tabs section: -->
<Tab CommandName="tabForeground">
<Group CommandName="grpFGButtons" SizeDefinition="EightButtons-LastThreeSmall">
<!-- Omitted: The group shown above -->
</Group>
<Group CommandName="grpFGDropdown" SizeDefinition="OneButton">
<DropDownButton CommandName="cmdFGColorDropdown">
<MenuGroup>
<Button CommandName="cmdFgColorBlack" />
<Button CommandName="cmdFgColorWhite" />
<Button CommandName="cmdFgColorRed" />
</MenuGroup>
</DropDownButton>
</Group>
</Tab>
菜单看起来是这样的。
菜单看起来与应用程序菜单相似,但它默认对命令使用小图标。我们将在下一节中了解如何自定义菜单的外观。
在定义菜单时,您可以采取一种快捷方式。如果您只有一个菜单组,则可以省略 <MenuGroup>
标签,并将菜单的内容作为 <DropDownButton>
标签的子项编写。
更改菜单的外观
有几种方法可以使用 <MenuGroup>
标签的特性来自定义菜单的外观。首先,您可以使用多个菜单组来创建分隔符。下面是如何创建一个包含所有八个颜色命令的菜单,并在第 4 个和第 5 个命令之间添加分隔符。
<DropDownButton CommandName="cmdFGColorDropdown">
<MenuGroup>
<Button CommandName="cmdFgColorBlack" />
<Button CommandName="cmdFgColorWhite" />
<Button CommandName="cmdFgColorRed" />
<Button CommandName="cmdFgColorCyan" />
</MenuGroup>
<MenuGroup>
<Button CommandName="cmdFgColorPurple" />
<Button CommandName="cmdFgColorGreen" />
<Button CommandName="cmdFgColorBlue" />
<Button CommandName="cmdFgColorYellow" />
</MenuGroup>
</DropDownButton>
菜单看起来是这样的。
<MenuGroup>
还有一个 Class
属性。Class
默认为 "StandardItems",但如果将其设置为 "MajorItems",则菜单将在该组中的命令使用大图标。这是将 Class="MajorItems"
添加到第一个 < MenuGroup>
标签的结果。
请注意,每个命令的 LabelTitle
现在都显示为粗体。您可以添加一个 LabelDescription
,它将显示在 LabelTitle
下方。例如,我们可以将 LabelDescription
添加到黑色命令。
<!-- In the Application.Commands section: -->
<Command Name="cmdFgColorBlack" LabelTitle="&Black"
LabelDescription="Set the foreground to #000000" />
命令看起来是这样的。
菜单将根据需要插入换行符。您可以通过将换行符的 XML 转义字符——

——放入 LabelDescription
来插入自己的换行符,但这样做会与菜单自身的换行符冲突。
最后,您可以将一个命令分配给一个菜单组。执行此操作时,Ribbon 会创建一个更长分隔符,作为该菜单部分的标题。标题还显示该命令的 LabelTitle
。例如,我们可以添加这些命令。
<!-- In the Application.Commands section: -->
<Command Name="hdrClrMenu1" LabelTitle="Group 1" />
<Command Name="hdrClrMenu2" LabelTitle="Group 2" />
然后将这些命令名称添加到 <MenuGroup>
标签中。
<DropDownButton CommandName="cmdFGColorDropdown">
<MenuGroup Class="MajorItems" CommandName="hdrClrMenu1">
<Button CommandName="cmdFgColorBlack" />
<Button CommandName="cmdFgColorWhite" />
<Button CommandName="cmdFgColorRed" />
<Button CommandName="cmdFgColorCyan" />
</MenuGroup>
<MenuGroup CommandName="hdrClrMenu2">
<Button CommandName="cmdFgColorPurple" />
<Button CommandName="cmdFgColorGreen" />
<Button CommandName="cmdFgColorBlue" />
<Button CommandName="cmdFgColorYellow" />
</MenuGroup>
</DropDownButton>
带这些新标题的菜单看起来是这样的。
复选框
我们要看的下一个控件是复选框。复选框类似于切换按钮,因为它在被点击时会维护自己的选中状态。但是,复选框没有图标;相反,当控件被选中时,会在项目旁边绘制一个勾号。
复选框默认情况下最初是未选中的。当控件首次显示时,Ribbon 将查询 UI_PKEY_BooleanValue
属性以确定初始的选中状态。
将复选框添加到菜单中与按钮类似:您将 <CheckBox>
标签作为 <MenuGroup>
的子项编写。下面是如何将复选框添加到前景色菜单的示例。
<!-- In the Application.Commands section: -->
<Command Name="cmdShowColors" LabelTitle="&Show colors" />
<!-- Then in the DropDownButton definition: -->
<DropDownButton CommandName="cmdFGColorDropdown">
<!-- The same MenuGroups listed above -->
<MenuGroup>
<CheckBox CommandName="cmdShowColors" />
</MenuGroup>
</DropDownButton>
复选框在选中状态下看起来是这样的。
示例应用程序在该命令被选中时显示额外的颜色信息。屏幕截图还显示了 QAT 中的复选框,它看起来像传统的复选框。
拆分按钮
我们要介绍的另一种按钮是拆分按钮,它有两个部分:一个按钮和一个下拉菜单。点击拆分按钮的按钮部分会执行一个命令,该命令称为按钮项。点击下拉箭头部分会显示一个菜单,与下拉按钮完全相同。
示例应用程序在背景选项卡上展示了一个拆分按钮。与前景选项卡一样,有八个按钮用于设置背景色,这些命令也出现在拆分按钮的菜单中。当执行按钮项命令时(也就是说,当您点击拆分按钮的按钮部分时),应用程序会将颜色重置为默认值。
由于拆分按钮有两个部分,它的属性来自两个 <Command>
标签。
<!-- In the Application.Commands section: -->
<Command Name="cmdBGColorSplit" Symbol="RIDC_BGCOLOR_SPLIT" Keytip="M"
TooltipDescription="Choose a background color from this menu" />
<Command Name="cmdBGSplitButtonItem" Symbol="RIDC_BGCOLOR_SPLITBUTTON_ITEM"
LabelTitle="List &o' colors" TooltipTitle="Color list"
TooltipDescription="Reset colors to their default values" />
然后我们使用 <SplitButton>
标签将拆分按钮添加到组中。<SplitButton>
与 <DropDownButton>
略有不同,因为我们必须为按钮项指定命令。<SplitButton>
有两个子标签。
<SplitButton.ButtonItem>
:此标签必须包含一个子标签,可以是<Button>
或<ToggleButton>
,用于定义按钮项。<SplitButton.MenuGroups>
:这是按钮菜单部分的容器标签。菜单的内容的指定方式与下拉按钮相同。
与下拉按钮一样,如果您只有一个菜单组,则可以省略 <SplitButton.MenuGroups>
标签,并将菜单的内容作为 <SplitButton>
标签的子项编写。
下面是背景选项卡及其组的定义,在第二个组中有拆分按钮。
<!-- In the Ribbon.Tabs section: -->
<Tab CommandName="tabBackground">
<Group CommandName="grpBGButtons">
<!-- Omitted: The group of 8 buttons -->
</Group>
<Group CommandName="grpBGSplit" SizeDefinition="OneButton">
<SplitButton CommandName="cmdBGColorSplit">
<SplitButton.ButtonItem>
<Button CommandName="cmdBGSplitButtonItem" />
</SplitButton.ButtonItem>
<SplitButton.MenuGroups>
<!-- Omitted: The menu, similar to the drop-down button's menu -->
</SplitButton.MenuGroups>
</SplitButton>
</Group>
</Tab>
按钮显示菜单的效果是这样的。
拆分按钮的某些视觉方面由拆分按钮的命令控制,某些方面由按钮项的命令控制。
LabelTitle
、LabelDescription
、图标、TooltipTitle
:由按钮项控制。Keytip
:由拆分按钮控制。TooltipDescription
:TooltipDescription
文本来自鼠标指针所在的按钮部分。
由于只使用了拆分按钮的 Keytip
,因此无法使用键盘调用按钮项。为了确保按钮项可访问,您可以将按钮项的命令包含在菜单中,或提供另一个执行与按钮项相同功能的命令。示例应用程序使用了后一种方法;默认颜色命令也会重置颜色。
您可以将整个拆分按钮添加到 QAT 中,方法是右键单击下拉部分并从上下文菜单中选择添加到快速访问工具栏。您还可以右键单击任何菜单标题或分隔符。右键单击拆分按钮的按钮部分允许您将按钮项添加到 QAT。
您可以像禁用其他控件一样禁用与拆分按钮关联的任何一个命令,但每个命令的效果不同。禁用拆分按钮的命令会禁用整个按钮,而禁用按钮项的命令则会使下拉部分保持启用状态。示例应用程序有两个按钮,用于启用和禁用拆分按钮的每个部分,因此您可以自己查看按钮的外观和行为。
在应用程序菜单中使用这些控件
正如我们在之前的文章中所见,您使用 <MenuGroup>
标签定义应用程序菜单的内容。我们在此处看到的所有菜单组功能也适用于应用程序菜单,但对于作为 <ApplicationMenu>
标签子项的组,有两个区别。
Class
属性默认为 "MajorItems"。Class
为 "MajorItems" 的组中的项目不会以粗体显示,并且LabelDescription
不会显示。
这些差异仅影响菜单中的顶级项目。通过嵌套下拉按钮或拆分按钮创建的子菜单遵循我们已经看到的适用于这些按钮的规则。
如果您将拆分按钮嵌套在应用程序菜单中,还有另外两个区别。
- 拆分按钮的两个部分都可以通过键盘访问。按钮项的助记符来自其
LabelTitle
,而不是其Keytip
,就像其他菜单一样。您可以通过将下拉部分的LabelTitle
设置为 "&" 加上键来为其分配助记符,例如:"&S"。 - 当拆分按钮的命令被禁用时,控件的按钮项部分仍然可访问。这意味着当您想要禁用拆分按钮的所有部分时,您必须禁用其两个命令,以便整个按钮被禁用,无论按钮位于何处。
示例应用程序演示了如何使拆分按钮的两个部分都可访问。
其他杂项
帮助按钮
您可能已经在屏幕截图中注意到,Ribbon 最右侧有一个帮助按钮。这是一个易于设置的内置功能。要显示帮助按钮,请将 <Ribbon.HelpButton>
标签作为 <Ribbon>
标签的子项编写。
<Ribbon>
<Ribbon.HelpButton>
<HelpButton CommandName="cmdHelp" />
</Ribbon.HelpButton>
</Ribbon>
在相应的 <Command>
标签中,您可以设置键提示、工具提示标题和工具提示描述。在其他所有方面,帮助按钮都像其他任何按钮一样工作。
对话框启动器
Office Ribbon 有一个称为对话框启动器的功能,它是一个组底部右侧的小按钮。在 Windows 7 的 Beta 版本中,原生 Ribbon 也具有此功能,但由于专利相关问题,它被从最终版本中删除了。(来源:CodePlex 上的这篇帖子。)
将 Ribbon 设置保存到注册表
之前的示例应用程序将 Ribbon 设置保存在 TEMP
目录中的一个文件中。另一个存储设置的常见位置是 HKEY_CURRENT_USER
下的注册表项。示例应用程序以这种方式保存设置,使用 SHOpenRegStream2()
函数创建一个流来读取或写入注册表项。加载设置的代码如下所示。
void CAppRibbon::LoadRibbonSetings()
{
// Create an IStream interface on the registry entry that the app uses to
// hold settings data. This will fail if the registry entry doesn't exist,
// in which case, the Ribbon will start out in a default state.
CComPtr<IStream> pStrm;
pStrm.Attach(SHOpenRegStream2(HKEY_CURRENT_USER, m_sSettingsKey,
m_sSettingsValue, STGM_READ));
if (NULL != pStrm)
m_pRibbon->LoadSettingsFromStream(pStrm);
}
保存设置的代码类似,但它使用 STGM_WRITE
标志打开流以获得写入访问权限。
结论
下拉按钮允许您将命令组织到菜单和子菜单中,而不是将每个命令都作为按钮放在 Ribbon 中。在下一篇文章中,我们将更详细地探讨快速访问工具栏、如何在运行时与其交互以及如何指定默认在此处显示的命令。
修订历史
2011年 9月 12日:文章首次发布