Display an icon and text on NSStatusBar for macOS using Swift - swift

I would like to display an icon and some texts to its right on a NSStatusBar.
The code I'm using, as seen below, displays the icon and the text overlapping.
This is an example of I'm trying to emulate:
And here's my current code for reference:
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.variableLength)
var preferencesWindow: NSWindowController?
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = statusItem.button {
button.image = NSImage(named:NSImage.Name("StatusBarButtonImage"))
button.title = "..."
}
initMenu()
}

Related

How to reopen an macos App using menubar button

I created an app with a menubar button using swift and storyboard, when I click the close button the window closed and the menubar button still sits on the menubar, that's good. What I want to do next is reopen the window by clicking the menubar button. After searching I figured out I can use this code to bring it to the front, but it only works when the window is still open. How can I bring it back when it is closed or miniatured?
NSApplication.shared.activate(ignoringOtherApps: true)
This the appDelegate
class AppDelegate: NSObject, NSApplicationDelegate {
private var statusItem: NSStatusItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
statusItem = NSStatusBar.system.statusItem(withLength: 16.0)
if let button = statusItem.button {
button.image = NSImage(named: "remote-control")
button.image?.size = NSSize(width: 16.0, height: 16.0)
button.image?.isTemplate = true
button.action = #selector(bringToFront(sender:))
}
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
print("terminate")
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
#objc func bringToFront(sender: AnyObject?) {
NSApplication.shared.activate(ignoringOtherApps: true)
NSApp.windows.last?.makeKeyAndOrderFront(nil)
}}
This is the windowcontroller
class MainWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
window?.title = ""
let styleMask: NSWindow.StyleMask = [.closable, .titled, .miniaturizable]
window?.styleMask = styleMask
}}
Thanks
I got it.
In appdelegate use deminiaturize function does exactly what I want.
for window in NSApp.windows {
window.deminiaturize(nil)
}
Since I only have one window but NSApp.windows has two members, I think I can deminiatureize all the windows.

How do I open a setting menù from a Status Item on right-click? Swift on MacOS [duplicate]

I’m building a status bar app and want to call different actions depending on if the user clicked left or right. Here’s what I have so far:
var statusItem = NSStatusBar.system().statusItem(withLength: -1)
statusItem.action = #selector(AppDelegate.doSomeAction(sender:))
let leftClick = NSEventMask.leftMouseDown
let rightClick = NSEventMask.rightMouseDown
statusItem.button?.sendAction(on: leftClick)
statusItem.button?.sendAction(on: rightClick)
func doSomeAction(sender: NSStatusItem) {
print("hello world")
}
My function is not called and I couldn’t find our why. I appreciate any help!
Have you tried:
button.sendAction(on: [.leftMouseUp, .rightMouseUp])
Then seeing which mouse button was pressed in the doSomeAction() function?
So it will look something like...
let statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength)
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = statusItem.button {
button.action = #selector(self.doSomeAction(sender:))
button.sendAction(on: [.leftMouseUp, .rightMouseUp])
}
}
func doSomeAction(sender: NSStatusItem) {
let event = NSApp.currentEvent!
if event.type == NSEvent.EventType.rightMouseUp {
// Right button click
} else {
// Left button click
}
}
Thanks to #dbrownjave for noticing the change in Swift 4 from NSEventType.rightMouseUp to NSEvent.EventType.rightMouseUp.
https://github.com/craigfrancis/datetime/blob/master/xcode/DateTime/AppDelegate.swift
Updated: SWIFT 4
I've updated (Craig Francis) answer
func doSomeAction(sender: NSStatusItem) {
let event = NSApp.currentEvent!
if event.type == NSEvent.EventType.rightMouseUp{
// Right button click
} else {
// Left button click
}

Swift+Macos Auto close popover window when focus is lost

I am writing a small app that display an icon in the menu bar with a popup view.
I followed https://github.com/twostraws/SwiftOnSundays/tree/master/013%20TextTransformer as an example.
One difference I am seeing in my test app is the popover view controller is not getting dismissed when view loses focus.
this is my app delegate,
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
let popupOver = NSPopover()
#IBOutlet weak var menu: NSMenu!
func applicationDidFinishLaunching(_ aNotification: Notification) {
statusItem.button?.title = "FT";
statusItem.button?.target = self;
statusItem.button?.action = #selector(showMenu)
let storyBoard = NSStoryboard(name: "Main", bundle: nil)
guard let viewController = storyBoard.instantiateController(withIdentifier: "FTViewController") as? ViewController else {
fatalError("Unable to find 'FTViewController'")
}
popupOver.contentViewController = viewController
popupOver.behavior = .semitransient
}
func applicationDidResignActive(_ notification: Notification) {
popupOver.close()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
#objc func showMenu() {
if(popupOver.isShown) {
popupOver.close()
}
else {
guard let statusButton = statusItem.button else {
fatalError("Unable to find status button")
}
popupOver.show(relativeTo: statusButton.bounds, of: statusButton, preferredEdge: .maxY)
}
}
}
I tried adding applicationDidResignActive but that's getting triggered only when the application loses focus so if i directly click the menu bar item and click else where on screen I am not getting that event. The sampleapp i referenced doesnt seem to hookup for these events but still works as expected.
I am just starting swift ui programming so couldnt figure out what I am missing here.
Not sure if you're still looking for a solution here, but I've just got stuck with the same problem and I found this example which seems to do the job. Hope this helps.

