[Help] Dynamically Create Right Click Menu Or Portion

I'm having a brain fart. Any help would be appreciated.

So, I'm working on my first "Skinnable" Widget/Gadget which uses the ImageMagick Com object
to create a reflective PNG. This came about after a request over at Aqua-soft.

My goal is to populate a portion of the right click menu with a list of the skins. At the moment
I'm using a Subfolder Collection to pull all of the Ini file's. Has anyone got an idea on how to
dynamically populate the right click menu with the names & calls?


8,501 views 32 replies
Reply #1 Top
I'm part way there and have cut 300 plus lines of code down to around 40.

Code: vbscript
  1. '--Builds Right Click Menu
  2. Sub rcMenu
  3. Dim submenu,menu
  4. '--Gets Sub Folder Collection
  5. intSize = 0
  6. Set objFSO = CreateObject("Scripting.FileSystemObject")
  7. strFolderName = "C:\Programming\Projects\DesktopX\WIP\Reflector\Reflector\skins"
  8. 'strFolderName = DesktopX.ExecutableDirectory &"\skins"
  9. Set objFSO = CreateObject("Scripting.FileSystemObject")
  10. Set objFolder = objFSO.GetFolder(strFolderName)
  11. Set colSubfolders = objFolder.Subfolders
  12. '--Loads subfolder collection into array
  13. For Each objSubfolder In colSubfolders
  14. strFolderName = objSubfolder.Path
  15. ReDim Preserve arrFolders(intSize)
  16. arrFolders(intSize) = strFolderName
  17. intSize = intSize + 1
  18. Next
  19. '--Builds first part of submenu
  20. Set submenu = DesktopX.CreatePopupMenu
  21. submenu.AppendMenu 0, 1, "About Skin"
  22. submenu.AppendMenu &H00000008, 2, curSkin
  23. submenu.AppendMenu&H00000800,1000,1000 'Menu separator
  24. '--Iterates through subfolder collection & retrievs skin info
  25. For Each strFolder In arrFolders
  26. i = i+1
  27. strname = "skin" & i
  28. 'msgbox strname
  29. pathSkin=strFolder
  30. skin=pathSkin&"\skin.ini"
  31. skinArray=FileToArray(skin, False)
  32. nskin=skinArray(1) '1 Fields Skin Name
  33. posNum=2+i
  34. submenu.AppendMenu 0, posNum, nskin
  35. 'msgbox posNum&nskin
  36. Next
  37. '--Finish building submenu
  38. submenu.AppendMenu&H00000800,1001,1001 'Menu separator
  39. submenu.AppendMenu 0, 13, "Select"
  40. Set menu = DesktopX.CreatePopupMenu
  41. menu.AppendMenu &H00000010, submenu.MenuID, "Skins"
  42. menu.AppendMenu 0, 93, "About"
  43. menu.AppendMenu 0, 98, "Exit"
  44. 'menu.AppendMenu 0, 99, "DesktopX"
  45. Dim rtn
  46. rtn = menu.TrackPopupMenu(0, System.CursorX, System.CursorY)
  47. Select Case rtn
  48. Case 1
  49. Call aboutSkin
  50. Case posNum
  51. 'msgbox posNum
  52. skinPath=pathSkin
  53. Call applySkin(pathSkin,skin)
  54. Case 13
  55. file = System.FileOpenDialog("Select Skin File", "skin.ini", strFolderName, "*.ini|*.ini",0)'--Browse for all file types
  56. Set objFSO = CreateObject("Scripting.FileSystemObject")
  57. fPath=objFSO.GetParentFolderName(file)
  58. iFile= objFSO.GetFileName(file)
  59. skinPath=fPath
  60. Call applySkin(fPath,iFile)
  61. Set objFSO=nothing
  62. Case 93
  63. Call aboutBox
  64. Case 98
  65. DesktopX.Exit(0)
  66. End Select
  67. Set menu = nothing
  68. If rtn <> 99 Then
  69. Object_OnRButtonUp=True
  70. End If
  71. End Sub
Reply #2 Top
Hello... Is anyone out there?
Reply #3 Top
Sorry.. i read this this morning, and didnt see what you were looking for.

YES It can be done, its a pain but it can be done.. let me find the code i used for this in the Holiday Countdown Pro.
Reply #4 Top
Ok, i have to work on this.. let me change some things.. give me about 2hrs
Reply #5 Top
No problem. Thanks.

