Делаем круговой NSSlide похожим на GarageBand - PullRequest
3 голосов
/ 13 июня 2010

Я новичок в рисовании с Какао, и я делаю некоторое программное обеспечение, которое будет иметь ползунки, подобные этим, найденные в GarageBand:

Ползунки GB http://img33.imageshack.us/img33/2668/schermafbeelding2010061r.png

Они выглядят красиво и их можно контролировать, перемещая мышь вверх и вниз.

Можете ли вы помочь мне с настройкой NSSliders путем выделения их подклассов, чтобы я мог заставить их выглядеть и вести себя точно так же, как в GarageBand? Спасибо.


У меня есть одно изображение для ручки, которая должна вращаться, поскольку они не должны быть в 3D.

Ответы [ 2 ]

4 голосов
/ 13 июня 2010

Самый простой способ - создать подкласс NSView, который обрабатывает как управление мышью, так и рисование.

Существует пример кода, который может помочь вам начать с именем "TLayer".Это часть примеров XCode 3.1.4.Он содержит круговой пользовательский вид, который контролирует смещение и радиус тени, нарисованной для слоев.Его легко понять и легко расширить.

Примечание: поскольку его, кажется, нет на веб-сайте Apple, я вставил приведенные ниже источники.


ShadowOffsetView.ч

#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
1 голос
/ 13 июня 2010

Что ж, для реального рисования вам нужно было бы иметь изображения для каждого угла поворота ручки (проще реализовать), а затем просто нарисовать нужный.

(Хотя для реального реалистичного 3DПосмотрите - даже если это возможно - программное рисование не стоило бы своего времени, я думаю.)

Или нарисовать ручку по коду.Эта статья должна дать вам представление: http://katidev.com/blog/2008/03/07/how-to-create-a-custom-control-with-nsview/ (как для обработки событий мыши, так и для базового рисования NSBezerPath круглых и вращающихся элементов в виде ручек)

...