This might be an easy question, but I am new to Swift and do not know for which terms to google for.
For a menu bar application, I have implemented a custom function called doSomething
that works just fine when it is bound to some button:
Class MainViewController:
{
@IBAction func doSomething(sender: NSButton)
{
// Do something when NSButton is pressed
}
}
However, I need to distinguish between left- and right click on the button, which in my case is a NSStatusBarButton
. Following the suggestion from this answer, I have written the following into my AppDelegate.swift
:
@NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate {
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-2)
var mainViewController: MainViewController?
func applicationDidFinishLaunching(notification: NSNotification)
{
if let button = statusItem.button
{
button.action = #selector(customClickAction)
button.sendActionOn(Int(NSEventMask.RightMouseDownMask.rawValue | NSEventMask.LeftMouseDownMask.rawValue))
}
}
func customClickAction(sender: NSButton)
{
let event:NSEvent! = NSApp.currentEvent!
if (event.type == NSEventType.RightMouseDown)
{
print("Right mouse button down")
}
else if (event.type == NSEventType.LeftMouseDown)
{
print("Left mouse button down")
mainViewController?.doSomething(_:) // THIS DOES NOT WORK
}
}
}
The above code snippet gives me the error message 'Expression resolves to an unused function' in XCode. I cannot figure out how to properly call the function doSomething
from the MainViewController
class within the customClickAction
function, or equivalently, how to redirect the action of the statusItem.button
via customClickAction
to doSomething
. I apologize if this question might seem too trivial for the Swift experts, but I am really in despair trying to figure this one out.
EDIT:
If the function customClickAction
was not existing, I would simply write button.action = #selector(mainViewController?.show(_:))
in applicationDidFinishLaunching
to call the function and everything works. However, part of my problem is that doing the same in my custom function would overwrite the binding once the left mouse button has been pressed for the first time.
Here is a question from someone who had the same Expression resolves to an unused function
problem. In his/her case the problem was that the functions was called without the ()
after the function, so stop
instead of stop()
(if that makes sense).
OK, so now that we know what the compiler is trying to tell us, we can try to figure out what to do to solve it.
In your case the problem is that you need to send a sender
parameter to your doSomething
method, and that parameter must be of type NSButton
as you've declared your self.
@IBAction func doSomething(sender: NSButton)
{
// Do something when NSButton is pressed
}
So, in your case, if you just pass the sender
which you get as a parameter to your customClickAction
along like so:
func customClickAction(sender: NSButton)
{
let event:NSEvent! = NSApp.currentEvent!
if (event.type == NSEventType.RightMouseDown)
{
print("Right mouse button down")
}
else if (event.type == NSEventType.LeftMouseDown)
{
print("Left mouse button down")
mainViewController?.doSomething(sender)
}
}
Then the compiler seems happy.
Here is the entire AppDelegate
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-2)
var mainViewController: MainViewController? = MainViewController() //initialized
func applicationDidFinishLaunching(notification: NSNotification)
{
if let button = statusItem.button
{
button.action = #selector(customClickAction)
button.sendActionOn(Int(NSEventMask.RightMouseDownMask.rawValue | NSEventMask.LeftMouseDownMask.rawValue))
}
}
func customClickAction(sender: NSButton)
{
let event:NSEvent! = NSApp.currentEvent!
if (event.type == NSEventType.RightMouseDown)
{
print("Right mouse button down")
}
else if (event.type == NSEventType.LeftMouseDown)
{
print("Left mouse button down")
mainViewController?.doSomething(sender)
}
}
}
Hope that helps you.
Followup to your edit
You write
If the function customClickAction was not existing, I would simply write button.action = #selector(mainViewController?.show(_:)) in applicationDidFinishLaunching to call the function and everything works.
Its possible that I'm misunderstanding everything here, but why don't you then "just" assign the doSomething
method to your button.action
and then moves the check for left or right button to that method?
So you'd say:
button.action = #selector(mainViewController?.doSomething(_:))
and your doSomething
would look like this:
@IBAction func doSomething(sender: NSButton)
{
// Do something when NSButton is pressed
let event:NSEvent! = NSApp.currentEvent!
if (event.type == NSEventType.RightMouseDown)
{
print("Right mouse button down")
}
else if (event.type == NSEventType.LeftMouseDown)
{
print("Left mouse button down")
}
}
"Left mouse button down" and "Right mouse button down" shows up in my console if I do that.
As @ixany writes in the comments:
Is it me or Swift 3? :) Seems that your solution needs to be updated to Swift 3 since I'm not able to adapt it using the current Xcode Beta
I've tried to upgrade the syntax to Swift 3.0 but there seems to be some problems with it.
The first problem is that I could not go directly to the doSomething
method of MainViewController
when assigning the selector
, so I added a "local" step so to speak.
The AppDelegate
now looks like this:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
let statusItem = NSStatusBar.system().statusItem(withLength: -2)
var mainViewController: MainViewController? = MainViewController()
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = statusItem.button
{
button.action = #selector(AppDelegate.localButtonAction(sender:))
button.sendAction(on: [NSEventMask.leftMouseDown, NSEventMask.rightMouseDown])
}
}
func localButtonAction(sender: NSStatusBarButton) {
mainViewController?.doSomething(sender: sender)
}
}
(Notice the ´localButtonAction´ method, I hope someone else has a prettier way to do this)
And the MainViewController
looks like this:
import Cocoa
class MainViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
@IBAction func doSomething(sender: NSStatusBarButton) {
// Do something when NSButton is pressed
let event:NSEvent! = NSApp.currentEvent!
if (event.type == NSEventType.rightMouseDown)
{
print("Right mouse button down")
}
else if (event.type == NSEventType.leftMouseDown)
{
print("Left mouse button down")
}
}
}
The problem with this is that the event
is never of type rightMouseDown
as far as I can see. I'm probably doing something wrong and I hope that someone else can make this work, but now it compiles at least and is Swift 3.0 syntax (using Xcode 8.0 - beta 6 :))
Hope that helps you @ixany