Sorry for the impatience. I've tried a couple of different things and know I should step away from the code for a bit but, when you're close to being finished it's hard to let it go.
Reply #6 Top
ok, create a new object (for testing this out) Copy/paste the following code into it:
Code: vbscript
  1. 'Called when the script is executed
  2. Dim Item(10)
  3. Sub Object_OnScriptEnter
  4. For x = 1 To 10
  5. Item(x) = "Item " & x
  6. Next
  7. End Sub
  8. 'Called when the script is terminated
  9. Sub Object_OnScriptExit
  10. End Sub
  11. Function PopupMenu()
  12. Set SubMenu = nothing
  13. Set SubMenu = DesktopX.CreatePopupMenu
  14. For x = 1 To 10
  15. SubMenu.AppendMenu 0, x, Item(x)
  16. Next
  17. Set mainmenu = nothing
  18. Set mainmenu = DesktopX.CreatePopupMenu '-- Create Main Men
  19. mainmenu.AppendMenu &H00000010, SubMenu.MenuID, "Pick an Item..."
  20. mainmenu.AppendMenu &H00000800, 0, ""
  21. mainmenu.AppendMenu 0, 999, "Cancel"
  22. result = mainmenu.TrackPopupMenu(0, System.CursorX, System.CursorY)
  23. If result > 1 And result < 999 Then
  24. msgbox "You Selected " & Item(result)
  25. End If
  26. If result = 999 Then MsgBox "You clicked Cancel"
  27. End Function
  28. Function Object_OnLButtonUp(x, y, Dragged)
  29. If Dragged = False Then
  30. Call PopupMenu()
  31. End If
  32. End Function


I'm not sure I'm getting what you are trying to do, because it looks like its doing what i just posted here. Can you show me an example of what you want it to do, and where the data is coming from?
Reply #7 Top
Okay. I think your script just pointed out where I was going wrong.

The array is being built from a the collection of subfolders & redim is used within a For Each statement to add each folder into the array.

Example Folder Structure:

Main Folder
|
|- Skins Folder
|
--------------
| | |
Skin1 Skin2 Skin3

Then I went and put an additional For Each Statement within the submenu structure then forgot to use redim which obviously overwrites the previous variable.


Code: vbscript
  1. '--Gets Sub Folder Collection
  2. intSize = 0
  3. Set objFSO = CreateObject("Scripting.FileSystemObject")
  4. strFolderName = "C:\Programming\Projects\DesktopX\WIP\Reflector\Reflector\skins"
  5. 'strFolderName = DesktopX.ExecutableDirectory &"\skins"
  6. Set objFSO = CreateObject("Scripting.FileSystemObject")
  7. Set objFolder = objFSO.GetFolder(strFolderName)
  8. Set colSubfolders = objFolder.Subfolders
  9. '--Loads subfolder collection into array
  10. For Each objSubfolder In colSubfolders
  11. strFolderName = objSubfolder.Path
  12. ReDim Preserve arrFolders(intSize)
  13. arrFolders(intSize) = strFolderName
  14. intSize = intSize + 1
  15. Next
  16. 'This is the For Each Statement from within the submenu
  17. For Each strFolder In arrFolders
  18. i = i+1
  19. strname = "skin" & i
  20. 'msgbox strname
  21. pathSkin=strFolder
  22. skin=pathSkin&"\skin.ini"
  23. skinArray=FileToArray(skin, False)
  24. nskin=skinArray(1) '1 Fields Skin Name
  25. posNum=2+i
  26. submenu.AppendMenu 0, posNum, nskin
  27. 'msgbox posNum&nskin
  28. Next
Reply #8 Top
So, its working?
Reply #10 Top
It's getting there. I've nested an array within an array. In simple terms what I'm trying to accomplish.

1. Get all skin subfolders into array. Done
2. Pull each skin.ini path into an array. Done
3. Pull the skin names from second line (variable1) of the skin.ini file into another array for display in the right click menu. Done
4. Build the right click menu. On clicking the skin name calls skin.ini into the applyskin sub & automatically updates the default settings file. Still working on this.
Reply #11 Top
Ok, so.. the part you needed help with is done?
Reply #12 Top
It would take a lot more than one thread to help me out!

Much appreciated. This got me going in the right direction.
I'll probably just upload it as a gadget & the object since I'm building it as a gadget. So, you'll be able to see what I'm trying to accomplish.
Reply #13 Top
Let me know if i can help more (email works)
Reply #14 Top
This is interesting. I was doing something like this for a skinnable clock. Wouldn't it be easier to retrieve all the information and set the arrays in a separate sub on startup and any time the information changes instead of in the r-click function?
Reply #15 Top
I use this same setup for the Holiday Countdown Pro, and i read things into a recordset, this works great for me because i can use it like a temporary database. I read the info into the recordset at the beginning of the program. Then any time i need to update/edit/add i can modify the recordset, then with the right-click it reads the recordset as a loop (like above).

