2012-01-04 5 views
0

Я пытаюсь реализовать пользовательский круговой слайдер, который использует образы, чтобы нарисовать циферблат и ручку. Для этой цели я подклассифицировал NSSliderCell и переопределил методы drawBarInside и drawKnob. Теперь, когда я оставляю ползунок по умолчанию (по горизонтали), мои функции рисования вызывают и образы рисуются вместо бара по умолчанию и ручки (конечно, все выглядит неправильно, поскольку изображения сделаны для кругового слайдера, но они здесь). Но как только я изменю тип ползунка на круговое (либо в IB, либо установив self.sliderType = NSCircularSlider; в ячейку слайдера), эти два метода никогда не вызываются и мои изображения не рисуются (создается только стандартный диск). Я что-то забыл, или круговые ползунки не могут быть настроены вообще?Пользовательский круговой NSSlider

Вот мой код: DialSliderCell подкласс NSSliderCell и инициируются и установить в классе под названием DialSlider, который является подклассом NSSlider (этот класс ничего не делает в то время).

@implementation DialSliderCell 

- (id)init { 
    self = [super init]; 
    if (self) { 
     dialImage = [NSImage imageNamed:@"dial"]; 
     knobImage = [NSImage imageNamed:@"dialKnob"]; 
     self.sliderType = NSCircularSlider; 
    } 
    NSLog(@"init"); 
    return self; 
} 

- (void)drawKnob:(NSRect)knobRect { 
    knobRect.size = knobImage.size; 
    [knobImage drawInRect:knobRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 
    NSLog(@"drawKnob"); 
} 

- (void)drawBarInside:(NSRect)aRect flipped:(BOOL)flipped { 
    [dialImage drawInRect:aRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 
    NSLog(@"drawBarInside"); 
} 

@end 
+0

Просто короткое примечание к любому копируете этот код: Это только при использовании ARC. В противном случае вам нужно сохранить полученные изображения из -imageNamed: когда вы поместите их в переменные экземпляра dialImage/knobImage. – uliwitness

+0

Исправить. Код был написан в среде ARC, поэтому сохранение/освобождение не выполняется. – pajevic

ответ

2

Я решил эту проблему, переопределив метод drawInteriorWithFrame. Решение основано на исходном методе. Я просто удалил все, что не было связано с круговыми слайдерами, удалило оригинальную графику и добавило свое. Геометрия почти полностью оригинальна.

- (void) drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView*)controlView 
{ 
    cellFrame = [self drawingRectForBounds: cellFrame]; 
    _trackRect = cellFrame; 

    NSPoint knobCenter; 
    NSPoint point; 
    float fraction, angle, radius; 

    knobCenter = NSMakePoint(NSMidX(cellFrame), NSMidY(cellFrame)); 

    [dialImage drawInRect:cellFrame fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 

    int knobDiameter = knobImage.size.width; 
    int knobRadius = knobDiameter/2; 
    fraction = ([self floatValue] - [self minValue])/([self maxValue] - [self minValue]); 
    angle = (fraction * (2.0 * M_PI)) - (M_PI/2.0); 
    radius = (cellFrame.size.height/2) - knobDiameter; 
    point = NSMakePoint((radius * cos(angle)) + knobCenter.x, 
        (radius * sin(angle)) + knobCenter.y); 

    NSRect dotRect; 
    dotRect.origin.x = point.x - knobRadius; 
    dotRect.origin.y = point.y - knobRadius; 
    dotRect.size = knobImage.size; 
    [knobImage drawInRect:dotRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 
} 

Размер cellFrame прямоугольника устанавливается равным размеру dialImage изображения.

Обратите внимание, что описанный выше способ, кажется, не дозвонились автоматически, поэтому я также должен переопределить метод drawWithFrame и сделать его называют drawInteriorWithFrame:

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView 
{ 
    [self drawInteriorWithFrame:cellFrame inView:controlView]; 
} 
+0

Отлично, спасибо. Я заметил, что изображение рисует вверх дном, поэтому вам нужно использовать 'drawInRect: fromRect: operation: fraction: respectFlipped: hints:', чтобы отобразить изображение в правильной ориентации. – VinceFior

+0

Кроме того, * вы не можете установить _trackRect *, если вы отправляете свое приложение в App Store, поскольку, по-видимому, это свойство рассматривается с использованием частного API. – VinceFior

0

Все, что я могу думать о том, что вы не перекрывая все назначенные инициализаторов

из документации ...

Назначенные Инициализаторы. При подклассификации NSCell вы должны реализовать все назначенные инициализаторы . Этими методами являются: init, initWithCoder :, initTextCell :, и initImageCell :.

Возможно, один из других 3 называется круговым слайдером.

+0

Привет Уоррен. На самом деле я, но я решил не включать их здесь для простоты. В любом случае, как я уже сказал, «DialSliderCell» создается вручную в «DialSlider», поэтому я совершенно уверен, какой метод init используется. Но если я задаю класс своей ячейки слайдера в IB, тогда он использует 'initWithCoder', который делает никакой разницы в моей проблеме. – pajevic

+0

Когда ваш слайдер не имеет аналогов с XIB, он открещивает как представление, так и ячейку. Это означает, что для того, чтобы он использовал правильный класс ячеек, вам нужно дважды щелкнуть свое представление в XIB, чтобы он выбрал NSSliderCell, а также установил свой собственный класс, а не только представление NSSlider. Вы это делаете? – uliwitness

Смежные вопросы