Делаем круговой NSSlide похожим на GarageBand
Я новичок в рисовании с Какао, и я делаю некоторые программы, которые будут иметь ползунки, подобные этим, найденные в GarageBand:
http://img33.imageshack.us/img33/2668/schermafbeelding2010061r.png
Они выглядят красиво и могут управляться, перемещая мышь вверх и вниз.
Можете ли вы помочь мне с настройкой NSSliders путем выделения их подклассов, чтобы я мог заставить их выглядеть и вести себя точно так же, как в GarageBand? Благодарю.
У меня есть одно изображение для ручки, которая должна вращаться, поскольку они не должны быть в 3D .
2 ответа
Самый простой способ - создать подкласс 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
Что ж, для реального рисования вам нужно было бы иметь изображения для каждого угла поворота ручки (проще реализовать), а затем просто нарисовать нужный.
(Хотя для реального реалистичного трехмерного вида - даже если это возможно - программное рисование не стоило бы своего времени, я думаю.)
Или нарисуйте ручку по коду. Эта статья должна дать вам идею, я думаю: http://katidev.com/blog/2008/03/07/how-to-create-a-custom-control-with-nsview/(Для обоих, обработка событий мыши и базовое рисование NSBezerPath круглых и вращающихся ручкообразных элементов)