2015-04-19 2 views
7

У меня есть NSWindow и горизонтальный NSSlider.Изменить цвет панели NSSlider

Я хочу изменить цвет правой части ползунка при изменении цвета фона окна.

enter image description here

enter image description here

В настоящее время, в правой части панели не видно больше, когда фон окна темно.

Примечание: фон окна на самом деле является градиентом, который я рисую, переопределяя drawRect в подклассе вида окна.

Я думал, что я мог бы изменить цвет заливки ползунок на подклассы NSSliderCell и переопределение некоторый метод, как drawBarInside, но я не понимаю, как это работает: я должен сделать небольшое квадратное изображение и сделать его несколько раз в прямоугольнику после регулятор? Или, может быть, просто нарисуйте цветную линию? Я никогда не делал это раньше.

Я просмотрел this question, и это интересно, но это касается рисования ручки, и мне это не нужно пока.

Я также имел взгляд на this one, который казался очень перспективным, но когда я пытаюсь имитировать этот код моего ползунок просто исчезает ...

В this question они используют drawWithFrame и это выглядит интересно, но опять я не знаю, как это работает.

Я бы хотел сделать это с помощью своего собственного кода вместо использования библиотеки. Может ли кто-нибудь дать мне подсказку о том, как это сделать, пожалуйста? :)

Я делаю это в Swift, но при необходимости могу прочитать/использовать Objective-C.

+0

Я думаю, вы не можете получить доступ к этим атрибутам из стандартного интерфейса. Второе звено выглядит многообещающим. Я думаю, вы должны запустить его. В основном слайдер представляет собой простой вид, где ручка следует за drag-n-drop. –

ответ

10

Это правильно, вы должны наследоваться NSSliderCell класс до перерисовать планку или ручка.

NSRect - это просто прямоугольный контейнер, вы должны нарисовать внутри этого контейнера. Я сделал пример, основанный на пользовательском NSLevelIndicator, который у меня есть в одной из моих программ.

Сначала вам нужно рассчитать положение ручки. Вы должны обратить внимание на минимальное и максимальное значение контроля. Затем вы нарисуете NSBezierPath для фона и другую для левой части.

Custom NSSlider control bar

#import "MyCustomSlider.h" 

@implementation MyCustomSlider 

- (void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped { 

// [super drawBarInside:rect flipped:flipped]; 

    rect.size.height = 5.0; 

    // Bar radius 
    CGFloat barRadius = 2.5; 

    // Knob position depending on control min/max value and current control value. 
    CGFloat value = ([self doubleValue] - [self minValue])/([self maxValue] - [self minValue]); 

    // Final Left Part Width 
    CGFloat finalWidth = value * ([[self controlView] frame].size.width - 8); 

    // Left Part Rect 
    NSRect leftRect = rect; 
    leftRect.size.width = finalWidth; 

    NSLog(@"- Current Rect:%@ \n- Value:%f \n- Final Width:%f", NSStringFromRect(rect), value, finalWidth); 

    // Draw Left Part 
    NSBezierPath* bg = [NSBezierPath bezierPathWithRoundedRect: rect xRadius: barRadius yRadius: barRadius]; 
    [NSColor.orangeColor setFill]; 
    [bg fill]; 

    // Draw Right Part 
    NSBezierPath* active = [NSBezierPath bezierPathWithRoundedRect: leftRect xRadius: barRadius yRadius: barRadius]; 
    [NSColor.purpleColor setFill]; 
    [active fill]; 


} 

@end 
+0

Большое спасибо, это выглядит очень полезно. Я адаптирую это для Swift и проверю его, как только смогу. – Moritz

+0

Работает как очарование! Я отмечаю ваш ответ как принятый, и я обновляю мою версию Swift, которую я сделал из вашего примера. Спасибо ! – Moritz

+0

Там * иногда * немного размывается, как [это] (https://www.evernote.com/shard/s89/sh/3815fed6-c28a-43ba-a8a5-ebe11c96f90f/47918faa41523aa7cfa4c5a0e962ae35/deep/0/BoomBox.png) on слева от ручки, когда она перемещается. Как вы думаете, мне нужно заставить интерфейс обновиться где-нибудь? – Moritz

9

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

Тогда я использовал этот образ в методе drawBarInside рисовать в баре rectдо того нормальных, так что мы видим только часть остатка (я хотел бы сохранить синюю часть нетронутой).

Это должно быть сделано в подклассе NSSliderCell:

class CustomSliderCell: NSSliderCell { 

    let bar: NSImage 

    required init(coder aDecoder: NSCoder) { 
     self.bar = NSImage(named: "bar")! 
     super.init(coder: aDecoder) 
    } 

    override func drawBarInside(aRect: NSRect, flipped: Bool) { 
     var rect = aRect 
     rect.size = NSSize(width: rect.width, height: 3) 
     self.bar.drawInRect(rect) 
     super.drawBarInside(rect, flipped: flipped) 
    } 

} 

Pro: она работает. :)

Con: он удаляет закругленные края бара, и я еще не нашел способ перерисовать его.

custom nsslider

UPDATE:

Я сделал Swift версию принятого ответа, она работает очень хорошо:

class CustomSliderCell: NSSliderCell { 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 

    override func drawBarInside(aRect: NSRect, flipped: Bool) { 
     var rect = aRect 
     rect.size.height = CGFloat(5) 
     let barRadius = CGFloat(2.5) 
     let value = CGFloat((self.doubleValue - self.minValue)/(self.maxValue - self.minValue)) 
     let finalWidth = CGFloat(value * (self.controlView!.frame.size.width - 8)) 
     var leftRect = rect 
     leftRect.size.width = finalWidth 
     let bg = NSBezierPath(roundedRect: rect, xRadius: barRadius, yRadius: barRadius) 
     NSColor.orangeColor().setFill() 
     bg.fill() 
     let active = NSBezierPath(roundedRect: leftRect, xRadius: barRadius, yRadius: barRadius) 
     NSColor.purpleColor().setFill() 
     active.fill() 
    } 

} 
+1

Отлично работает. Время для обновления верхнего ответа для Swift 3, 4. В следующем году вы можете сделать это снова с помощью Swift 5, а затем Swift 6, а затем Apple выйдет с новым языком и обесценит всю работу, которую вы сделали. – wcochran