Use menu with different handlers? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 05:43

Hi all, I am trying to wrap my mind around something that I think should be easy but I can't figure out.

I'd like to have a menu to select a file in a folder hierarchy, so that I can use it for different purposes. For example, I could want to add text to a file, or run it, or just display its contents.

Now, there are several functions in these forums and elsewhere that will do a directory walk and construct a menu for you -- but they all seem to be tied to a particular thing that you'd do with the files. For example, QuickLinks and FolderMenu will run the selected file, while FavFolders will open the folder in a Windows dialog. None of them is a general-purpose directory walker.

And this is the issue: I can't see ANY way to make a general-purpose directory walker with an AHK menu. Because as far as I can understand, you provide the handler when you create the menu or menu item.

What I need is a way to create a menu, but not give it a handler, so that I can use it afterwards by "passing" a handler to it. For example, I'd have a menu constructed from a folder tree, that I could use to run files OR display them OR add content to them, depending on where I'm calling it from. The FolderMenu() function would be ideal for it... but I would need to have a slightly different function for each thing I want to do, only varying in the handler part.

Is this even possible? Or are AHK menus always tied to a particular handler?

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 06:18

Code: Select all

dir = %A_ScriptDir%\t
Loop, Files, %dir%\*.pdf
 Menu, files, Add, %A_LoopFileName%, Handle

F3::
handler = 1
Gosub, Show
Return

F4::
handler = 2
Show:
Menu, files, Show
Return

Handle:
Switch handler {
 Case 1: MsgBox, 64, Happy, %A_ThisMenuItem%
 Case 2: MsgBox, 48, Sad  , %A_ThisMenuItem%
}
Return

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 07:57

Thank you! That is a workaround. There is still one handler, though -- one that I'd have to patch every time I want to implement new functionality. A directory walker function is quite complex (because it's recursive) and general at the same time. It's a function that you shouldn't have to be modifying constantly.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 08:07

Well, yes, when you want new functionality, you will (typically) need to modify your script! :)

There is no need to alter the loop, unless you need a different one.

The script is not a workaround. It provides a way for one subroutine to do multiple things, according to a condition.

The file walk and the menu handler remain independent.
Last edited by mikeyww on 13 Aug 2022, 08:12, edited 1 time in total.


User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 08:15

An AHK menu is not an object per se. You could build an array of your file names, and then use it as a function parameter, to build a new menu as needed. If your menu is constant, that might be less efficient than the approach shown.

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 08:22

mikeyww wrote:
13 Aug 2022, 08:07
Well, yes, when you want new functionality, you will (typically) need to modify your script! :)
But let's say that you want to distribute the directory walker, just like the authors of the FolderMenu and similar functions did. You can't, without imposing a particular behaviour to the menu. Then it's no longer your script. The user would need to modify it.

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 08:23

Sorry if I'm misunderstanding, but is this not essentially the same thing? You need to hardcode the function name when you build the menu, don't you?

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 08:30

mikeyww wrote:
13 Aug 2022, 08:15
An AHK menu is not an object per se. You could build an array of your file names, and then use it as a function parameter, to build a new menu as needed. If your menu is constant, that might be less efficient than the approach shown.
The problem is not having to build a menu every time. The problem is having to modify the handler when you need different behaviour.

What I'm thinking of is something like this: You have a menu for all .docx files in your documents folder, then you can select one and do stuff as displaying info, copy to a folder, or send by email from different parts of your script, in a modular way, not having to modify the menu building function every time you need to do a new thing. You'd only write the function to do what you need to do.

Pseudocode:

Menu, docs, Call DisplayStats()
Menu, docs, Call CopyToFolder("Work")
Menu, docs, Call SendByEmail()

Actual code: seemingly impossible.

EDIT: Because I forgot to explain that the menu doesn't need to be constant. Because you could also do (pseudocode):

Menu, docs, Call DisplayStats()
Menu, executables, Call DisplayStats()

where you'd be using the same handler function for two different menus, both generated through a generic directory walker.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 08:43

Code: Select all

dir = %A_ScriptDir%\t
Menu, docs, Add, Display
Menu, docs, Add, Copy

F3::Menu, docs, Show

Display:
list =
For each, file in list(dir)
 list .= file "`n"
MsgBox, 64, List, % Trim(list, "`n")
Return

Copy:
For each, file in list(dir)
 FileCopy, %file%, %A_ScriptDir%\t2
MsgBox, 64, Copied, Done!
Return

list(dir) {
 list := []
 Loop, Files, %dir%\*.docx
  list.Push(A_LoopFilePath)
 Return list
}

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 08:48

mikeyww wrote:
13 Aug 2022, 08:43

Code: Select all

dir = %A_ScriptDir%\t
Menu, docs, Add, Display
Menu, docs, Add, Copy

F3::Menu, docs, Show

}
The docs menu in this case would be a menu showing the names of the .doc files in the folder (and subfolders, represented by submenus). You wouldn't add elements to the menu like "Display" and "Copy". You would use the menu to select a particular file.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 08:50

Your description does not match your previous post. You can use the first script that I posted. I am not following why the need is unmet.

The menu is the file list. The handler provides the actions. These are independent. If needed, you can build the menu inside a subroutine or function.

See :arrow: https://www.autohotkey.com/docs/commands/Menu.htm#ExBoundFunc

As you can see, the menu is not rebuilt in the script.

What the script does:
You have a menu for all .docx files in your documents folder, then you can select one and do stuff as displaying info, copy to a folder, or send by email from different parts of your script, in a modular way, not having to modify the menu building function every time you need to do a new thing. You'd only write the function to do what you need to do.

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 09:04

