65.9K
CodeProject 正在变化。 阅读更多。
Home

圆形菜单组件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (52投票s)

2005年1月21日

16分钟阅读

viewsIcon

254397

downloadIcon

4967

介绍使用 C# 编写的动画式、圆形排列的弹出菜单控件的使用和架构。

Sample Image - circularmenu.jpg

引言

圆形菜单组件是一个 .NETTM 用户界面组件,我将其开发为可用性课程项目的一部分。它是一个动画菜单弹出窗口,可在启动弹出窗口的位置周围以圆形显示选项图标。

尽管该工具是我设计和编写代码的,但我的团队成员在布局理念方面做出了多项贡献

  • Eric Engquist
  • Joshua Correa
  • Zianeh Kemmeh-Gama

非常感谢他们宝贵的意见和建议。

与传统的弹出窗口相比,圆形菜单具有一些优势

  1. 它们看起来更酷:用户会喜欢这种菜单的新颖外观和感觉,它会为您的应用程序增添额外的酷感。
  2. 它们更有趣:圆形弹出窗口的动画和新颖样式有助于为您的程序营造更“有趣”的氛围。这有助于用户放下戒备,更容易地学习您的应用程序。
  3. 它们可以提供更高的用户效率:由于菜单选项围绕单击位置呈圆形排列,因此当菜单首次显示时,每个选项到用户鼠标的距离都相等。圆形菜单是图标化的,可以看作是临时可见的工具栏。由于用户查找图标的速度比查找文本快,因此使用圆形弹出窗口可能比普通弹出窗口更快,并且由于弹出窗口出现在用户关注点的位置,因此它们甚至可能比普通工具栏更快。

当然,圆形菜单也有缺点,其中一些在此处进行了描述

  1. 由于信息主要是图标化的,因此用户将无法使用不提供有效视觉隐喻的圆形菜单。尽管菜单支持工具提示,但如果用户需要在找到每个项目之前阅读其文本,则无法高效地使用该菜单。另一方面,一旦他们使用过每个选项一次,他们就能更容易地将大致含义与图标关联起来。
  2. 圆形排列意味着菜单的整体尺寸必须随着选项的增加而增加:选项越多,菜单越大。当菜单中的图标较大时,尤其如此。这可能会限制您在圆形菜单中放置的选项数量,而不同于传统的变体。
  3. 圆形菜单的外观将取决于您如何制作它。在图标的开发中需要格外注意,以使其看起来专业且现代,而且很少有软件开发人员是兼职图形艺术家。幸运的是,网络和 MicrosoftTM Visual StudioTM 上都有大量简单的图标可供使用。虽然 Visual Studio 图标很小,看起来不如专业设计的图标,但添加菜单动画和阴影将有助于确保您的弹出窗口仍然看起来很酷。

本文档提供了对圆形菜单组件结构的通用概述,以及在其第三方应用程序中使用它的教程。

许可协议和免责声明

本软件及随附文档按“原样”提供,不附带任何明示或暗示的保证。请自行承担使用风险。作者对本产品可能造成的任何损坏或数据丢失不承担任何责任。

修改后,本产品(源代码、二进制文件和文档)可以自由再分发,用于商业和个人用途。可接受的修改定义为:添加、对源代码进行有意义的更改,或将源代码或二进制文件包含在更大的软件包中。

我请求,但不要求,对我的工作进行署名。这可以放在您的产品文档中,或者直接放在软件的“帮助/关于”屏幕中。

教程 (Visual Studio .NET)

将圆形菜单组件添加到 Visual Studio 工具箱

在使用圆形菜单组件创建程序之前,需要将该组件添加到 Visual Studio 工具箱面板中。

为此,请右键单击工具箱中的任意位置,然后选择“添加/删除项…”。

选择此菜单选项将显示“自定义工具箱”对话框。在此,您必须先单击“浏览…”按钮,然后导航到安装圆形菜单的目录。

找到安装目录后,选择“CircularMenu.dll”文件,然后选择“打开”。这将返回到“自定义工具箱”对话框。单击“确定”,您将返回到 Visual Studio。圆形菜单组件和菜单选项组件的新图标已添加到您的工具箱中。

添加和配置弹出菜单

使用您选择的语言创建一个新的 Windows 应用程序项目。模板就绪后,您的项目中将有一个名为 Form1 的新窗体。确保已按照前面的说明将圆形菜单添加到工具箱。完成此操作后,您可以将其从工具箱拖放到窗体上。立即执行此操作。请注意,Visual Studio 在您的组件托盘中创建了一个名为“circularMenuPopup1”的图标。您可以像处理任何其他控件一样,通过“属性”窗口修改圆形菜单的属性。

