What you need to understand is that AppleScript code is just text, and the script file you have open in the Script Editor app is just a text file, it is not an application in itself.
So when you run AppleScriptObjC code in the Script Editor app, its not your AppleScript code that runs the commands, it’s the Script Editor app that does the actual execution.
So as Shane has pointed out, the Script Editor app runs that code in a background thread, in order to allow it’s own interface to continue to work and be responsive.
So when working with visual screen UI elements, you have to tell the Script Editor app to execute the code on the main thread, as that’s the operating system rules for UI manipulation, and not to execute the code on a background thread.
Or you have to do as Shane as also pointed out, and save your code as an applet or application, so that the Script Editor is no longer in control of the thread, and your stand alone AppleScript applet is, which will by default run any contained code on the main thread.
So with that being understood, while your working on your AppleScript code in the Script Editor app, you have to make sure that any UI manipulation that the Script Editor app does, is carried out on the main thread, and you do that by using the “performSelectorOnMainThread:withObject:waitUntilDone:” method that Shane has pointed too.
Like this example below.
use framework "Foundation"
use framework "AppKit"
use scripting additions
property myApp : a reference to current application
property statusBar : missing value
property statusItem : missing value
set statusItemTitle to "Status Bar Title"
set my statusBar to myApp's NSStatusBar's systemStatusBar()
if my NSThread's isMainThread() as boolean then
my displayStatusItem:statusItemTitle
else
my performSelectorOnMainThread:"displayStatusItem:" withObject:statusItemTitle waitUntilDone:true
end if
on displayStatusItem:title
set my statusItem to statusBar's statusItemWithLength:(myApp's NSVariableStatusItemLength)
statusItem's button's setTitle:title
set statusItemMenu to myApp's NSMenu's alloc()'s initWithTitle:""
set quitMenuItem to myApp's NSMenuItem's alloc()'s initWithTitle:"Quit" action:"quitStatusItem" keyEquivalent:"q"
quitMenuItem's setTarget:me
statusItemMenu's addItem:quitMenuItem
statusItem's setMenu:statusItemMenu
end displayStatusItem:
on quitStatusItem()
set quitStatusItem to button returned of (display alert "Do you want to quit the status bar item ?" buttons {"NO", "YES"})
if quitStatusItem = "YES" then
my performSelectorOnMainThread:"removeStatusItem" withObject:(missing value) waitUntilDone:true
end if
end quitStatusItem
on removeStatusItem()
statusBar's removeStatusItem:statusItem
end removeStatusItem
I hate to post code that I can not test on the correct operating system, but I don’t have access to “Monterey”, and was only able to test it on “Mojave”, so I’ll apologise in advance for any issues that my occur from the OS differences, but I’m sure someone running “Monterey” can step in and help with any OS specific solutions.
But with that being said, you can see the code check which thread it is being run on, and if it’s not the main thread, then it uses the “performSelectorOnMainThread:withObject:waitUntilDone:” method.
This code may not be what you want, but is simply to show you how to perform UI code on the main thread while in the Script Editor app, and also how to use methods and create a menu for your status item if you need to.
if you want to change the status item’s title as you describe, you also have to make sure that is also done on the main thread, perhaps via another created method called “on changeStatusItemTitle:”.
I hope this makes things a bit more understandable.
Regards Mark