AutoHotkey Community

It is currently May 27th, 2012, 8:26 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: February 7th, 2012, 2:23 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
Hey guys and gals, I'm new to the forums and fairly new to AHK. Ive been coding for about two weeks now with the help of the forum and FAQ but seem to have run into a snag. I'm trying to design a Menu that can possibly change everytime a user runs the .exe. I have already decided that the best options would be to use an XML to layout the menu and I have planned on using Titan's xpath to help read and write the XML.

Before I get too far along, I want to make sure my options are feasible. The issue I seem to have run into is that all of the subroutines that get called from a menu have to be declared in the script itself. The only work around for the user changing the menus is to call one Subroutine. This issue with this however, is that how will the subroutine be able to know what information was retrieved from the XML document?

A quick example of this is several blocks of colors that the user can select to click on any number of times. With the help of xpath, the user can save their preferences to the XML document so that the next time they use the menu, they're information is saved. However, I have no idea of how to go about determining if the First option in the menu reads Click Blue x5 or if it says Click Red x5...The User also had the option of inserting their own naming scheme for the menu options.

This brings me to my actual question, I have an array set up to read from the XML and create the menu, but I have to code the subroutines a head of time, there is no way that I can think of that would allow me to tell which menu item was selected.

I don't currently have any code with me but I'm fairly familiar with AHK and the way my code is set up, I can completely rework this, but the menu option has been a huge hit with my friends. I really don't want to use a Gui.

Thank you in advance and I look forward to hearing back from you. I will post some code if needed and as soon as I get a chance.

Edit: I have solved this and the code and example are on page 2. 2/9/12


Last edited by mrplow123456 on February 9th, 2012, 9:27 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 2:26 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
Quick thought I had while typing this, not sure if it's feasible or not. But I know A_ThisMenu and A_ThisMenuItem return the menu information, would I be able to make some sort of dynamic associative array using this coupled with the xpath code to create my desired results?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 3:23 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
Although it's very unusual to do so, AHK allows menu names to contain /slash/ characters. As you traverse your XML to build the menu tree, you can keep track of the full path of the current node's parent and use that as the name of menu.

Then, if each menu item is linked to the same subroutine, A_ThisMenu will reflect most of the path from the original XML (enough to let A_ThisMenuItem or A_ThisMenuItemPos identify the node).

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 3:31 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
Thanks for the very quick reply. I know its sort of an unusual request, but it's basically the best option I've come up with. and essentially you're saying a three tier menu would essentially have three...essentially directories in them?
Something like menu/tier 1/tier 2/menu item5?

If I implemented this correctly, I'd still need to read from the XML document twice, is there anyway I can use an associative array thats been declared globally and add items to them that way so that I only have to access the document to read/write to it? or is it possible to declare global variables anywhere in the script even? Sorry if some of these are obvious questions, I've been working for just over a week straight on this script and my mind is currently mush.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 5:25 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
You can think of each tier like a directory, with each menu name like a folder and each menu item like a file. Since you get to decide on the menu names, why not make the names useful?

I don't see a problem with reading the XML twice. You may be overcomplicating the task by trying to optimize performance. In my experience, anything UI related almost never needs to be 2ms faster.

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 5:31 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
I'm just trying to minimize the processing time the script will require, I know AHK is fairly light weight, especially with the optimizations I've made recently to my script, but maybe I'm over estimating how much it would slow down reading some 300+ entries from an XML document.

And as to the first part of your reply, I will not be getting to determine those values in the final copy, only currently to do testing. Down the road, it is my goal to allow the used to click the same color 10,000 times if they really want to, they can name that macro "I'm Bored" and save it to the submenu "Check this out" or use completely different words, I have no idea.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 5:51 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
I guess I should have clarified: you get to decide how the menu names are constructed, even if you don't know what the pieces are going to be. You can choose a method that is both extensible (allowing variable levels of nesting, or tiers) and uniquely identifies the source of the data.

So, if your XML looked like this:
Code:
<A item="The top">
  <1 item="The middle">
    <x item="Blah"/>
    <y item="Zomg!"/>
  </1>
</A>

