Is it possible to store the full path to a UI element (obtained using UI Browser) in a variable, then use that variable later on in a “tell” statement in order to obtain the properties of that UI element?
For example, this script returns null, when attempting to use a UI element path that’s stored in the variable named uiElementPath
:
set uiElementPath to "checkbox 9 of group 1 of window 1"
activate application "DaVinci Resolve"
tell application "System Events"
tell application process "DaVinci Resolve"
set xPos to ""
set yPos to ""
try
tell uiElementPath
set {xPosition, yPosition} to position
set {xSize, ySize} to size
-- modify offsets if hot spot is not centered:
set xPos to xPosition + (xSize div 2)
set yPos to yPosition + (ySize div 2)
end tell
end try
end tell
end tell
return {xPos, yPos}
However, I can get this routine to work as expected if I separate the UI Element index numbers into their own variables, and then build the tell
statement like this:
set uiElementPath_checkbox to 9
set uiElementPath_group to 1
set uiElementPath_window to 1
activate application "DaVinci Resolve"
tell application "System Events"
tell application process "DaVinci Resolve"
set xPos to ""
set yPos to ""
try
tell checkbox uiElementPath_checkbox of group uiElementPath_group of window uiElementPath_window
set {xPosition, yPosition} to position
set {xSize, ySize} to size
-- modify offsets if hot spot is not centered:
set xPos to xPosition + (xSize div 2)
set yPos to yPosition + (ySize div 2)
end tell
end try
end tell
end tell
return {xPos, yPos}
But this is not ideal for the script I’m trying to build, because not all of the UI Element indexes adhere to the same type of hierarchy, and I don’t want to have to manually write tell
statements for every possible permutation of the element paths that exist in the app I’m trying to UI Script. I already have a map of all the UI element paths in a JSON file, and just want to be able to iterate over all the keys in the JSON file and feed the UI Element path value for each key into the AppleScript tell
statement.
I come from a Bash scripting background, so I was hoping there was an AppleScript equivalent to Bash parameter expansion for a scenario like this. But it seems like AppleScript doesn’t work this way? Any advice is greatly appreciated.
Yes, you can store the path to UI elements in references (which essentially delay the normally-transparent resolution of the reference until later in the script). The full keyword is a reference to
, but you can type ref
as shorthand.
I have a couple of complex UI scripts that use references extensively. Here’s a snippet:
tell application "System Events"
-- Determine if Mail should be scripted.
set use_system_settings to true
tell application "Mail" to set mail_active to application "Mail" is frontmost and (count message viewers) > 0
if mail_active then
set mail_sheet_heading to a reference to static text 1 of sheet 1 of window 1 of application process "Mail"
set mail_sheet_exists to (exists mail_sheet_heading) and value of mail_sheet_heading contains "Enter the password for the account"
if not mail_sheet_exists then
set account_row to a reference to (first row of outline 1 of scroll area 1 of splitter group 1 of window 1 of application process "Mail" where (value of static text 1 of its UI element 1 is account_name and value of its attribute "AXDisclosureLevel" is 0)) -- Main heading (not the inbox).
set connect_button to a reference to (first button of UI element 1 of account_row whose description is "disconnect")
-- Check if connect button exists.
set connect_button_exists to exists connect_button
if not connect_button_exists then
-- Attempt to display the connect button.
tell application "Mail" to check for new mail for account account_name
set connect_button_exists to SL's waitUntilUIElementExists(connect_button, 3, 0.1)
end if
-- Attempt to trigger sheet.
if connect_button_exists then
click connect_button
set mail_sheet_exists to SL's waitUntilUIElementAttributeContains(a reference to value of mail_sheet_heading, 10, 0.1, "Enter the password for the account")
end if
end if
-- Determine whether to use Mail or System Settings.
set use_system_settings to not mail_sheet_exists
end if
if use_system_settings then
set target_process to "System Settings"
tell application "System Settings"
-- Get application state & activate Internet Accounts pane.
set was_running to running
activate
if not was_running or current pane is missing value then
set previous_pane_id to missing value
else
set previous_pane_id to id of current pane
end if
set internet_accounts_pane_was_selected to previous_pane_id is internet_accounts_pane_id
if not internet_accounts_pane_was_selected then reveal pane id internet_accounts_pane_id
delay 0.1
end tell
else -- Using Mail directly.
set target_process to "Mail"
end if
-- Script either System Settings or Mail.
tell process target_process
set sheet_heading to a reference to static text 1 of sheet 1 of window 1
set web_form_scroll_area to a reference to scroll area 1 of group 1 of group 1 of group 1 of sheet 1 of window 1
set web_form_group to a reference to group 2 of UI element 1 of web_form_scroll_area
(*continued*)
end tell
end tell
Thanks for the heads up on the a reference to
thing.
However, I can’t seem to get this to work by storing the UI element path in a variable first (uiElementPath
in this example), and then recalling it later using the to a reference
syntax:
activate application "DaVinci Resolve"
tell application "System Events"
tell application process "DaVinci Resolve"
set uiElementPath to "checkbox 9 of group 1 of window 1"
set uiElementPathRef to a reference to uiElementPath
set xPos to ""
set yPos to ""
try
set {xPosition, yPosition} to position of uiElementPathRef
set {xSize, ySize} to size of uiElementPathRef
-- get center coordinates of UI element
set xPos to xPosition + (xSize div 2)
set yPos to yPosition + (ySize div 2)
end try
end tell
end tell
return {xPos, yPos}
This code does not error out, but it still returns null. I did discover that it works if I remove the quotes around the initial value assignment to the uiElementPath
variable.
How would I get this to work if I wanted to feed the script UI Element paths from a pre-existing JSON dictionary like this (I’m running this script from Keyboard Maestro)?
{
"cameraraw": "checkbox 9 of group 1 of window 1",
"colormatch": "checkbox 10 of group 1 of window 1",
"primaries": "checkbox 11 of group 1 of window 1",
"hdr": "checkbox 12 of group 1 of window 1",
"rgbmixer": "checkbox 13 of group 1 of window 1",
"motioneffects": "checkbox 14 of group 1 of window 1",
"curves": "checkbox 15 of group 1 of window 1"
}
You can’t do that; uiElementPathRef
ends up being a reference to the uiElementPath variable itself.
You can’t do it directly or easily. You have the following options:
- Do a second level of compilation at runtime to convert the UI element paths into references (slow, but straightforward).
- Parse the strings yourself and build the references in a
repeat
loop.