这些属性共同控制您的圆形菜单的外观和行为。OpeningAnimationClosingAnimation 属性分别定义菜单打开和关闭时播放的动画。ToolTip 属性控制菜单工具提示的显示方式和位置。

暂时保留默认值。要向菜单添加项,我们需要使用 MenuOptions 属性。为此,请在属性编辑器中选择 MenuOptions,然后单击右侧出现的“…”按钮。

这将打开一个“MenuOption Collection Editor”对话框,可用于向菜单添加选项并对其进行配置。单击“添加”按钮三次,为菜单添加三个新选项。

请注意,您可以直接在此对话框中编辑菜单的属性。每个选项都已添加到 Visual Studio 设计器的组件托盘中,因此也可以在此对话框外部进行编辑。

选择第一个选项“menuOption1”。我们将使其成为一个“打开”按钮。请按照以下步骤操作

  1. 选择“HoverImage”属性,然后单击右侧的“…”按钮。这将打开“Edit Menu Option Image”对话框,您可以使用它来控制选项的外观。选择“浏览…”,然后导航到您的 Visual Studio 程序目录(通常为“C:\Program Files\Microsoft Visual Studio”或“C:\Program Files\Microsoft Visual Studio .NET 2003”)。在此,选择“Common7”目录,然后打开“Graphics”。此目录包含许多通用图标和位图,您可以在应用程序中随处使用。
  2. 选择“bitmaps”目录,然后打开“Tlbr_W95”。选择并打开“OPEN.BMP”文件。
  3. 将透明度设置为“ffc0c0c0”以使此图像的背景透明,然后单击“确定”。
  4. DisabledImageImagePressedImage 属性重复步骤 1-3。
  5. 最后,将 ToolTip 属性设置为“打开文件”。

重复这些步骤,将 menuOption2 设置为“保存”按钮,将 menuOption3 设置为“打印”按钮。完成后,单击“MenuOption Collection Editor”对话框上的“确定”按钮。

由于我们使用的图标相对较小,因此需要减小弹出菜单的半径。从组件托盘中选择“circularMenuPopup1”,然后将 Radius 属性从 50 更改为 25。

我们还可以稍微更改一下动画:选择“OpeningAnimation”属性,然后单击右侧的“…”按钮。在出现的编辑对话框中,将布局样式更改为“沿周长旋转”,将效果样式更改为“放大”,然后将帧数更改为“30”。帧大约每秒显示 30 帧,因此这使得我们的打开动画接近一秒钟。

单击播放按钮预览动画,然后单击“确定”关闭对话框。我们终于可以启用弹出窗口了。弹出窗口何时以及为何显示取决于您,但一个非常常见的触发器是右键单击窗体。要启用此功能,请执行以下步骤

C#

  1. 选择您的窗体,然后单击属性窗口中的闪电图标以查看可用于该窗体的事件。
  2. 找到“MouseUp”事件并双击它。这将启动代码编辑器,并带有一个新添加的方法,名为“Form1_MouseUp”。
  3. 将以下代码添加到新方法中
    if( e.Button == MouseButtons.Right )
        circularMenuPopup1.Popup( this, e.X, e.Y );

Visual Basic

  1. 右键单击窗体上的某个位置,然后选择“查看代码”。这将打开代码编辑器窗口。
  2. 将以下代码添加到 Form1 类中
    Private Sub Form1_Click(ByVal sender as Object, ByVal e As MouseEventArgs)_
             Handles MyBase.MouseUp
        If e.Button = MouseButtons.Right Then
            CircularMenuPopup1.Popup(Me, e.X, e.Y)
        End If
    End Sub

现在,我们可以测试该应用程序了!使用“调试 > 开始”菜单选项(Visual Basic 用户快捷键 F5)运行该应用程序,然后在窗体上的任意位置右键单击以调出快捷菜单!

处理菜单事件

当圆形菜单显示时,它会获取系统的输入焦点,直到用户取消菜单或选择一个选项后才会释放。这些用户操作通过一组事件传达给您的程序,其中最重要的事件是 MenuOption 类的“Click”事件和 CircularMenuPopup 类的“OptionSelected”事件。

这些事件的主要区别在于,“Click”事件由特定的菜单选项触发,而圆形菜单本身会触发“OptionSelected”事件。这意味着,在编写处理“Click”的方法时,每个方法中只需要包含特定于单个菜单选项的代码。另一方面,编写“OptionSelected”处理程序意味着在该菜单处理程序中包含每个菜单选项的代码。