It could easily be setup to read the entire ini and all info at startup (or at a set interval in case of updates). Then read that into the menu.
Reply #16 Top

It could easily be setup to read the entire ini and all info at startup (or at a set interval in case of updates). Then read that into the menu.


Yeah, that's what I was doing. I just wondered if there were any benefits to retreiving the info on r-click instead. This is the r-click code I used for it:

Code: vbscript
  1. Function PopupMenu()
  2. Dim submenu
  3. Set mainmenu = nothing
  4. Set mainmenu = DesktopX.CreatePopupMenu '-- Create Main Menu
  5. Set submenu = DesktopX.CreatePopupMenu
  6. mainmenu.AppendMenu 0, 1, "Save Skin"
  7. mainmenu.AppendMenu &H00000010, submenu.MenuID, "Load Skin"
  8. mainmenu.AppendMenu &H00000800, 9998, ""
  9. mainmenu.AppendMenu 0, 2, "Minimize to Tray"
  10. mainmenu.AppendMenu 0, 3, "Close"
  11. mainmenu.AppendMenu &H00000800, 9999, ""
  12. mainmenu.AppendMenu 0, 4, "Preference"
  13. mainmenu.AppendMenu 0, 5, "About"
  14. 'Skins submenu
  15. For x = 0 To skincount
  16. submenu.AppendMenu 0, x+5, skinArr(x)
  17. Next
  18. '-- Save the results of mouse movements
  19. result = mainmenu.TrackPopupMenu(0, System.CursorX, System.CursorY)
  20. Select Case result
  21. Case 1
  22. savePrompt
  23. Case 2
  24. widget.Minimize
  25. Case 3
  26. widget.Close
  27. Case 4
  28. widget.OpenProperties
  29. Case 5
  30. msgbox "My about box"
  31. End Select
  32. If result > 5 Then
  33. selectskin = skinArr(result-6)
  34. Call loadSkin(2, selectskin)
  35. End If
  36. End Function


loadSkin is the sub that retrieves all the info (current skin, skin titles) on startup and when the user loads a skin.
Reply #17 Top
Actually, I did put it into a sub.

Not only is it easier you'll find it runs up the RAM if you put it into the right click since it calls the code every time you initiate the right click menu.

RomanDA, that's a great idea. It also is probably easier on resources & maybe less likely to break the code with repeated FSO calls?

I've created one little glitch. If you click the right click menu then don't click a menu item (ie. close the menu) for some reason it automatically calls/applies the first skin in the list. Haven't given much work into this but, I'm wondering if it's not related to the fact that I've made the For Next statement's zero based?
Reply #18 Top
sViz, your code always looks so clean.

I feel embarrassed to show mine.
Reply #19 Top
Thanks, SirS. I get all confused if I don't format my codes and comment the heck out of them.

I feel embarrassed to show mine.


But, but, if you don't, then who will I snag all these useful codes snippets from?! I always learn something new from studying your scripts.


If you click the right click menu then don't click a menu item (ie. close the menu) for some reason it automatically calls/applies the first skin in the list.


What about using Case Else? Like:

Case Else
object.state = object.state

I used that once when I was having trouble with closing the menu.



Reply #20 Top
Thanks sViz.
But, but, if you don't, then who will I snag all these useful codes snippets from?! I always learn something new from studying your scripts.


I find the same from your. Your Script Helper saves me a great deal of time.

Reply #21 Top
this looks good.. i was going to say the issue is a
CASE ELSE as well.
good one!
Reply #22 Top
Wouldn't that be essentially the same as an IF THEN ELSE statement? Because that didn't work...and apparently neither does the CASE ELSE.

I'm thinking it's most likely using the zero based array? Even though there's nothing specific in the DX documentation most likely zero is a default? So, I'll work on adjusting my arrays accordingly.
Reply #23 Top
That was it or a combination of it with the CASE ELSE.

So class the lesson for the day is, when dynamically creating a right click menu one can't use a zero based array!

Thanks a lot for all the help guys.
Reply #24 Top
So class the lesson for the day is, when dynamically creating a right click menu one can't use a zero based array!


   Glad to hear you worked it out. I'll certainly keep this in mind in future.