Search code examples
applescriptnsmenunsmenuitem

Enable menu items and call function when activated in AppleScript


I'm trying to enable the NSMenuItems that I have but it doesn't seem to be working. I'm not sure what I'm doing wrong and I'm fairly new at AppleScript. When the menu items are clicked they need to call the functions as kind of shown in the code.

use scripting additions
use framework "Foundation"
use framework "AppKit"

set bar to current application's NSStatusBar's systemStatusBar
set StatusItem to bar's statusItemWithLength:-1.0

StatusItem's setTitle:"menu"
set newMenu to current application's NSMenu's alloc()'s initWithTitle:"Custom"
set menuItem1 to current application's NSMenuItem's alloc()'s initWithTitle:"item 1" action:"action1:" keyEquivalent:""
set menuItem2 to current application's NSMenuItem's alloc()'s initWithTitle:"item 2" action:"action2:" keyEquivalent:""

StatusItem's setMenu:newMenu
newMenu's addItem:menuItem1
newMenu's addItem:(current application's NSMenuItem's separatorItem())
newMenu's addItem:menuItem2

on action1()
    log "this works"
end action1

on action2()
    log "this works 2"
end action2

Solution

  • The main issue is your action handler declarations don't match the selectors when creating the menu items, and you need to specify the target that contains the action methods.

    The system typically passes the sender (the menu item) to the action, so they need to be declared with a single parameter, with the selector ending with a colon - for example:

    on action1:sender --> matches the selector "action1:"
    

    If you aren't passing anything to your own methods, they wouldn't have a parameter or the ending colon:

    on anotherAction() --> matches the selector "anotherAction"
    

    The following script matches the method declarations and sets the targets - note that when running from the Script Editor, the script will normally end before using any menu items, so you won't get log statements when the action methods are called - I've used alerts instead. I've also added a termination handler (without a parameter) to remove the status menu, so that when testing from the Script Editor you don't wind up with a menu bar full of them (theoretically):

    use framework "Foundation"
    use scripting additions
    
    property statusItem : missing value
    
    on run -- example
       set my statusItem to current application's NSStatusBar's systemStatusBar's statusItemWithLength:(current application's NSVariableStatusItemLength)
       statusItem's setTitle:"menu"
       set newMenu to current application's NSMenu's alloc()'s initWithTitle:""
       (newMenu's addItemWithTitle:"item 1" action:"action1:" keyEquivalent:"")'s setTarget:me
       (newMenu's addItemWithTitle:"item 2" action:"action2:" keyEquivalent:"")'s setTarget:me
       newMenu's addItem:(current application's NSMenuItem's separatorItem)
       (newMenu's addItemWithTitle:"Quit" action:"terminate" keyEquivalent:"")'s setTarget:me
       statusItem's setMenu:newMenu
    end run
    
    on action1:sender
       display alert "Menu " & quoted form of (sender's title() as text) & " works"
    end action1:
    
    on action2:sender
       display alert "Menu " & quoted form of (sender's title() as text) & " also works"
    end action2:
    
    to terminate() -- quit handler is not called from normal NSApplication terminate:
       current application's NSStatusBar's systemStatusBar's removeStatusItem:statusItem
       if name of current application does not start with "Script" then tell me to quit
    end terminate