这两个事件主要用于支持不同的样式,但 OptionSelected 确实比 Click 提供更多信息——特别是,菜单显示时的坐标。如果您需要知道菜单在用户选择选项时显示的位置,则需要使用 OptionSelected 事件。有关更多详细信息,请参阅代码文档。

在本教程中,我们将编写一些代码来处理“打开”按钮的 Click 事件。为此,请关闭任何打开的对话框,然后从组件托盘中选择 menuOption1。双击 menuOption1 将自动为您的 Form1 类添加一个新方法,该方法可以处理该选项的 Click 事件。默认情况下,它称为“menuOption1_Click”。

出于演示目的,我们将在此方法中显示一个打开对话框。代码如下

C#

private void menuOption1_Click(object sender, System.EventArgs e)
{
    OpenFileDialog dialog = new OpenFileDialog();
    dialog.ShowDialog( this );
}

Visual Basic

Private Sub MenuOption1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MenuOption1.Click
   Dim dialog As New OpenFileDialog
   dialog.ShowDialog(Me)
End Sub

现在,当您运行程序并单击菜单中的“打开文件”按钮时,系统将显示一个“打开文件”对话框。

进一步探索

系统提供的其他事件允许您在用户将鼠标光标移到选项上 (MenuOption.StartHover) 或移出选项 (MenuOption.EndHover) 时收到通知。您还可以处理 CircularMenuPopup.MenuCanceled 以在用户未选择任何内容而取消菜单时收到通知,以及处理 CircularMenuPopup.MenuClosed 以在菜单关闭时(无论是否选择了选项)收到通知。

库中的动画由实现 IFrameLayoutManagerIFrameModifier 的类处理。这些类负责将选项围绕单击位置排列并应用动画效果。有关编写自己的动画和效果的更多详细信息,请参阅文档和默认实现。这些类应用于 MenuAnimation 类的 FrameImageEffectLayoutAnimator 属性。菜单的打开和关闭动画都是 MenuAnimation 类的实例。

类似地,菜单工具提示由实现 IToolTipRenderer 接口的类绘制。您可以通过 CircularMenuPopup.ToolTipOverride 属性指定自定义工具提示渲染器。

圆形菜单架构

圆形菜单组件的代码是用 Microsoft 提供的 C# 语言编写的。虽然 .NET SDK 和 C# 编译器都是免费提供的,但圆形菜单代码大量使用了 Visual Studio 开发环境提供的附加功能,因此本文档是从使用 Visual Studio 的开发者的角度编写的。

作为 .NET 平台第二个主要版本 (2.0) 的一部分,Microsoft 计划提供免费版本的 Visual Studio,面向对 C# 和 Visual Basic 感兴趣的学生和业余爱好者。有关这些环境的早期文档表明,它们将具有与其零售版本类似的功能,但会限制使用它们编写的应用程序的复杂性。

还有一个免费设计器可用于访问圆形菜单程序集的 Visual Studio 功能。截至本文撰写之时,有关此设计器的信息可以在以下 URL 找到

圆形菜单组件的代码已分为两个独立的程序集:CircularMenu.dllPixelEffects.dll。PixelEffects 库旨在为 CircularMenu 库中的绘图提供通用的特殊效果,本文档将不进行讨论。但是,其中包含其源代码。

下图显示了圆形菜单库的基本类

Class Diagram

圆形菜单库可分为三个子系统:顶级对象、菜单选项和渲染,以及菜单动画。顶级对象充当其他两个子系统中对象的控制器。

顶级对象

在此架构中,CircularMenuPopup 类代表最高层级实体。在以此处开始的依赖链中,您将能够访问该库提供的大部分功能。

另一个顶级组件 CircularMenuWindow 是一个 System.Windows.Forms.Form 子类型,能够为圆形菜单设置动画和显示。这是负责将用户选择传递给请求应用程序的类。虽然 Menu Window 是一个公开可用且可用的类,但在大多数情况下,您将通过 Menu Popup 对象而不是直接使用它。

圆形菜单弹出窗口由四个对象组成:菜单选项集合、打开动画、关闭动画和工具提示渲染器。这些对象反过来又由几个元素组成。

菜单选项和渲染

MenuOptionCollection 类是 .NET CollectionBase 类的简化实现,针对非空 MenuOption 对象进行了强类型化。该类公开了一个方法,该方法返回当前可见的所有菜单选项的子集合。此子集合在显示或设置窗口动画时使用。