Then you would have the top-tier menu named "A" containing one menu item called "The top", which expands the menu "A/1" containing one menu item called "The Middle".

That menu contains two items which are NOT represented by their node names ( "x" and "y" ), but which appear as menu items "Blah" and "Zomg!".

Clicking "Blah" triggers the subroutine, where A_ThisMenu contains "A/1" and A_ThisMenuItem contains "Blah", which should be enough to identify any other data related to it.

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 7th, 2012, 6:08 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
so my menu would look something like...
Code:
Menu, A/1, Add, Zomg!, MenuHandler
Menu, A, Add, The Middle, :A/1
Menu, TopMenu, Add, The top, :A

Would something like that be correct from how you explained it?

Then use xpath to grab and fill in the information as needed? I have yet to use xpath, but I did read the first several pages of the topic so I have a pretty good idea of how it's used.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 8th, 2012, 4:37 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
This is what I've managed to throw together today after I got home

Code:
#Include xpath.ahk

; Check to make sure the XML Document Exists
If (!xpath_load(xml, "Test.xml")) {
   MsgBox, Fail
   xpath_save(xml, "Test.xml")
}

; Create Menu
menuNames := Array()
i := j := k := 0
; Assign pre-parsed menu list
; Top Most Menu
preparsed1 := xpath(xml, "/Menu/@Name/text()")
Loop, Parse, preparsed1, CSV
{
   j := k := 0
   i ++
   menuNames[A_Index, 0, 0] := "/" . A_LoopField
   MsgBox, % menuNames[i,j,k]
   preparsed2 := xpath(xml, "/Menu/Submenu/@Name/text()")
   Loop, Parse, preparsed2, CSV
   {
      k := 0
      j ++
      menuNames[i, A_Index, k] := menuNames[i,0,0] . "/" . A_LoopField
      preparsed3 := xpath(xml, "/Menu/Submenu/SubMenu2/@Name/text()")
      Loop, Parse, preparsed3, CSV
      {
         k ++
         menuNames[i, j, A_Index] := menuNames[i,j,0] . "/" . A_LoopField
         MsgBox, % menuNames[i,j,k]
         Menu, % menuNames[i,j,0], Add, % menuNames[i,j,k], MenuHandler
      }
      holder := menuNames[i,j,0]
      Menu, % menuNames[i,0,0], Add,  % menuNames[i,j,0], ; I can not figure out how to put :menuNames[i,j,0] here
   }
}
MenuHandler:
   MsgBox, Good Job
Return

+RButton::
   ; Show Menu
   Menu, % menuNames[1,0,0], Show
Return


Only issue I'm having is I can't declare submenus for the life of me, I have tried everything that I could think of and it all returns error

I also know believe that I can remove my variables, but I haven't tested it yet. Anyways, Any help?

Thanks


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 8th, 2012, 6:07 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
I think you got your parameters mixed up.
Code:
Menu, % menuNames[i,0,0], Add, % preparsed3, % ":" menuNames[i,j,0]
:?:

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 8th, 2012, 6:19 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
Thanks for the reply, I just figured out that I could do
Code:
Menu, % menuNames[i,0,0], Add, % preparsed3, % ":" menuNames[i,j,0]


But instead of using preparsed, I used A_LoopField. I wasn't able to get the menu to appear, so that was the issue that I ran into. I think my final question now is I have some subsections under one area, but not under the other, how would I use the parser to figure this out without an untold amount of if statements?

Code:
<?xml version="1.0" encoding="UTF-8"?>

<Menu Name="MyMenu">
   <Submenu Name="Preset">
      <Setting Name="Sample" Default="true">
         <Division Number="1" Type="Blue">1</Division>
         <Division Number="2" Type="Green">1</Division>
         <Division Number="3" Type="Red">1</Division>
         <Division Number="4" Type="Yellow">1</Division>
         <Division Number="5" Type="Purple">1</Division>
         <Division Number="6" Type="Black">1</Division>
      </Setting>
      <Setting Name="5 Blue">
         <Division Number="2" Color="Blue">5</Division>
      </Setting>
   </Submenu>
   <Submenu Name="Custom">
      <Submenu2 Level="1">
         <Setting Name="Setting 1">
            <Division Number="1" Color="Green">10</Division>
         </Setting>
      </SubMenu2>
   </Submenu>