mikeyww wrote:
13 Aug 2022, 08:50
Your description does not match your previous post. You can use the first script that I posted. I am not following why the need is unmet.
I think my description matches my previous post, but I admit my wording might be bad. I'm not a native English speaker.

I'll give you the particular situation I'm in right now.

I have this wonderful, recursive FolderMenu() function that builds a menu from a folder. I want to use that function to add the URL from my current browser's tab to a particular text file in a hierarchy (yes, I'm mirroring the browser's bookmark funcionality). The problem is I would need to modify the function itself (well, its handler) in order to achieve that. The function, as it is written, launches the file you select. I don't want that, so I would have to change it.

But then, if I want to use the function to do some other thing, I would have to add the new behaviour again in the function itself. This is what you did in your first example. It's a workaround, it does the job, but it's unmodular and error prone. Now, the code for doing this thing can't be located in the file I'm using for browser-related stuff anymore -- it needs to be in the file I'm using for general functions, such as a directory walker. If I add code for processing Word docs, it won't be together with the other code I wrote for Word stuff -- it will be in the helper function. And so on.

The function and the handler aren't independent. And it looks like they CAN'T be.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 09:13

Does this help?

Code: Select all

F3::handler(A_ScriptDir "\t", "display")
F4::handler(A_ScriptDir "\t", "copy")

handler(dir, action) {
 Static fileList := []
 If !fileList.Count() {
  Loop, Files, %dir%\*.docx
   fileList.Push(A_LoopFilePath)
  For each, file in fileList
   Menu, files, Add, %file%, Handle
 }
 Menu, files, Show
 Return
 Handle:
 Switch action {
  Case "display": MsgBox, 64, Happy, %A_ThisMenuItem%
  Case "copy"   : MsgBox, 48, Sad  , %A_ThisMenuItem%
 }
 Return
}
This is not a properly functional function, as it is set up for only one directory as a demonstration, but it could be modified.

As I mentioned, a menu is not an object, and I believe that if you want a function to have a different action, then the function would need to be modified, though a function could act upon an object that is passed to it as a parameter.
Last edited by mikeyww on 13 Aug 2022, 09:19, edited 1 time in total.

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 13 Aug 2022, 09:19

mikeyww wrote:
13 Aug 2022, 09:13
Does this help?
Unless I'm misunderstanding, no, because you just replaced the function I want to use (FolderMenu()) with a non-recursive menu building function, but the rest remains the same. I'd still need to put all the logic in the handler (inside every case in the Switch).

Thanks anyway, I think this method will have to do because apparently having a general-purpose menu building function is impossible in AHK.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 13 Aug 2022, 09:20

The function does build the menu, so I must not be following what you actually need to do. Sorry about that.

A function can call another function, but if you want your function to do that, then you would have to indicate it in the function, of course.

wetware05
Posts: 750
Joined: 04 Dec 2020, 16:09

Re: Use menu with different handlers?

Post by wetware05 » 13 Aug 2022, 12:16

Hi.

If you share your script maybe it will be better understood what your problem is. A short video would also help. There is a good custom menu program. Built at the beginning —and based on— Autohotkey, called Quick Access Popup https://www.quickaccesspopup.com. Maybe you can adapt it to your needs.

lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Use menu with different handlers?  Topic is solved

Post by lexikos » 13 Aug 2022, 23:10

elbitjusticiero wrote:
13 Aug 2022, 08:23
You need to hardcode the function name when you build the menu, don't you?
No, there is no need to hardcode the function name. As with the parameters of every other command, the LabelOrSubmenu parameter can be a variable or % expression.

In other words, write a function to build the menu. Let that function have a parameter which specifies the handler function. When you call the menu-building function, you specify which function to call when a menu item is selected.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Use menu with different handlers?

Post by mikeyww » 14 Aug 2022, 04:34

One example is below. It's a variation of my last script, but I'm not sure whether this addresses the original need. In essence, it doesn't do anything that the last script did not do.
If it is not the name of an existing label, LabelOrSubmenu can be the name of a function, or a single variable reference containing a function object.

Code: Select all

F3::handler(A_ScriptDir "\t", "display")
F4::handler(A_ScriptDir "\t", "copy")

handler(dir, action) {
 If !FileExist(dir)
  Return
 Try Menu, files, Delete
 Loop, Files, %dir%\*.docx
  Menu, files, Add, %A_LoopFilePath%, %action%
 Menu, files, Show
}

display(itemName, itemPos, menuName) {
 MsgBox, 64, Happy, %itemName%
}

copy(itemName, itemPos, menuName) {
 MsgBox, 48, Sad  , %itemName%
}

elbitjusticiero
Posts: 75
Joined: 06 May 2017, 11:07

Re: Use menu with different handlers?

Post by elbitjusticiero » 14 Aug 2022, 19:24

lexikos wrote:
13 Aug 2022, 23:10
No, there is no need to hardcode the function name. As with the parameters of every other command, the LabelOrSubmenu parameter can be a variable or % expression.

In other words, write a function to build the menu. Let that function have a parameter which specifies the handler function. When you call the menu-building function, you specify which function to call when a menu item is selected.
You can do that?!?!? Lexikos, that's exactly what I'm looking for.

I think the documentation should be updated to clarify this, because it reads like the only thing you can do is hardcode a literal label name OR a "function object".

Maybe this is why I haven't found a general purpose directory walker. Or maybe I didn't search correctly.

Thank you so much!

Post Reply

Return to “Ask for Help (v1)”