MenuOption 类的实例描述弹出菜单中的单个元素。这些类似于传统 .NET 菜单中的 MenuItem 实例。每个选项都维护一个启用状态、一个可见状态和一个工具提示,以及控制选项渲染时视觉外观的若干图像。这些图像以 MenuOptionImage 实例的形式存储,包括 ImageDisabledImageHoverImagePressedImage。稍后将详细介绍这些。

每个 MenuOptionImage 对象定义一个图标和对图像的可选操作(颜色键、透明度、阴影)。当系统需要绘制与对象关联的图像时,此类会逐个执行每个可选操作,并返回渲染结果。由于此过程可能很耗时,因此每个 MenuOptionImage 都会存储结果的缓存版本。当图像的任何选项发生更改时,缓存的结果会被清除(并在请求时重新渲染)。

最后,DropShadowOptions 类封装了定义应用于图像的阴影算法行为的选项。每个 MenuOptionImage 实例都有一个相应的 DropShadowOptions 实例。

最后,IToolTipRenderer 接口描述了一个能够绘制弹出菜单的工具提示的对象。CircularMenu.dllStandardToolTipRenderer 中提供了此接口的默认实现。此渲染器只是将工具提示放置在弹出菜单的中心。它公开了多个可以通过 Visual Studio 设计器配置的选项。

工具提示渲染器的扩展版本由 IExtraSpaceToolTipRenderer 接口及其默认实现 BelowMenuToolTipRenderer 描述。这种类型的工具提示渲染器可能需要在菜单表面上占用额外的空间,而这仅通过菜单选项的位置和大小无法说明。例如,下面的菜单渲染器会将工具提示放置在所有菜单选项下方,因此会增加菜单的总高度。这些类型的工具提示渲染器需要将其额外需求报告给系统,以便正确创建和定位菜单。

StandardToolTipRendererBelowMenuToolTipRenderer 都继承了基类 StandardToolTipData,该类提供了常见的与设计器兼容的选项列表,例如前景色和边框粗细。

菜单动画

MenuAnimation 类代表每个弹出菜单定义的两个菜单动画之一。此类定义了要设置动画的帧数,以及这些帧的布局和修改。由于生成动画可能成本高昂,此类还维护着构建动画的缓存副本,形式为 FrameCollection 实例。当设置更改会产生不同的动画时,需要清除此副本。

IFrameLayoutManager 接口描述了能够为菜单动画中的每一帧定义布局的对象。此接口有许多内置实现,也可以使用自定义实现。

类似地,实现 IFrameModifier 接口的对象用于在菜单动画中提供“特殊效果”。与布局管理器不同,帧修改器不应用于动画的最终帧。因此,它们应该产生一个逐渐移向正常图像状态的效果。与布局管理器一样,CircularMenu.dll 程序集中内置了许多默认实现。

菜单动画有两种:向前和向后。每种类型都使用布局管理器和帧修改器,但它们的帧渲染顺序不同。

ForwardMenuAnimation 从索引零开始渲染帧,并向前移动到最高索引,而 ReverseMenuAnimation 从最高帧索引开始渲染,并在零处结束。这些实例分别产生 ForwardFrameCollectionReverseFrameCollection。通常,向前动画将用于弹出窗口的打开,而向后动画将用于弹出窗口的关闭。为了保持库的灵活性,此约定并未强制执行。

每个 FrameCollection 实例都是一个不可变的、完全渲染的动画。MenuAnimation 实例中缓存的动画是此类子类型之一的对象。创建帧集合时,将为新实例提供一组要渲染的菜单选项、菜单半径、布局管理器和帧修改器。然后,对象的构造函数将继续渲染帧,应用它所提供的布局和修改。请注意,FrameCollection 类并非设计为 CircularMenu.dll 程序集之外的对象的超类。

库文档

本文提供的源文件包含一套全面的文档,这些文档是从 C# XML 注释中使用 nDoc 渲染的。它们比本文档更详细地描述了架构和选项。提供的安装程序项目会将文档集添加到 Visual Studio 中,以便在使用圆形菜单的应用程序创作时可以使用帮助。

修订历史

2005.01.25:

重写了动画线程以使用 Control.Invoke,而不是直接从单独的线程调用控件上的方法。特别感谢在文章中发表评论的成员,尤其是 DrewS,他指出了解决方案。这个问题在我使用的任何机器上都没有出现——如果它最终还是不起作用,请告诉我。

此外,还添加了构建安装程序所需的文件。这使得 ZIP 文件稍微大了一些,希望没人介意 :)

© . All rights reserved.