Monday, September 27, 2010

ApplescriptObjC tutorial: the most basic tutorial

I wrote a collection of Applescripts to automate data entry and other processes. These scripts however don't have a good place to live. For example, how should I launch them all? Double click on their icon? I now have about 10 scripts and I need a way to launch them. I decided to go the route of AppleScriptObjC. This is a brand new platform Apple designed to replace Applescript Studio. It is essentially applescript bindings to the cocoa library. The only reason this is useful is because the XCode Interface Builder (IB) allows you to design your own window by drag and drop of buttons, etc. Each button can correspond to launching a script. You can include text fields to gather user intput, and you can even implement progress bars, etc... But lets not get ahead of ourselves. The problem with ApplescriptObjC is that it requires a basic understanding of Cocoa. But, I believe that is only because nobody on the net is currently talking about it from the scripter's perspective.

If you start out as someone wanting to write automation routines, then why would you ever consider writing or learning C libraries? Nobody is doing that this day and age. Its bad enough you have to use applescript in the first place.

This tutorial is for those of you who don't want to program C libraries, but want to write your automations and hook them into a GUI you build using drag and drop. I'll start by opening a new project and creating a simple program that has 1 button and when you click it it runs your script.

Phase 1: Writing the code.
  1. Download and install Apple's XCode (requires snow leopard 10.6 or better)
  2. Start a new project by selecting "Cocoa Applescript Application" and name it "test"
  3. Once your project is created and in front of you look on the left side for "Classes" go into it and select "testAppDelegate".  This is simply a file containing all your applescripts. You can safely ignore everything else for now.
  4. Notice there is a script in there: "script testAppDelegate" this is the script where you will setup functions that will run when you click buttons in your program. Notice the first line is: "property parent : "NSObject"". This is inheritance. Everything in this script inherits all the functions available in the cocoa class NSObject. Fortunately we don't care what this means or does as we just want to setup a GUI for our collection of scripts. Just keep in mind that everything you implement needs to go after this for cocoa to work properly.
  5. Create a new function call it "ButtonClicked" and SAVE:
 on ButtonClicked_(sender)
display dialog "button was clicked"
end ButtonClicked_
You need to have the underscore at the end of the function name and the parameter must be sender. This informs the Cocoa libraries that it can accept connections from buttons you will later create in the Interface Builder (IB)

Phase 2: Designing the window and connecting buttons.
  1. Next on the left side under resources: double click on the file MainMenu.xib This will open up the interface builder and start you out with a default empty window.
  2. If the library pane isn't already opened up, click on "Tools>Library" and the window should open. Scroll down until you find a button and drag it into your main window.
  3. Type whatever text you want into the button to label it
  4. Control-Drag the button to the object "Test App Delegate" in the MainMenu.xib object browser. It should create a line between the button and the App Delegate object  (your script)
  5. When you let go of the mouse click, it should popup a context HUD menu. Select "ButtonClicked:". If it is not an option go back to the app delegate script and ensure you have it saved and ensure that it is setup correctly with the underscore and parameter "sender" as described above. Notice they use a : instead of _ in the name of your function that is because Cocoa is converting the functionname syntax from applescript to C. Don't worry about that it is supposed to be that way.
  6. You are now fully connected. SAVE from within MainMenu.xib's object browser and go back to XCode and hit the hammer button to compile and run.
A couple of notes: notice that when you click the button, it doesn't become available again until the script finishes running. So if you have a script that requires lots of time to run and you want to continue to use your application you might consider forking it off using a shell script call to osascript. I have another post that describes exactly how to do that here


  1. I think 5 of Phase 1 is confusing. Do you mean I should create a new file called ButtonClicked.applescript under the Classes group? When I create such a file, text is automatically filled in
    script ButtonClicked
    property parent : class "NSObject"
    end script

    I tried both replacing that text with the one you included under Phase 1.5. and adding it after the automatically added text.

    Either way, the scripting doesn't work, i.e. I don't get the ButtonClicked option in step Phase 2.5.

    1. No, put the on buttonClicked function in the generated file, whose name in Xcode 4.4 will be either AppDelegate.applescript for a non-document based app, or Document.applescript for a document-based app.

  2. The problem I'm having is when I just blindly insert my applescript in the button, I get a problem with the objects in my applescript...

    So I try to run and I get an error saying it's expected "end" but found "on" ... because I defeine 3 objects at the beginning of the script and they start with on xxxxxx ... end xxxx

    Is there some way I can make the applescript a big function/object and have the button just point to that some way?

    I'm very sorry for the sloppiness of my question, but I have just barely hacked together applescripts from info I found on the internet, and I haven't really ready any books or anything official