Skip to content

06. TreeWalker

Descolada edited this page Jul 17, 2022 · 1 revision

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.

Getting TreeWalkers

Built-in TreeWalkers

TreeWalkerTrue

UIA_Interface.TreeWalkerTrue matches every element, so should return the closest one.

RawViewWalker

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.

ControlViewWalker

UIA_Interface.ControlViewWalker matches only elements that are controls.

ContentViewWalker

UIA_Interface.ControlViewWalker matches only elements that contain content.

Creating a new TreeWalker

UIA_Interface.CreateTreeWalker(condition) takes in a condition and returns a new UIA_TreeWalker object.

TreeWalker properties

UIA_TreeWalker.Condition returns the condition the TreeWalker was created with.

TreeWalker methods

GetParentElement

UIA_TreeWalker.GetParentElement(e) takes an element e and returns the parent element (using the condition the TreeWalker was created with).

GetFirstChildElement

UIA_TreeWalker.GetFirstChildElement(e) takes an element e and returns the first child element (using the condition the TreeWalker was created with).

GetLastChildElement

UIA_TreeWalker.GetLastChildElement(e) takes an element e and returns the last child element (using the condition the TreeWalker was created with).

GetNextSiblingElement

UIA_TreeWalker.GetNextSiblingElement(e) takes an element e and returns the next sibling element (using the condition the TreeWalker was created with).

GetPreviousSiblingElement

UIA_TreeWalker.GetPreviousSiblingElement(e) takes an element e and returns the previous sibling element (using the condition the TreeWalker was created with).

NormalizeElement

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)).

Easier way

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.

Example

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