</Menu>


Provided a sample of XML to help explain. Essentially, what would be the best way to change my script, or my XML to make the menu appear how it does in the previous code? For example, preset only has items in it, where Custom has submenus as well. Thanks for your help as well. You have allowed me to think well out side the box, and I like it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 8th, 2012, 8:15 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
Well, since you previously set it up as a fixed set of nested loops, if you want to have flexible nest levels, you'll have to use a different approach (e.g: recursion).

For instance, you can traverse the XML linearly and use a stack to hold the paths (menu names) of each node until you're finished building each submenu.

As you build the menu tree, you can effectively add a submenu to its parent before adding items to it by adding a dummy item, then using Menu, <submenuname>, DeleteAll, then adding that menu (which should still exist, despite having no items) to the parent.

Be careful thinking outside the box... you could lose your mind :shock:

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 8th, 2012, 8:21 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
My mind hasn't been here for a while, which is why I feel the need to ask these questions, I have no clue how obvious or far fetched they are anymore. This is a lot different than how C++ was, but at the same time, I like the approach. I have also been a few steps ahead of you on that, but I'm not quite sure how to work it.

As you can see from the XML sample, Custom will have a submenu inside of it where as Preset will not. the only thing I haven't been able to figure out with xpath is how to return a tag and not just the attribute, for example, how do I return the tags for Submenu, Submenu2, and Setting without already assuming they're there...I haven't decided yet, but the user may be able to modify these names/placements/etc.

I've seen recursion used before, but since I'm a little rusty with my coding experience, can you give me a crash course as to what that'd look like?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 9th, 2012, 3:09 am 
Offline

Joined: February 7th, 2012, 2:09 am
Posts: 28
Did some snooping around last night and learned about recursive coding...brought back memories. Anyways, I decided I'd have a go at it, but seems like I've now run into a few problems, again.

Code Sample
Code:
DynamicMenu(name, type, path) {
   If (type = "Item") {      ; type Contained Item
      MsgBox, Menu, %path%, Add, %name%, MenuHandler is being created
      Menu, %path%, Add, %name%, MenuHandler
   } Else {   ; type Contained Submenu
      parseme := xpath(xml, path . "[@Name=" . name . "]/*/@Name/text()")
      Loop, Parse, parseme, CSV
      {
         i := path . "/*" ; Dynamic Path
         j := A_LoopField ; Dynamic Name
         k := xpath(xml, i . "[@Name=" . j . "]/@Type/text()") ; Dynamic Type
         l := DynamicMenu(j,k,i)
         If (type = "Submenu") {
            ; MsgBox, Menu, %path%, Add, %l%, :%path%/* is being created
            Menu, %path%, Add, %l%, % ":" . i
         } Else {
            ; MsgBox, Menu, %name%, Add, %l%, :%path%/* is being created
            Menu, %name%, Add, %l%, % ":" . i
         }
      }
      Return name
   }
}


Everything works fairly well, and I thought it was the right way to go...until my menu smashed all the items into each submenu. I still have not been able to figure out how to get each node using xpath. That seems to be the most pertinent issue and should solve this whole mess.

VxE, I did want to greatly thank you for your patience with me, as well as inspiring me to improve upon what I know. If you could help me one last time to be able to figure out how to get the nodes from xpath, I'd be eternally grateful.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 9th, 2012, 4:39 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
Unfortunately, I know nothing about xpath. Whenever I have to work with XML, I do it using ordinary string manipulation. My table library has one such example.

One way to parse XML (without comments, technically speaking) is using two Loop, Parse e.g:
Code:
Loop, Parse, XML, <
    Loop, Parse, A_LoopField, >, % "`t`n`r "
        If ( A_Index = 1 )
            ; do stuff with the text inside <angle brackets>
        Else
            ; do stuff with the text outside >angle brackets<

That's totally not recursion though. On the other hand, it may help you identify the subnodes that lay on the next nest level.

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Bing [Bot], BrandonHotkey, Google Feedfetcher, immunity, sjc1000 and 76 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group