Simple example of NSStatusBar, NSMenu and NSMenuItem to perform action…
If you make a applet you need to add things in the info.plist
LSUIElement
It makes the icon of dock to be hidden, and in the script we use if statement to tell me to quit
Ps. If you use Script Debugger you could change in the script.
The script could be run directly from Script Editor.
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions
(** add to info.plist in the applet
* <key>LSUIElement</key>
* <true/>
*)
property itemStatus : missing value
on run
set arguments to {"Action 1", "|", "Action 2", "|", "Action 3", "|", "Action 4", "|", "Action 5", "|", "Action 6", "|", "Action 7", "|", "Quit"}
if my NSThread's isMainThread() as boolean then
my performMenuStatusbar:arguments
else
my performSelectorOnMainThread:"performMenuStatusbar:" withObject:arguments waitUntilDone:true
end if
end run
on performMenuStatusbar:arguments
set menuList to arguments
set theMenu to createMenu(menuList)
set itemStatus to (current application's NSStatusBar's systemStatusBar())'s statusItemWithLength:(current application's NSVariableStatusItemLength)
itemStatus's setTitle:"Action Menu"
itemStatus's setHighlightMode:true
itemStatus's setMenu:theMenu
end performMenuStatusbar:
on createMenu(menuList)
set theMenu to current application's NSMenu's alloc()'s init()
set theCount to 1
repeat with i in menuList
if (contents of i) as string is not "|" then
set menuItem to (current application's NSMenuItem's alloc()'s initWithTitle:(contents of i) action:"actionHandler:" keyEquivalent:"")
else
set menuItem to current application's NSMenuItem's separatorItem()
end if
(menuItem's setTarget:me)
(menuItem's setTag:theCount)
(theMenu's addItem:menuItem)
if (contents of i) as string is not "|" then
set theCount to theCount + 1
end if
end repeat
return theMenu
end createMenu
on actionHandler:sender
set menuTitle to title of sender as string
if menuTitle is "Quit" then
current application's NSStatusBar's systemStatusBar()'s removeStatusItem:itemStatus
if (name of current application) is not "Script Editor" then
tell me to quit
end if
else if menuTitle is "Action 1" then
display dialog "This is action 1..."
else if menuTitle is "Action 2" then
display dialog "This is action 2..."
else if menuTitle is "Action 3" then
display dialog "This is action 3..."
else if menuTitle is "Action 4" then
display dialog "This is action 4..."
else if menuTitle is "Action 5" then
display dialog "This is action 5..."
else if menuTitle is "Action 6" then
display dialog "This is action 6..."
else if menuTitle is "Action 7" then
display dialog "This is action 7..."
end if
end actionHandler:
I update other script here on macscripter:
https://www.macscripter.net/viewtopic.php?pid=196609#p196609
This one include subMenu and 4 actions and some useful logging.
Could be run directly in Script Editor or as applet…
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions
(** add to info.plist in the applet
* <key>LSUIElement</key>
* <true/>
*)
property theStatusItem : missing value
on run
set theStatusBar to showStatusBar given arguments:{"ActionGroup 1", {"Action 1", "Action 2"}, "ActionGroup 2", {"Action 3", "Action 4"}, "", "Quit"}
end run
on showStatusBar given arguments:arguments
if my NSThread's isMainThread() as boolean then
my performMenuStatusbar:arguments
else
my performSelectorOnMainThread:"performMenuStatusbar:" withObject:arguments waitUntilDone:true
end if
end showStatusBar
on performMenuStatusbar:arguments
set menuList to arguments as list
set theMenu to createMenu(menuList)
set theStatusBar to createStatusBar("Action", theMenu)
end performMenuStatusbar:
on createStatusBar(theTitle, menuList)
-- Returns the system-wide status bar located in the menu bar.
set theStatusBar to current application's NSStatusBar's systemStatusBar()
-- A status item length that dynamically adjusts to the width of its contents.
set theStatusItem to theStatusBar's statusItemWithLength:(current application's NSVariableStatusItemLength)
theStatusItem's setTitle:theTitle
theStatusItem's setImage:(current application's NSImage's imageNamed:(current application's NSImageNameActionTemplate))
theStatusItem's setHighlightMode:true
log theStatusItem's |description|() as text
theStatusItem's setMenu:menuList
log theStatusItem's button()'s |description|() as text
log theStatusItem's |menu|()'s |description|() as text
return theStatusItem
end createStatusBar
on createMenu(menuList)
set theMenu to current application's NSMenu's alloc()'s init()
set {theCount, prevMenuItem} to {10, ""}
repeat with i in menuList
if (contents of i) is equal to "" then
set theMenuItem to (current application's NSMenuItem's separatorItem())
(theMenu's addItem:theMenuItem)
else if ((class of (contents of i)) as string) = "list" then
--Generate Submenu
set subMenu to current application's NSMenu's alloc()'s init()
(theMenuItem's setSubmenu:subMenu)
set subCounter to 1
repeat with j in (contents of i)
set subMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:(contents of j) action:"actionHandler:" keyEquivalent:"")
(subMenuItem's setTarget:me)
(subMenuItem's setTag:(theCount + subCounter))
(subMenu's addItem:subMenuItem)
set subCounter to subCounter + 1
end repeat
else
set theMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:(contents of i) action:"actionHandler:" keyEquivalent:"")
(theMenuItem's setTag:theCount)
(theMenuItem's setTarget:me)
(theMenu's addItem:theMenuItem)
set theCount to theCount + 10
copy theMenuItem to prevMenuItem
end if
end repeat
return theMenu
end createMenu
on actionHandler:sender
set menuTitle to title of sender as string
if menuTitle is "Quit" then
current application's NSStatusBar's systemStatusBar()'s removeStatusItem:theStatusItem
if (name of current application) is not "Script Editor" then
tell me to quit
end if
else if menuTitle is "Action 1" then
display dialog "This is action 1..."
else if menuTitle is "Action 2" then
display dialog "This is action 2..."
else if menuTitle is "Action 3" then
display dialog "This is action 3..."
else if menuTitle is "Action 4" then
display dialog "This is action 4..."
end if
end actionHandler:
If we like to run script with paramers… we could do something like this…
Make AppleScript with name: scriptToRun.scpt and save it to desktop.
on run {input, parameters}
display dialog "My running script from menu status bar with: " & parameters
end run
Now open the script below and run…
EDIT: 210707 Have clean-up the original code and add a separator character for menu and submenu.
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions
(** add to info.plist in the applet
* <key>LSUIElement</key>
* <true/>
**
* on run {input, parameters}
* display dialog "My running script from menu status bar with: " & parameters
* end run
*)
property theStatusItem : missing value
on run
set theStatusBar to showStatusBar given arguments:{"Action Group 1", {"Action 1", "|", "Action 2", "Action 3", "Action 4"}, "Action Group 2", {"Action 5", "|", "Action 6"}, "|", "Quit"}
end run
on showStatusBar given arguments:arguments
if my NSThread's isMainThread() as boolean then
my performMenuStatusbar:arguments
else
my performSelectorOnMainThread:"performMenuStatusbar:" withObject:arguments waitUntilDone:true
end if
end showStatusBar
on performMenuStatusbar:arguments
set menuList to arguments as list
set theMenu to createMenu(menuList, "|")
set theStatusBar to createStatusBar("Action", theMenu)
end performMenuStatusbar:
on createStatusBar(theTitle, menuList)
-- Returns the system-wide status bar located in the menu bar.
set theStatusBar to current application's NSStatusBar's systemStatusBar()
-- A status item length that dynamically adjusts to the width of its contents.
set theStatusItem to theStatusBar's statusItemWithLength:(current application's NSVariableStatusItemLength)
theStatusItem's setTitle:theTitle
theStatusItem's setImage:(current application's NSImage's imageNamed:(current application's NSImageNameActionTemplate))
theStatusItem's setHighlightMode:true
log theStatusItem's |description|() as text
theStatusItem's setMenu:menuList
log theStatusItem's button()'s |description|() as text
log theStatusItem's |menu|()'s |description|() as text
return theStatusItem
end createStatusBar
on createMenu(menuList, seperator)
set theMenu to current application's NSMenu's alloc()'s init()
set theCount to 1
repeat with i in menuList
if (contents of i) as string is seperator then
set theMenuItem to (current application's NSMenuItem's separatorItem())
(theMenu's addItem:theMenuItem)
else if ((class of (contents of i)) as string) = "list" then
--Generate Submenu
set subMenu to current application's NSMenu's alloc()'s init()
(theMenuItem's setSubmenu:subMenu)
repeat with j in (contents of i)
if (contents of j) as string is seperator then
set theMenuItem to (current application's NSMenuItem's separatorItem())
(subMenu's addItem:theMenuItem)
else
set subMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:(contents of j) action:"actionHandler:" keyEquivalent:"")
(subMenuItem's setTarget:me)
(subMenuItem's setTag:theCount)
(subMenu's addItem:subMenuItem)
end if
end repeat
else
set theMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:(contents of i) action:"actionHandler:" keyEquivalent:"")
(theMenuItem's setTag:theCount)
(theMenuItem's setTarget:me)
(theMenu's addItem:theMenuItem)
set theCount to theCount + 1
end if
end repeat
return theMenu
end createMenu
on actionHandler:sender
set menuTitle to title of sender as string
if menuTitle is "Quit" then
current application's NSStatusBar's systemStatusBar()'s removeStatusItem:theStatusItem
if (name of current application) is not "Script Editor" then
tell me to quit
end if
else if menuTitle is "Action 1" then
run script POSIX path of (path to desktop) & "scriptToRun.scpt" with parameters {"", "Action 1"}
else if menuTitle is "Action 2" then
run script POSIX path of (path to desktop) & "scriptToRun.scpt" with parameters {"", "Action 2"}
else if menuTitle is "Action 3" then
run script POSIX path of (path to desktop) & "scriptToRun.scpt" with parameters {"", "Action 3"}
else if menuTitle is "Action 4" then
run script POSIX path of (path to desktop) & "scriptToRun.scpt" with parameters {"", "Action 4"}
else if menuTitle is "Action 5" then
run script POSIX path of (path to desktop) & "scriptToRun.scpt" with parameters {"", "Action 5"}
else if menuTitle is "Action 6" then
run script POSIX path of (path to desktop) & "scriptToRun.scpt" with parameters {"", "Action 6"}
end if
end actionHandler: