开发者

Circular NSSlider with stop (non-continuous) [closed]

开发者 https://www.devze.com 2022-12-28 23:43 出处:网络
Closed. This question needs debugging details. It is not currently accepting answers. Edit the question to include desired behavior, a specific problem or error, and the shortest code nece
Closed. This question needs debugging details. It is not currently accepting answers.

Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.

开发者_如何学Go

Closed 4 years ago.

Improve this question

I am not sure how to phrase this better as a title but I need to make an NSSlider that functions as a normal volume knob. At the moment it will spin around as many times as I hold the mouse down and move it around the control. I need it to stop at the "0" position and the "100" position, I cannot have it jumping from 0 to 100 when I drag it the other way. I hope I am making this clear. Does anyone know how to do this or have any suggestions?


An old question, but here we go anyway:

(1) Set the slider to have 100 tickmarks

(2) Select "Only stop at tickmarks"

(3) In Interface Builder, set the custom cell class to SBCustomSliderCell

Use the code below:

@interface SBCustomSliderCell()

@property CGFloat lastSliderValue;

@end

@implementation SBCustomSliderCell

- (void)awakeFromNib
{
    self.lastSliderValue = -1;
}

- (double)closestTickMarkValueToValue:(double)value
{
    double proposedValue = [super closestTickMarkValueToValue:value];

    if (self.lastSliderValue == -1)
    {
        self.lastSliderValue = proposedValue;
        return proposedValue;
    }

    double MAX_JUMP = 50;

    double tickDifference = ABS(self.lastSliderValue - proposedValue);

    BOOL isTurningUp = proposedValue > self.lastSliderValue;

    if (tickDifference > MAX_JUMP)
    {
        proposedValue = isTurningUp ? 0.0 : self.maxValue;
    }

    NSLog(@"value: %.2f gap: %.2f", proposedValue, tickDifference);

    self.lastSliderValue = proposedValue;
    return proposedValue;
}

- (NSRect)rectOfTickMarkAtIndex:(NSInteger)index
{
    return NSZeroRect;
}

@end


I think you'll need to subclass NSSliderCell and override startTrackingAt:inView:, continueTracking:at:inView: and stopTracking:at:inView:mouseIsUp:.

The documentation of continueTracking:at:inView: says:

This method is invoked in trackMouse:inRect:ofView:untilMouseUp:. The default implementation returns YES if the cell is set to continuously send action messages to its target when the mouse button is down or the mouse is being dragged. Subclasses can override this method to provide more sophisticated tracking behavior.


Here's how to do it in Swift

This answer is based on Mark's "SBSLiderCell" answer above, but adapted for Swift.

Because it's a subclass of NSSliderCell, be sure to set the custom class in Interface Builder for the cell, and not the NSSlider superview.

Set the number of Tick Marks to your desired granularity (e.g.: 100) and click the "Only stop on tick marks" checkbox.

class PraxSliderCell : NSSliderCell {

    var lastSliderValue: Double = -1

    override func closestTickMarkValueToValue(value: Double) -> Double {

        var proposedValue = super.closestTickMarkValueToValue(value)

        if lastSliderValue == -1 { lastSliderValue = proposedValue }

        else {

            let tickDifference = abs(lastSliderValue - proposedValue)
            let isTurningUp = proposedValue > lastSliderValue
            if tickDifference > Double(numberOfTickMarks / 2) {
                proposedValue = isTurningUp ? 0.0 : maxValue }

            print (NSString(format: "value: %.2f gap: %.2f", proposedValue, tickDifference))
            lastSliderValue = proposedValue
        }

    return proposedValue
    }

    override func rectOfTickMarkAtIndex(index: Int) -> NSRect { return NSZeroRect }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消