When writing AppleScript Studio apps in XCode, I find that I spend most of my time trying guess the location of “theObject”. For testing purposes, is there a way that I can simply display a dialog box containing the properties of theObject including where it lives in my application? It would save me a lot of time trying to figure out stuff like button “getButton” oftab view item “htmlTab” oftab view “bodyView” ofwindow “mainWin”.
I’m thinking something like (although this doesn’t give me what I need):
I’m not really sure I understand why you have to “guess” the location of theObject. You should be able to click on it in IB to get it’s name, the window’s name, and any container objects it might be in. Yeah, you have to type it all out, but you’ve already done so much typing that it seems like a small burden. There are ways to simplify your code to eliminate some of the bloat and hassle, which everyone discovers and refines as they learn.
Below is the start to some code that I found did an OK job of getting me the location of an object, as I think you’re looking for. It was actually kinda hard to find ways of getting all the info I needed, and you’ll have a challenge figuring out what all the code does and how to add to it to accomodate more types of objects. It only goes one superview deep, so any more than that will throw an error. For example, if you have “button 1>tab view 1>window 1”…you’re alright. But if you have “button 1>BOX 1>tab view 1>window 1”, you’re out of luck because I didn’t bother with evaluating more than three levels. Check out the code and you’ll see why. 8)
on clicked theObject
displayObjectInfo(theObject)
end clicked
(* Also connected successfully to... *)
--> on action theObject
--> on choose menu item theObject
(* Couldn't get to work... *)
--> image view
--> color well
--> text view
to displayObjectInfo(theObject)
set theObjectInfo to "" --> Initialize the output var
set {theName, theClass, theWindow, theWindowID} to {(name of theObject), (class of theObject), (name of window of theObject), (id of window of theObject)}
(* Get the first superview *)
try
set superViewClass to class of (super view of (super view of theObject))
set superViewID to id of (super view of (super view of theObject))
end try
set theSuperview to "none"
if (superViewClass as string) contains "boxO" then
set theSuperview to "box"
else if (superViewClass as string) contains "tabV" then
set theSuperview to "tab view"
end if
(* Create the object info *)
--> The object
set theObjectType to "<object>" --> default object type
if (theClass as string) contains "butT" then
set theObjectType to "button"
else if (theClass as string) contains "popB" then
set theObjectType to "popup button"
set thePopupItem to (name of current menu item of theObject)
set theObjectInfo to ("menu item "" & thePopupItem & "" of ") as string
end if
set theObjectInfo to (theObjectInfo & theObjectType & " "" & theName & """) as string
--> The superview
if theSuperview is not "none" then
set theSuperviewName to (name of (view id superViewID of window id theWindowID))
set theObjectInfo to (theObjectInfo & " of " & theSuperview & " "" & theSuperviewName & """) as string
end if
--> The window
set theObjectInfo to (theObjectInfo & " of window "" & theWindow & """) as string
(* EDITED: Copy the path to the clipboard, if desired *)
(* Display the object info *)
if button returned of (display dialog "The Object Hierarchy Path..." default answer (theObjectInfo as string) buttons {"Cancel", "Copy"} default button 2) is "Copy" then
set preferred type of pasteboard "general" to "string"
set contents of pasteboard "general" to (theObjectInfo as string)
set preferred type of pasteboard "general" to ""
end if
end displayObjectInfo
As you found, you can use “set theObjectInfo to properties of theObject” in place of all the other code, and right before the ‘display dialog…’ to get all of the properties of the object in question. You’ll have to weed through that to find the class codes, id’s names and other stuff you can find. Actually, I’m happy you posted this because it was amusing trying to figure it out. Feel free to PM me for more discussion.
I usually make a script file that I include into my other scripts with contents like
property confirmButton : button “confirm” of blah “x” of blah “y”…
property cancelButton :…
then including it
set nibRefs to load script …
then using it with
if theObject is confirmButton of nibRefs
Another possibility is to just have more script files so your handlers don’t have to fork so much… putting the core handlers (not directly associated with interface) and properties into a seperate file that gets loaded by each script that does interact directly with AppKit
If I follow you correctly, you just want a way to get the object reference of the object clicked, just log the object:
If you want to do something specific when the object is clicked, just name each object uniquely and then act on each object based on its name and you won’t need to worry about the full object reference path anyway:
Yeah, I guess I’m just still working out how things work in Interface Builder. I was trying to target some radio buttons and I couldn’t figure out if I needed to target them or the enclosing matrix or target them inside the matrix. I eventually figured it out.
But that code that you’ve posted is pretty cool! I’m pretty new to all of this, so
log theObject
was a big discovery for me and has helped a lot. I’m going to keep that code handy though 'cause it might help me out in the right situation. I just wish that it was a little more bullet-proof and worked for everything.