Sometimes We Resort to Programming Trickery to Make Autohotkey Menus Look Better
The Windows Menu control is part of the Windows operating system. AutoHotkey offers you the Menu command for setting up and altering custom menus using this built-in control. However, much of the inflexibility of AutoHotkey menus results from the limitations of the Windows Menu object itself. This rigidity often forces us to resort to programming sleight-of-hand to accomplish many goals.
The Limitations of AutoHotkey Menus
The AutoHotkey Menu command stores three primary data units:
Menu, MenuName, Add , MenuItemName, LabelOrSubmenu, Options
When selecting an option from a menu, AutoHotkey provides three pieces of data:
The built-in variables A_ThisMenuItem and A_ThisMenuItemPos contain the name and position of the custom menu item most recently selected by the user (blank if none). Similarly, A_ThisMenu is the name of the menu from which A_ThisMenuItem was selected. These variables are useful when building a menu whose contents are not always the same. In such a case, it is usually best to point all such menu items to the same label and have that label refer to the above variables to determine what action to take.
Unlike other objects (such as GUI pop-up windows) AutoHotkey does not provide options for adding new variables—with the one exception discussed next. That means we must include any data we plan to use after a menu selection in the final menu variables: A_ThisMenuItem, A_ThisMenuItemPos, or A_ThisMenu.
Using Bound Data to Pass Menu Data
The most recent versions (since March 2015) of AutoHotkey allow the use of a function object in place of a Label subroutine or submenu name. This provides an opportunity to pass additional data parameters but involves a slightly higher level of complexity. It’s not as simple as calling a function with new parameters. AutoHotkey must bind each new parameter value to the function and include it in the Menu, Add command using the bound variable:
Handler := Func("NewFunction").Bind("Jim","Spring") Menu, MenuName, Add, MenuItemName, % Handler Menu, MenuName, Show NewFunction(First,Last,ItemName,ItemPos,MenuName) { MsgBox, Hello! %First% %Last% %ItemName% %ItemPos% %MenuName% }
Although useful for passing hidden data upon menu selection, this technique does not help with Menu set up. The online documentation takes a little effort to comprehend but I plan to implement this approach in a future blog to demonstrate a more elegant solution for building Hotstring menus.
Menu Formatting Tricks
Outside of the “functor” discussed above, this shortage of Menu command data options forces us to resort to simple schemes for, first, embedding data in the menu itself, then, second, extracting the data from the standard Menu variables.
In previous blogs, I offered a couple of tricks for embedding data in a menu item:
- Add a single-key shortcut to a menu item that does not appear in the final output (“AutoHotkey Hotstring Menus for Text Replacement Options“).
- Add character descriptions to emoji (and other) menu items that do not appear in the final output (“Hotstring Menu Techniques for Inserting Symbols and Emojis“).
Both of these examples add helpful text (shortcuts and/or description) to a menu item then later removes that extra text after menu selection but before the Hotstring replacement. Much simpler to execute, this next menu trick only requires adding special menu options without affecting output.
One of my favorite Windows tools, I’ve written extensively about assorted ways to use the AutoHotkey Menu command in my various AutoHotkey books.
A Trick for Wrapping Menus
The HotstringMenu.ahk fractions menu shown above (or any other long menu) may seem too long for the computer screen. You might find it more convenient to wrap the menu into shorter columns. In past scripts, I created a counting loop that started a new menu column at regular intervals. For example, when adding columns to the pop-up menus in the SynonymLookup.ahk script, AutoHotkey started a new column after every twenty menu items.
However, for the fractions menu, I decide to choose the spot where I wanted to break the menu columns. I placed a break keyword (“Brk”) at the appropriate spot in the data array:
FractionsA := {⅒: "one-tenth",⅑: "one-ninth" ,⅛: "one-eight",⅐: "one-seventh" ,⅙: "one-sixth Brk",⅕: "one-fifth" ,¼: "one-fourth",⅓: "one-third Brk" ,⅜: "three-eights",⅖: "two-fifths" ,½: "one-half",⅗: "three-fifths" ,⅝: "five-eights",⅔: "two-thirds" ,¾: "three-fourths",⅘: "four-fifths" ,⅚: "five-sixths",⅞: "seven-eights"}
The three-letter keyword “Brk” tells AutoHotkey to add the option +BarBreak to the menu item to force a new column.
Note: The placement of the keyword “Brk” appears random in the above array but the location represents the appropriate spot after sorting the associative array when using the For Key, Value in Expression command. The following code uses the values from the For Each, Item in MenuArray form of the command:
If (InStr(Item,"Brk")) ; Add column breaks to long menus Menu, MyMenu, Add, % Each " | " StrReplace(Item,"Brk") , % Handle, +BarBreak Else Menu, MyMenu, Add, % Each " | " Item, % Handle
The script starts a new column when it detects “Brk” in the menu item text then strips out that keyword while inserting the menu item text.
Go to the HotstringMenu.ahk script to view the code in context.
You can use this trick to key almost any conditional change to a menu or menu item.
Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)
This post was proofread by Grammarly
(Any other mistakes are all mine.)
(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)
[…] of various AutoHotkey Menu tricks expanded to using arrays in the variadic function parameter. Last time, I briefly mentioned using the BoundFunc Object in menus as a possible alternative technique to […]
LikeLike