【问题标题】:Making a circular NSSlide look and behave like in GarageBand使圆形 NSSlide 的外观和行为类似于 GarageBand
【发布时间】:2010-06-13 12:23:31
【问题描述】:

我是使用 Cocoa 绘图的新手,我正在制作一些软件,它的滑块类似于 GarageBand 中的滑块:

GB Sliders http://img33.imageshack.us/img33/2668/schermafbeelding2010061r.png

这些看起来很漂亮,可以通过上下移动鼠标来控制。

您能帮我自定义 NSSlider 子类,以便我可以让它们的外观和行为与 GarageBand 中的完全一样吗?谢谢。


我有一张旋钮图像,应该旋转,因为它们不需要是 3D 的。

【问题讨论】:

    标签: objective-c cocoa subclass circular-slider nsslider


    【解决方案1】:

    最简单的方法是创建一个 NSView 子类来处理鼠标管理和绘图。

    有一个示例代码可以帮助您开始命名为“TLayer”。它是 XCode 3.1.4 示例的一部分。它包含一个圆形自定义视图,用于控制为图层绘制的阴影的偏移和半径。它易于理解且易于扩展。

    注意:因为它似乎在 Apple 网站上不可用,所以我将来源粘贴在下面。


    ShadowOffsetView.h

    #import <AppKit/AppKit.h>
    
    extern NSString *ShadowOffsetChanged;
    
    @interface ShadowOffsetView : NSView
    {
        CGSize _offset;
        float _scale;
    }
    
    - (float)scale;
    - (void)setScale:(float)scale;
    
    - (CGSize)offset;
    - (void)setOffset:(CGSize)offset;
    
    @end
    

    ShadowOffsetView.m

    #import "ShadowOffsetView.h"
    
    NSString *ShadowOffsetChanged = @"ShadowOffsetChanged";
    
    @interface ShadowOffsetView (Internal)
    - (NSCell *)cell;
    @end
    
    @implementation ShadowOffsetView
    
    - (id)initWithFrame:(NSRect)frame
    {
        self = [super initWithFrame:frame];
        if (self == nil)
        return nil;
    
        _offset = CGSizeZero;
    
        return self;
    }
    
    - (void)dealloc
    {
        [super dealloc];
    }
    
    - (float)scale
    {
        return _scale;
    }
    
    - (void)setScale:(float)scale
    {
        _scale = scale;
    }
    
    - (CGSize)offset
    {
        return CGSizeMake(_offset.width * _scale, _offset.height * _scale);
    }
    
    - (void)setOffset:(CGSize)offset
    {
        offset = CGSizeMake(offset.width / _scale, offset.height / _scale);
        if (!CGSizeEqualToSize(_offset, offset)) {
        _offset = offset;
        [self setNeedsDisplay:YES];
        }
    }
    
    - (BOOL)isOpaque
    {
        return NO;
    }
    
    - (void)setOffsetFromPoint:(NSPoint)point
    {
        float radius;
        CGSize offset;
        NSRect bounds;
        
        bounds = [self bounds];
        offset.width = (point.x - NSMidX(bounds)) / (NSWidth(bounds) / 2);
        offset.height = (point.y - NSMidY(bounds)) / (NSHeight(bounds) / 2);
        radius = sqrt(offset.width * offset.width + offset.height * offset.height);
        if (radius > 1) {
        offset.width /= radius;
        offset.height /= radius;
        }
        if (!CGSizeEqualToSize(_offset, offset)) {
        _offset = offset;
        [self setNeedsDisplay:YES];
        [(NSNotificationCenter *)[NSNotificationCenter defaultCenter]
            postNotificationName:ShadowOffsetChanged object:self];
        }
    }
    
    - (void)mouseDown:(NSEvent *)event
    {
        NSPoint point;
    
        point = [self convertPoint:[event locationInWindow] fromView:nil];
        [self setOffsetFromPoint:point];
    }
    
    - (void)mouseDragged:(NSEvent *)event
    {
        NSPoint point;
    
        point = [self convertPoint:[event locationInWindow] fromView:nil];
        [self setOffsetFromPoint:point];
    }
    
    - (void)drawRect:(NSRect)rect
    {
        NSRect bounds;
        CGContextRef context;
        float x, y, w, h, r;
    
        bounds = [self bounds];
        x = NSMinX(bounds);
        y = NSMinY(bounds);
        w = NSWidth(bounds);
        h = NSHeight(bounds);
        r = MIN(w / 2, h / 2);
        
        context = [[NSGraphicsContext currentContext] graphicsPort];
    
        CGContextTranslateCTM(context, x + w/2, y + h/2);
    
        CGContextAddArc(context, 0, 0, r, 0, 2*M_PI, true);
        CGContextClip(context);
    
        CGContextSetGrayFillColor(context, 0.910, 1);
        CGContextFillRect(context, CGRectMake(-w/2, -h/2, w, h));
    
        CGContextAddArc(context, 0, 0, r, 0, 2*M_PI, true);
        CGContextSetGrayStrokeColor(context, 0.616, 1);
        CGContextStrokePath(context);
    
        CGContextAddArc(context, 0, -2, r, 0, 2*M_PI, true);
        CGContextSetGrayStrokeColor(context, 0.784, 1);
        CGContextStrokePath(context);
    
        CGContextMoveToPoint(context, 0, 0);
        CGContextAddLineToPoint(context, r * _offset.width, r * _offset.height);
    
        CGContextSetLineWidth(context, 2);
        CGContextSetGrayStrokeColor(context, 0.33, 1);
        CGContextStrokePath(context);
    }
    
    @end
    

    【讨论】:

      【解决方案2】:

      好吧,对于实际绘图,您要么必须为旋钮的每个旋转角度制作图像(更易于实现),然后再绘制正确的图像。

      (虽然对于真正逼真的 3D 外观 - 即使可能 - 编程绘图也不值得花时间,我猜。)

      或者通过代码绘制旋钮。这篇文章应该给你一个我认为的想法: http://katidev.com/blog/2008/03/07/how-to-create-a-custom-control-with-nsview/ (对于两者,鼠标事件处理和圆形和旋钮类元素的基本 NSBezerPath 绘制)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-07
        • 2019-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-11
        • 2022-11-29
        • 1970-01-01
        相关资源
        最近更新 更多