-
Notifications
You must be signed in to change notification settings - Fork 26
06. TreeWalker
A TreeWalker is used to "walk" the UIA tree step by step in any direction by giving it a starting point element and a condition for selecting elements.
UIA_Interface.TreeWalkerTrue matches every element, so should return the closest one.
UIA_Interface.RawViewWalker matches all UIAutomation elements and if functionally equivalent to TreeWalkerTrue. The only difference is that TreeWalkerTrue can be accessed faster, without a DllCall.
UIA_Interface.ControlViewWalker matches only elements that are controls.
UIA_Interface.ControlViewWalker matches only elements that contain content.
UIA_Interface.CreateTreeWalker(condition) takes in a condition and returns a new UIA_TreeWalker object.
UIA_TreeWalker.Condition returns the condition the TreeWalker was created with.
UIA_TreeWalker.GetParentElement(e) takes an element e and returns the parent element (using the condition the TreeWalker was created with).
UIA_TreeWalker.GetFirstChildElement(e) takes an element e and returns the first child element (using the condition the TreeWalker was created with).
UIA_TreeWalker.GetLastChildElement(e) takes an element e and returns the last child element (using the condition the TreeWalker was created with).
UIA_TreeWalker.GetNextSiblingElement(e) takes an element e and returns the next sibling element (using the condition the TreeWalker was created with).
UIA_TreeWalker.GetPreviousSiblingElement(e) takes an element e and returns the previous sibling element (using the condition the TreeWalker was created with).
UIA_TreeWalker.NormalizeElement(e) takes an element e and first checks if e matches the condition, otherwise returns the first parent element that matches the condition. The difference between this and GetParentElement is that NormalizeElement may return the original element as well.
A TreeWalker can be used multiple times. For example to get the second sibling, use UIA_TreeWalker.GetNextSiblingElement(UIA_TreeWalker.GetNextSiblingElement(e))
.
If getting the next/previous/parent element, then using TreeWalkers is easy enough. But when trying to access elements that are further away, for example the 4th sibling element, it can get quite cumbersome. You would either need to loop the TreeWalker call, or nest the methods. To solve this issue, UIA_Element.FindByPath may be used:
FindByPath(searchPath="", c="") FindByPath gets an element by a relative "path" from a starting element.
To get the nth child of the starting element, set searchPath to "n". To get a deeper node, separate the numbers with a ".": "2.1" will get the second childs first child. This kind of path can easily be got from the UIA_Element.DumpAll() method, which returns a path in the same style (this is like the Acc path but for UIA, they are not compatible!).
To get the nth parent of the starting element, use "Pn": "P2" will get the parent of the parent.
To get sibling elements, put a "+" or "-" in front of "n": +2 will get the next sibling from the next sibling (calling GetNextSiblingElement twice). Using this after "Pn" doesn't require a "." separator ("P2.-1" == "P2-1").
These conditions can also be combined: searchPath="P1-1.1.1.2" -> gets the parent element, then the previous sibling element of the parent, and then "1.1.2" gets the second child of the first childs first child.
c or condition argument can be used to only filter elements specified by the condition: UIA_Element.FindByPath("+2", UIA_Interface.CreateCondition("ControlType", "Button")) will only consider "Button" controls and gets the second sibling button.
With FindByPath we can use element.FindByPath("+4")
to get the fourth next sibling, element.FindByPath("-2")
to get the second previous sibling, element.FindByPath("P2")
the parent of the parent.
Using TreeWalkerTrue to get the next sibling element.
#Include <UIA_Interface>
UIA := UIA_Interface() ; Initialize UIA interface
Run, notepad.exe
WinWaitActive, ahk_exe notepad.exe
npEl := UIA.ElementFromHandle(WinExist("ahk_exe notepad.exe")) ; Get the element for the Notepad window
editEl := npEl.FindFirstByName("Edit") ; Should return the "Edit" menuitem
MsgBox, % "Next sibling from ""Edit"" menu item: " UIA.TreeWalkerTrue.GetNextSiblingElement(editEl).Dump()
ExitApp