Use menu with different handlers? Topic is solved
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Use menu with different handlers?
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?
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?
Re: Use menu with different handlers?
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
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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.
Re: Use menu with different handlers?
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.
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.
Re: Use menu with different handlers?
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.
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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.
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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?
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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.
Re: Use menu with different handlers?
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
}
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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.mikeyww wrote: ↑13 Aug 2022, 08:43Code: Select all
dir = %A_ScriptDir%\t Menu, docs, Add, Display Menu, docs, Add, Copy F3::Menu, docs, Show }
Re: Use menu with different handlers?
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 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:
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 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.
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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.
Re: Use menu with different handlers?
Does this help?
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.
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
}
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.
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
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.
Re: Use menu with different handlers?
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.
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.
Re: Use menu with different handlers?
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.
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.
Re: Use menu with different handlers? Topic is solved
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.elbitjusticiero wrote: ↑13 Aug 2022, 08:23You need to hardcode the function name when you build the menu, don't you?
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.
Re: Use menu with different handlers?
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%
}
-
- Posts: 75
- Joined: 06 May 2017, 11:07
Re: Use menu with different handlers?
You can do that?!?!? Lexikos, that's exactly what I'm looking for.lexikos wrote: ↑13 Aug 2022, 23:10No, 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.
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!