Menu/MenuBar 对象

提供创建和修改菜单或菜单栏, 添加和修改菜单项目, 检索菜单或菜单栏信息的接口.

class Menu extends Object

菜单对象用于定义, 修改和显示弹出菜单. Menu(), MenuFromHandleA_TrayMenu 返回此类对象.

class MenuBar extends Menu

MenuBar 对象用于定义和修改与 Gui.MenuBar 一起使用的菜单栏. 它们是使用 MenuBar() 创建的. 如果给定菜单栏句柄, 则 MenuFromHandle 返回此类型的对象.

下面使用 "MyMenu" 作为任何 Menu 对象的占位符, 因为 "Menu" 就是类本身.

除了从 Object 继承的方法和属性外, Menu 对象还具有以下预定义的方法和属性.

目录

静态方法

Call

创建新的 Menu 或 MenuBar 对象.

MyMenu := Menu()
MyMenuBar := MenuBar()
MyMenu := Menu.Call()
MyMenuBar := MenuBar.Call()

Add

添加或修改菜单项.

MyMenu.Add(MenuItemName, CallbackOrSubmenu, Options)

参数

MenuItemName

类型: 字符串

要显示在菜单项上的文字, 或者要修改的现有项的位置&. 请参阅 MenuItemName.

CallbackOrSubmenu

类型: 函数对象Menu

选择菜单项或作为子菜单使用的 Menu 对象引用时, 函数作为新线程被调用.

在创建新项目时需要此参数, 但在更新现有项目选项时可选.

回调接受三个参数, 可以定义如下:

