Tested in Excel 365 (16.0.11601.20184) 64-bit.
When you have a bunch of macros that you use frequently, a menu containing all of them, structured by functionality, would be a great help.
Here is some code that would read any text file (txt, csv etc) and will build your menu when you open Excel. This code needs to be called either on Workbook_Open or in Auto_Open subs.
Also a piece of code will delete the menu when you close Excel. This one needs to be called in either Workbook_BeforeClose or Auto_Close.
While Auto_Open and Auto_Close can be put anywhere, the other two need to be placed on ThisWorkbook (above Modules, expand Microsoft Excel Objects and double-click ThisWorkbook.
- Private Sub Workbook_BeforeClose(Cancel As Boolean)
- DeleteMenu
- End Sub
- Private Sub Workbook_Open()
- CreateMenu
- End Sub
Main code:
- Option Explicit
- Public Const TopLevelMenuName = "MyMacros"
- Public Const ConfigComment = "#"
- Public Const MenuFile = "MyMenu.csv"
- Public Const xlsMenuBar = "Worksheet Menu Bar"
- Sub CreateMenu()
- ' inspired from https://sitestory.dk/excel_vba/user-defined-menu.htm
- ' needs reference to Microsoft Scripting Runtime
- Dim cbMainMenu As CommandBar
- Dim TopLevelMenu As CommandBarControl
- Dim SubMenu As CommandBarControl, tempMenu As CommandBarControl
- Dim MySettings As New Dictionary
- Dim dKey, arrTemp, i
- Set MySettings = GetMenuSettings
- ' Delete the menu if it exists
- On Error Resume Next
- Application.CommandBars(xlsMenuBar).Controls(TopLevelMenuName).Delete
- On Error GoTo 0
- 'Set a CommandBar variable as a Worksheet menu bar
- Set cbMainMenu = Application.CommandBars(xlsMenuBar)
- ' add top level menu
- Set TopLevelMenu = cbMainMenu.Controls.Add(Type:=msoControlPopup)
- TopLevelMenu.Caption = TopLevelMenuName
- ' open the csv settings files and build the menu
- For Each dKey In MySettings
- arrTemp = Split(dKey, ",")
- If dKey <> "Submenu,Caption,OnAction,FaceID" Then
- ' check if submenu exists and add it if not
- On Error Resume Next
- tempMenu = Nothing
- Set tempMenu = TopLevelMenu.Controls(arrTemp(0))
- On Error GoTo 0
- If tempMenu Is Nothing Then
- Set SubMenu = TopLevelMenu.Controls.Add(Type:=msoControlPopup)
- SubMenu.Caption = arrTemp(0)
- Set SubMenu = TopLevelMenu.Controls(arrTemp(0))
- End If
- ' add macro
- With SubMenu.Controls.Add(Type:=msoControlButton)
- .Caption = arrTemp(1)
- .OnAction = arrTemp(2)
- .FaceId = arrTemp(3)
- End With
- Set tempMenu = Nothing
- End If
- Next
- Set TopLevelMenu = Nothing
- Set SubMenu = Nothing
- Set cbMainMenu = Nothing
- Set MySettings = Nothing
- Set tempMenu = Nothing
- End Sub
- Sub DeleteMenu()
- 'Deletes the user defined menu
- ' Application.CommandBars("Worksheet Menu Bar").Reset
- On Error Resume Next
- Application.CommandBars(xlsMenuBar).Controls(TopLevelMenuName).Delete
- End Sub
- Function GetMenuSettings() As Dictionary
- ' needs reference to Microsoft Scripting Runtime
- Dim f, MyDoc
- Dim strFile
- Dim dSettings As New Dictionary
- f = FreeFile
- strFile = ""
- MyDoc = Environ("USERPROFILE") & "\Documents\"
- Open MyDoc & MenuFile For Input As #f
- ' parse the file
- Do Until EOF(f)
- Line Input #f, strFile
- If Left(strFile, 1) <> ConfigComment Then
- ' add to dictionary
- If Not dSettings.Exists(strFile) Then _
- dSettings.Add Trim(strFile), Trim(strFile)
- End If
- Loop
- Close #f
- Set GetMenuSettings = dSettings
- ' discard the dictionary
- Set dSettings = Nothing
- End Function
Settings file example:
- Submenu,Caption,OnAction,FaceID
- # This is a comment
- Main subs,Stats,not_yet,0001
- Grooming,Unhide All Cols And Rows,UnhideAllColsAndRows,0164
- Grooming,Extract URL From Shape,ExtractURLFromShape,0098
- Grooming,Extract URL From Text,ExtractURLFromText,0099
- Grooming,Create Summary sheet,CreateSheetNameLinks,0247
- Tools,Excel Functionalities ON,ExcelFunctionalitiesON,0156
- Tools,List all comments,ListComments,0170
- Tools,List files or folders,ListFilesOrFolders,0085
- Tools,List File properties (no subfolders),ListFileProperties,0188
- Tools,Merge files,MergeExcelTextFiles,1642
- Tools,Copy Files,CopyFiles,0053