Determine when NSSlider knob is 'let go' in continuous mode

后端 未结 7 1087
青春惊慌失措
青春惊慌失措 2020-12-17 10:19

I\'m using an NSSlider control, and I\'ve configured it to use continuous mode so that I can continually update an NSTextField with the current value of the slider while the

相关标签:
7条回答
  • 2020-12-17 10:19

    You could also simply check the type of the current event in the action method:

    - (IBAction)sliderChanged:(id)sender
    {
        NSEvent *currentEvent = [[sender window] currentEvent];
        if ([currentEvent type] == NSLeftMouseUp) {
            // the slider was let go
        }
    }
    
    0 讨论(0)
  • 2020-12-17 10:26

    Subclass NSSlider and implement

    - (void)mouseDown:(NSEvent *)theEvent
    

    it's called mouseDown:, but its called when the know interaction ends

    - (void)mouseDown:(NSEvent *)theEvent {
        [super mouseDown:theEvent];
        NSLog(@"Knob released!");
    }
    
    0 讨论(0)
  • 2020-12-17 10:26

    Just found an elegant way to have a slider continuously updating a label, and storing the slider's value only when the user releases all the mouse buttons.

    class YourViewController: NSViewController {
        @IBOutlet weak var slider: NSSlider!
        @IBOutlet weak var label: NSTextField!
    
        @objc var sliderValue = 0
    
        override func awakeFromNib() {
            sliderValue = 123 // init the value to whatever you like
    
            slider.bind(NSBindingName("value"), to: self, withKeyPath: "sliderValue")
            label.bind(NSBindingName("value"),  to: self, withKeyPath: "sliderValue")
        }
    
        @IBAction func sliderMoved(_ sender: NSSlider) {
            // return if a mouse button is pressed
            guard NSEvent.pressedMouseButtons == 0 else { return }
    
            // do something with the value
        }
    }
    
    0 讨论(0)
  • 2020-12-17 10:34

    Using current application or window event as suggested by other answers might be simpler to some degree, but not bulletproof – tracking can be stopped programmatically + check related comments for other issues. Subclassing both slider and slider cell is by far more reliable and straightforward, however, updating classes in interface builder is a drawback:

    // This is Swift 3.
    
    import AppKit
    
    class Slider: NSSlider
    {
        fileprivate(set) var tracking: Bool = false
    }
    
    class SliderCell: NSSliderCell
    {
        override func startTracking(at startPoint: NSPoint, in controlView: NSView) -> Bool {
            (self.controlView as? Slider)?.tracking = true
            return super.startTracking(at: startPoint, in: controlView)
        }
    
        override func stopTracking(last lastPoint: NSPoint, current stopPoint: NSPoint, in controlView: NSView, mouseIsUp flag: Bool) {
            super.stopTracking(last: lastPoint, current: stopPoint, in: controlView, mouseIsUp: flag)
            (self.controlView as? Slider)?.tracking = false
        }
    }
    
    0 讨论(0)
  • 2020-12-17 10:38

    This works for me (and is easier than subclassing NSSlider):

    - (IBAction)sizeSliderValueChanged:(id)sender {
        NSEvent *event = [[NSApplication sharedApplication] currentEvent];
        BOOL startingDrag = event.type == NSLeftMouseDown;
        BOOL endingDrag = event.type == NSLeftMouseUp;
        BOOL dragging = event.type == NSLeftMouseDragged;
    
        NSAssert(startingDrag || endingDrag || dragging, @"unexpected event type caused slider change: %@", event);
    
        if (startingDrag) {
            NSLog(@"slider value started changing");
            // do whatever needs to be done when the slider starts changing
        }
    
        // do whatever needs to be done for "uncommitted" changes
        NSLog(@"slider value: %f", [sender doubleValue]);
    
        if (endingDrag) {
            NSLog(@"slider value stopped changing");
            // do whatever needs to be done when the slider stops changing
        }
    }
    
    0 讨论(0)
  • 2020-12-17 10:44

    Took me a little while to find this thread, but the accepted answer (although old) is great for detecting NSSlider state changes (slider value stopped changing being the main one I was looking for)!

    Answer in Swift (Swift 4.1):

    let slider = NSSlider(value: 1,
                          minValue: 0,
                          maxValue: 4,
                          target: self,
                          action: #selector(sliderValueChanged(sender:)))
    
    . . .
    
    @objc func sliderValueChanged(sender: Any) {
    
        guard let slider = sender as? NSSlider, 
              let event = NSApplication.shared.currentEvent else { return }
    
        switch event.type {
        case .leftMouseDown, .rightMouseDown:
            print("slider value started changing")
        case .leftMouseUp, .rightMouseUp:
            print("slider value stopped changing: \(slider.doubleValue)")
        case .leftMouseDragged, .rightMouseDragged:
            print("slider value changed: \(slider.doubleValue)")
        default:
            break
        }
    }
    

    Note: the right event types account for someone who has reversed their mouse buttons

    0 讨论(0)
提交回复
热议问题