Xcode NSStatusBar Item not appearing

I'm trying to add an item to the status bar, but when I launch the app the item only appears in the top left for a split second and then quickly disappears.
I've looked through the documentation and I can see things have changed recently e.g. statusItem.title has become statusItem.button?.title. But don't seem to be missing anything else. Any help?
Here's my code:
var statusItem : NSStatusItem? = nil
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
statusItem.button?.title = "Connect!"
}
Ah brilliant. That's worked! Thanks Saleh. After playing around with both our codes, mine seemed to work with the var declaration at the top and without NSMenuDelegate instance. My issue seems to be that I was saying :
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
All I had to do to make it work was remove the 'let' and just say:
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
AppDelegate should be an instance of NSMenuDelegate
Define the statusItem at creation
Setup the button title in the applicationDidFinishLaunching callback
class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.variableLength)
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = statusItem.button {
//button.image = NSImage(named:NSImage.Name("StatusBarButtonImage"))
button.title = "connect"
//button.action = #selector(doSomething(_:))
}
}

How to open a locally saved PDF file with Swift

I've made a Swift menu bar app XCode 8.2.1. One of the menu bar options in this script successfully runs an AppleScript I created. I'd like to put another option in this menu bar app that opens a PDF instruction/read me file for the user. How do I open a locally saved PDF file in Swift?
I've included the code I have in the AppDelegate.swift file in XCode.
//
// AppDelegate.swift
// Layout Ad
//
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
#IBAction func quitClicked(sender: NSMenuItem) {
NSApplication.shared().terminate(self)
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
statusItem.menu = statusMenu
let icon = NSImage(named: "statusIcon")
//icon?.isTemplate = true // best for dark mode
statusItem.image = icon
statusItem.menu = statusMenu
constructMenu()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
//Function to get the path to the applescript
func runApplescript(){
let task = Process()
task.launchPath = "/usr/bin/osascript"
task.arguments = ["/Library/Scripts/1_Page Layout Scripts/Layout Ad.scpt"]
task.launch()
}
//Function to open the script's instructions
func openPDF(){
//Code to open PDF file will go here
//"/Volumes/NAS/Advertising Department/16_SCRIPTS/*Instructions/2_Running Scripts/1_InDesign/Layout Ad Script Instructions.pdf"
}
//Function to make the menu work
func constructMenu() {
let menu = NSMenu()
menu.addItem(NSMenuItem(title: "Script Instructions", action: #selector(openPDF), keyEquivalent: ""))
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Layout Ad", action: #selector(runApplescript), keyEquivalent: ""))
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
statusItem.menu = menu
}
}
NSWorkspace can do that.
let url = URL(fileURLWithPath: "/Volumes/NAS/Advertising Department/16_SCRIPTS/*Instructions/2_Running Scripts/1_InDesign/Layout Ad Script Instructions.pdf")
NSWorkspace.shared.open(url)