Joshua Joshua - 1 year ago 109
Swift Question

Subclassing NSControl, IBAction is not called in Swift

I've subclassed an NSSlider that behaves differently whether the option key is pressed. In order to do that, I overrode the mouseDown func. It seems to do the job.
The thing is, I've noticed the connected @IBAction in my ViewController is only triggered when the option key is unpressed (i.e. when the mouseDown method is passed to super). What am I missing in order to allow the @IBAction to perform?

Many thanks
Besides the issue, improvement advices on the code are welcome... :-)


class ViewController: NSViewController {

@IBOutlet weak var theSlider: MySlider!
@IBAction func moveSlider(sender: NSSlider) {
print(sender.floatValue) //works only with optionKey unpressed

class MySlider: NSSlider { //Implemented in another source file

@IBInspectable var multiplier: Float = 0.5
private var modifierKeys = NSEventModifierFlags.AlternateKeyMask
private var optionKeyPressed = false
private var previousSliderPosition: Float = 0.0

//MARK: Init with NSCoder
required init?(coder: NSCoder) {
super.init(coder: coder)
Swift.print("init Coder called")

self.continuous = true
NSEvent.addLocalMonitorForEventsMatchingMask(.FlagsChangedMask) { (theEvent) -> NSEvent? in
return theEvent

//MARK: Mouse tracking
override func mouseDown(theEvent: NSEvent) {

if optionKeyPressed {

var keepOn = true
previousSliderPosition = self.floatValue * Float(self.bounds.width) / Float(self.maxValue)

while keepOn {
if let nextEvent = self.window?.nextEventMatchingMask(Int(NSEventMask.LeftMouseUpMask.rawValue) | Int(NSEventMask.LeftMouseDraggedMask.rawValue))
switch nextEvent.type
case .LeftMouseDragged:
let mouseInnerLocationX = Float(self.convertPoint(nextEvent.locationInWindow, fromView: self.superview).x)
let mouseDelta = mouseInnerLocationX - previousSliderPosition
let newSliderPosition = previousSliderPosition + (mouseDelta) * multiplier

self.floatValue = newSliderPosition * Float(self.maxValue) / Float(self.bounds.width)

case .LeftMouseUp:
keepOn = false

} else {

//MARK: Option key handling
override func flagsChanged(theEvent: NSEvent) {
if (theEvent.modifierFlags.rawValue & NSEventModifierFlags.DeviceIndependentModifierFlagsMask.rawValue) == NSEventModifierFlags.AlternateKeyMask.rawValue {
optionKeyPressed = true
} else {
optionKeyPressed = false

Answer Source

If you're not calling super.mouseDown, you need to send the action yourself:

sendAction(action, to: target)

sendAction(_:to:), action and target are existing members of NSControl.