MyCallback(ItemName, ItemPos, MyMenu) { ...

虽然你给参数的名字并不重要, 但是下面的值会依次赋值给它们:

  1. 菜单项的名称.
  2. 菜单项的位置编号.
  3. 添加菜单项的 Menu 对象.

如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

Options

类型: 字符串

如果为空或省略, 则默认为无选项. 否则, 从下面的列表中指定一个或多个选项(不区分大小写). 用空格或制表符将每个选项与下一个选项分开. 若要删除某个选项, 请在其前面加一个减号. 要添加一个选项, 可以使用加号, 但不是必需的.

Pn: 指定 n 为菜单项的线程优先级, 例如 P1. 如果在添加菜单项时省略该选项, 优先级将为 0, 这是标准的默认值. 如果在更新菜单项时省略该选项, 则该项目的优先级将不会改变. 请使用十进制(不是十六进制) 数字作为优先级.

Radio: 如果该项目被选中, 则使用个空心圆代替复选标记.

Right: 该项目在菜单栏内右对齐. 这只适用于菜单栏, 不适用于弹出式菜单或子菜单.

Break: 该项在弹出式菜单中开始一个新的列.

BarBreak: 同上, 但在列之间有一条分界线.

要改变一个现有项目的选项而不影响它的回调或子菜单, 只需省略 CallbackOrSubmenu 参数.

要添加菜单分隔线, 请省略所有三个参数.

备注

这是一个多用途的方法, 它可以添加一个菜单项, 用新的子菜单或回调更新一个菜单项, 或者将一个菜单项从普通项转换为子菜单(反之亦然). 如果 MenuItemName 还不存在, 它将被添加到菜单中. 否则, 将用新指定的 CallbackOrSubmenu 和/或 Options 更新 MenuItemName.

Add 总是在菜单底部添加新的菜单项, 但 Insert 可以用来在现有的自定义菜单项之前插入一个项目.

此方法总是在菜单底部添加新的菜单项, 而 Insert 方法可用于在现有自定义菜单项之前插入一个项目.

AddStandard

添加标准的托盘菜单项.

MyMenu.AddStandard()

此方法可以与托盘菜单或任何其他菜单一起使用.

标准项目被插入到任何现有项目之后. 任何已经在菜单中的标准项不会被重复, 但任何缺失的项目会被添加. 下表显示了在空菜单上调用 AddStandard 后标准项的名称和位置:

&Open10
&Help2
3
&Window Spy4
&Reload Script5
&Edit Script6
7
&Suspend Hotkeys81
&Pause Script92
E&xit103

编译后的脚本默认只包含最后三个. 只有在 A_AllowMainWindow 为 1 时, 调用 AddStandard 才会包含 &Open(在这种情况下, 在第三列显示的位置上加 1). 如果托盘菜单中包含标准项目, 每当改变 A_AllowMainWindow 时, 就会插入或移除 &Open. 对于其他菜单, 如果 A_AllowMainWindow 为 0, 则 &Open 没有效果.

每个标准项都有一个内部的菜单项 ID, 与它所执行的功能相对应, 但也可以像其他菜单项一样被修改或删除. AddStandard 通过 ID 而不是名称来检测现有的项目. 如果使用 Add 方法来改变与标准菜单项相关联的回调函数, 那么它将被分配一个新的唯一 ID, 并且不再被认为是一个标准项.

&Open 项添加到托盘菜单中会导致它成为默认项, 如果还没有的话.

Check

在菜单项旁边添加一个可见的复选标记(如果还没有).

MyMenu.Check(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Delete

删除一个或所有菜单项.

MyMenu.Delete(MenuItemName)

参数

MenuItemName

类型: 字符串

如果省略, 则所有项目都会从菜单中删除, 使菜单为空. 否则, 请指定菜单项的名称或位置. 请参阅 MenuItemName.

备注

空菜单仍然存在, 因此, 任何使用它作为子菜单的其他菜单将保留这些子菜单.

要删除一个分隔线, 请通过它在菜单中的位置来识别它. 例如, 如果分隔符前面有两个项目, 则使用 MyMenu.Delete("3&").

如果删除了 default 菜单项, 其效果将类似于设置了 Menu.Default := "".

Disable

将菜单项改为灰色, 以指示用户无法选择它.

MyMenu.Disable(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Enable

允许用户再次选择菜单项, 如果它之前被禁用(灰色).

MyMenu.Enable(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Insert

在指定的项之前插入一个新项.

MyMenu.Insert(MenuItemName, ItemToInsert, CallbackOrSubmenu, Options)

参数

MenuItemName

类型: 字符串

如果为空或省略, ItemToInsert 将被添加到菜单的底部. 否则, 指定现有自定义菜单项的名称或位置, ItemToInsert 应插入到该菜单项之前. 请参阅 MenuItemName.

ItemToInsert

类型: 字符串

要在 MenuItemName 之前插入的新菜单项的名称. 与 Add 方法不同的是, 即使 ItemToInsert 与现有项目的名称一致, 也始终会创建一个新项目.

CallbackOrSubmenu

请参阅 Add 方法的 CallbackOrSubmenu 参数.

Options

请参阅 Add 方法的 Options 参数.

备注

要在现有自定义菜单项之前插入菜单分隔线, 请省略除 MenuItemName 以外的所有参数. 要在菜单底部添加菜单分隔线, 请省略所有参数.

Rename

重命名菜单项.

MyMenu.Rename(MenuItemName , NewName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

NewName

类型: 字符串

如果为空或省略, MenuItemName 将被转换为分隔线. 否则, 请指定新的名称.

备注

菜单项的当前回调或子菜单不变.

通过指定分隔线的位置, 如为 MenuItemName 指定 "1&" 和给 NewName 指定一个非空白名称, 然后使用 Add 方法给项目一个回调或子菜单, 可以将分隔线转换为一个普通项目.

SetColor

改变菜单的背景颜色.

MyMenu.SetColor(ColorValue, ApplyToSubmenus)

参数

ColorValue

类型: 字符串整数

16 种主要的 HTML 颜色名称之一, 十六进制的 RGB 颜色字符串(0x 前缀是可选的), 或一个纯数字 RGB 颜色值. 省略 ColorValue(或指定一个空字符串或单词 "Default") 来恢复菜单的默认颜色. 示例值: "Silver", "FFFFAA", 0xFFFFAA, "Default".

ApplyToSubmenus

类型: 布尔值

如果省略, 则默认为 true.

如果为 true, 颜色将应用于这个菜单的所有子菜单.

如果为 false, 颜色将只应用于菜单.

SetIcon

设置显示在菜单项旁边的图标.

MyMenu.SetIcon(MenuItemName, FileName , IconNumber, IconWidth)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

FileName

类型: 字符串

图标或图像文件的路径, 或位图或图标句柄, 如, "HICON:" handle. 关于支持的格式列表, 请参阅 Picture 控件.

指定一个空字符串或 "*" 来删除该项的当前图标.

IconNumber

类型: 整数

如果省略, 则默认为 1(第一个图标组). 否则, 请在文件中指定要使用的图标组的编号. 例如, MyMenu.SetIcon(MenuItemName, "Shell32.dll", 2) 将使用第二个图标组中的默认图标. 如果为负数, 则假定其绝对值为可执行文件中图标的资源 ID.

IconWidth

类型: 整数

如果省略, 则默认为操作系统推荐的小图标宽度(通常为 16 像素). 如果为 0, 则使用原始宽度. 否则, 指定图标所需的宽度(以像素为单位). 如果 IconNumber 表示的图标组包含多个图标大小, 则使用最接近的匹配, 并将图标缩放到指定的大小.

备注

目前, 在设置图标时需要指定 "实际大小" 以保持透明度, 例如 MyMenu.SetIcon(MenuItemName, "Filename.png",, 0).

Show

显示菜单.

MyMenu.Show(X, Y)

参数

X, Y

类型: 整数

如果省略, 菜单将显示在鼠标光标附近. 否则, 指定显示菜单左上角的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非使用 CoordModeA_CoordModeMenu 覆盖.

备注

显示菜单允许用户使用方向键, 菜单快捷方式(带下划线的字母)或鼠标选择项目.

任何弹出式菜单都可以被显示, 包括子菜单和托盘菜单. 但是, 如果 MyMenu 是 MenuBar 对象, 则抛出异常.

ToggleCheck

如果没有复选标记, 则添加; 否则, 就移除.

MyMenu.ToggleCheck(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

ToggleEnable

如果之前已经启用, 则禁用菜单项; 否则启用.

MyMenu.ToggleEnable(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Uncheck

移除菜单项上的复选标记(如果有的话).

Menu.Uncheck(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

属性

ClickCount

检索或设置必须点击多少次托盘图标才能选择其默认菜单项.

CurrentCount := MyMenu.ClickCount
MyMenu.ClickCount := NewCount

如果已经赋值, CurrentCountNewCount, 否则默认为 2.

NewCount 为 1, 允许单次点击选择托盘菜单的默认菜单项. 指定 2 可返回默认行为(双击). 任何其他值都是无效的, 并抛出异常.

Default

检索或设置默认菜单项.

CurrentDefault := MyMenu.Default
MyMenu.Default := MenuItemName

CurrentDefault 是默认菜单项的名称, 如果没有默认项, 则为空字符串.

MenuItemName 是菜单项的名称或位置. 请参阅 MenuItemName. 如果 MenuItemName 是一个空字符串, 则没有默认项.

设置默认项会使该项的字体变粗(在托盘菜单以外的其他菜单中设置默认项目前没有效果). 当用户双击托盘图标时, 其默认的菜单项就会被启动(即使该项目被禁用). 如果没有默认项, 双击没有效果.

托盘菜单的默认项目最初是 &Open, 如果存在的话. 通过调用 AddStandard&Open 添加到托盘菜单中或改变 A_AllowMainWindow 如果没有默认项, 也会使其成为默认项.

如果删除了默认项, 则菜单中没有默认项.

Handle

返回一个 Win32 menu 的句柄(HMENU 类型的句柄), 必要时构造它.

Handle := MyMenu.Handle

返回的句柄只在 Win32 菜单被销毁之前有效, 这通常发生在菜单对象被释放时. 一旦菜单被销毁, 操作系统可以将句柄值重新分配给脚本或任何其他程序随后创建的任何菜单.

菜单项的名称或位置. 一些通用规则适用于所有使用该参数的方法:

要为菜单项名称的某个字母加下划线, 在这个字母前加一个 & 符号. 当菜单显示出来时, 此项可以通过按键盘上对应的按键来选中. 要显示原义的 & 符号, 指定连续的两个 & 号, 如此例所示: "Save && Exit"

当引用到一个已存在的菜单或菜单项时, 其名称不区分大小写但 & 号不能少. 例如: "&Open"

菜单项的名称最多可以有 260 个字符.

要通过菜单中的位置来识别一个现有的项目, 请在项目的位置后写上一个 &. 例如, "1&" 表示第一个项目.

Win32 Menus

Windows 提供了一组函数和通知, 用于创建, 修改和显示具有标准外观和行为的菜单. 我们把由这些函数之一创建的菜单称为 Win32 menu.

当项目被添加到菜单中或修改时, 每个项目的名称和其他属性都存储在 Menu 对象. 当菜单或它的父菜单第一次连接到 GUI 或显示时, 就会构造一个 Win32 menu. 当菜单对象被删除时, 它就会被自动销毁(当它的引用计数达到零时就会发生).

Menu.Handle 返回一个 Win32 menu 的句柄(HMENU 类型的句柄), 必要时构造它.

任何由 Win32 函数直接对菜单进行的修改都不会反映在脚本的 Menu 对象中, 所以如果一个项目被内置方法修改, 可能会丢失.

当每个菜单项第一次被添加到菜单中时, 它被分配了一个 ID. 脚本不能依赖一个项目收到一个特定的 ID, 但是可以通过使用 GetMenuItemID 来检索一个项目的 ID, 如示例 #5 所示. 这个 ID 不能用于 Menu 对象, 但可以用于各种 Win32 函数.

备注

菜单通常看起来像这样:

Menu

如果一个菜单完全变空 -- 比如使用 MyMenu.Delete() -- 它就不能被显示. 如果托盘菜单变成空的, 右击和双击托盘图标将没有任何效果(在这种情况下, 通常最好使用 #NoTrayIcon).

如果一个菜单项的回调已经在运行, 而用户再次选择同一个菜单项, 则会创建一个新的线程来运行同样的回调, 从而中断之前的线程. 如果要把这些事件缓冲到以后, 可以使用 Critical 作为回调的第一行(然而, 这也会缓冲/延迟其他线程, 比如按下热键).

每当通过菜单项调用一个函数时, 它都会以默认值(如 SendMode) 重新开始. 这些默认值可以在脚本启动时更改.

当建立一个内容不总是相同的菜单时, 一种方法是将所有这样的菜单项指向同一个函数, 并让该函数参考它的参数来决定采取什么行动. 另外, 可以使用函数对象, 闭包胖箭头函数将一个或多个值或变量绑定到菜单项的回调函数上.

GUI, 线程, Thread, Critical, #NoTrayIcon, 函数, Return, SetTimer

示例

添加一个新菜单项到托盘图标菜单的底部.

A_TrayMenu.Add()  ; 创建分隔线.
A_TrayMenu.Add("Item1", MenuHandler)  ; 创建新菜单项.
Persistent

MenuHandler(ItemName, ItemPos, MyMenu) {
    MsgBox "You selected " ItemName " (position " ItemPos ")"
}

创建一个弹出菜单, 当用户按下热键时显示.

; 添加一些菜单项来创建弹出菜单.
MyMenu := Menu()
MyMenu.Add("Item 1", MenuHandler)
MyMenu.Add("Item 2", MenuHandler)
MyMenu.Add()  ; 添加分隔线.

; 添加子菜单到上面的菜单中.
Submenu1 := Menu()
Submenu1.Add("Item A", MenuHandler)
Submenu1.Add("Item B", MenuHandler)

; 创建第一个菜单的子菜单(右箭头指示符). 当用户选择它时会显示第二个菜单.
MyMenu.Add("My Submenu", Submenu1)

MyMenu.Add()  ; 在子菜单下添加分隔线.
MyMenu.Add("Item 3", MenuHandler)  ; 在子菜单下添加另一个菜单项.

MenuHandler(Item, *) {
    MsgBox("You selected " Item)
}

#z::MyMenu.Show()  ; 即按下 Win-Z 热键来显示菜单.

演示各种菜单对象成员.

#SingleInstance
Persistent
Tray := A_TrayMenu ; 为了方便.
Tray.Delete() ; 删除标准项目.
Tray.Add() ; 分隔线
Tray.Add("TestToggleCheck", TestToggleCheck)
Tray.Add("TestToggleEnable", TestToggleEnable)
Tray.Add("TestDefault", TestDefault)
Tray.Add("TestAddStandard", TestAddStandard)
Tray.Add("TestDelete", TestDelete)
Tray.Add("TestDeleteAll", TestDeleteAll)
Tray.Add("TestRename", TestRename)
Tray.Add("Test", Test)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TestToggleCheck(*)
{
    Tray.ToggleCheck("TestToggleCheck")
    Tray.Enable("TestToggleEnable") ; 由于自己无法撤销禁用, 所以还能进行下一次测试.
    Tray.add("TestDelete", TestDelete) ; 类似于上面.
}

TestToggleEnable(*)
{
    Tray.ToggleEnable("TestToggleEnable")
}

TestDefault(*)
{
    if Tray.Default = "TestDefault"
        Tray.Default := ""
    else
        Tray.Default := "TestDefault"
}

TestAddStandard(*)
{
    Tray.AddStandard()
}

TestDelete(*)
{
    Tray.Delete("TestDelete")
}

TestDeleteAll(*)
{
    Tray.Delete()
}

TestRename(*)
{
    static OldName := "", NewName := ""
    if NewName != "renamed"
    {
        OldName := "TestRename"
        NewName := "renamed"
    }
    else
    {
        OldName := "renamed"
        NewName := "TestRename"
    }
    Tray.Rename(OldName, NewName)
}

Test(Item, *)
{
    MsgBox("You selected " Item)
}

添加图标到其菜单项.

FileMenu := Menu()
FileMenu.Add("Script Icon", MenuHandler)
FileMenu.Add("Suspend Icon", MenuHandler)
FileMenu.Add("Pause Icon", MenuHandler)
FileMenu.SetIcon("Script Icon", A_AhkPath, 2) ; 使用文件中的第二个图标组
FileMenu.SetIcon("Suspend Icon", A_AhkPath, -206) ; 使用资源标识符 206 表示的图标
FileMenu.SetIcon("Pause Icon", A_AhkPath, -207) ; 使用资源标识符 207 表示的图标
MyMenuBar := MenuBar()
MyMenuBar.Add("&File", FileMenu)
MyGui := Gui()
MyGui.MenuBar := MyMenuBar
MyGui.Add("Button",, "Exit This Example").OnEvent("Click", (*) => WinClose())
MyGui.Show()

MenuHandler(*) {
    ; 在这个例子中, 菜单项没有任何作用.
}

报告菜单中的项目数量和最后一项的 ID.

MyMenu := Menu()
MyMenu.Add("Item 1", NoAction)
MyMenu.Add("Item 2", NoAction)
MyMenu.Add("Item B", NoAction)

; 检索菜单中的项目数.
item_count := DllCall("GetMenuItemCount", "ptr", MyMenu.Handle)

; 检索最后一个项目的 ID.
last_id := DllCall("GetMenuItemID", "ptr", MyMenu.Handle, "int", item_count-1)

MsgBox("MyMenu has " item_count " items, and its last item has ID " last_id)

NoAction(*) {
    ; 什么都不做.
}