2015-04-19 18 views
7

Ich habe ein NSWindow und ein horizontales NSSlider.Ändern NSSlider bar Farbe

Ich möchte die Farbe des rechten Teils des Schiebereglers ändern, wenn sich die Hintergrundfarbe des Fensters ändert.

enter image description here

enter image description here

Derzeit ist der rechte Teil der Bar nicht mehr sichtbar, wenn das Fenster Hintergrund dunkel ist.

Hinweis: Der Fensterhintergrund ist eigentlich ein Farbverlauf, den ich zeichne, indem ich drawRect in einer Unterklasse der Fensteransicht überschreibe.

Ich dachte, ich könnte den Schieberegler Füllfarbe ändern NSSliderCell von Subklassen und überschreiben eine Methode wie drawBarInside aber ich verstehe nicht, wie es funktioniert: soll ich ein kleines quadratisches Bild machen und es immer wieder in der rect nach der Auslosung Knopf? Oder vielleicht einfach eine farbige Linie zeichnen? Ich habe das noch nie zuvor gemacht.

Ich habe mir this question angesehen und es ist interessant, aber es geht darum, den Knopf zu zeichnen und ich brauche das jetzt nicht.

Ich hatte auch einen Blick auf this one die sehr vielversprechend schien, aber wenn ich versuche, diesen Code bar mein Schieber verschwindet zu imitieren nur ...

In this question sie drawWithFrame verwenden und es sieht interessant, aber wieder bin ich nicht sicher, wie es funktioniert.

Ich möchte dies mit meinem eigenen Code tun, anstatt eine Bibliothek zu verwenden. Könnte mir bitte jemand einen Hinweis geben, wie man das macht? :)

Ich mache das in Swift, aber ich kann Objective-C bei Bedarf lesen/verwenden.

+0

Ich denke, Sie nicht, diese Attribute von der Standard-Schnittstelle zugreifen können. Der 2. Link sieht vielversprechend aus. Ich schätze, du solltest es zum Laufen bringen. Grundsätzlich ist ein Schieberegler eine einfache Ansicht, in der der Drehknopf dem Ziehen-und-Ablegen folgt. –

Antwort

10

Das ist richtig, müssen Sie die NSSliderCell Klasse Unterklasse zu ziehen Sie die Bar oder die Knopf.

NSRect ist nur ein rechteckiger Container, den Sie in diesem Container zeichnen müssen. Ich habe ein Beispiel basierend auf einer benutzerdefinierten NSLevelIndicator gemacht, die ich in einem meiner Programme habe.

Zuerst müssen Sie die Position des Knopfes berechnen. Sie müssen auf den minimalen und maximalen Kontrollwert achten. Als nächstes zeichnen Sie eine NSBezierPath für den Hintergrund und eine andere für den linken Teil.

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

Vielen Dank, es sieht sehr hilfreich aus. Ich werde dies an Swift anpassen und es so schnell wie möglich testen. – Moritz

+0

Funktioniert wie ein Charme! Ich markiere deine Antwort als akzeptiert, und ich aktualisiere meine mit der Swift-Version, die ich aus deinem Beispiel gemacht habe. Vielen Dank ! – Moritz

+0

Es gibt * manchmal * eine kleine Unschärfe wie [diese] (https://www.evernote.com/shard/s89/sh/3815fed6-c28a-43ba-a8a5-ebe11c96f90f/47918faa41523aa7cfa4c5a0e962ae35/deep/0/BoomBox.png) auf die linke Seite des Knopfes, wenn es sich bewegt. Denkst du, ich muss die UI zwingen, irgendwo zu aktualisieren? – Moritz

9

Zuerst erstellte ich ein Bild von einem Schieberegler und kopierte es in meinem Projekt.

Dann habe ich dieses Bild in den drawBarInside Verfahren in der Bar zu ziehen rectvor die normalen, so dass wir nur den Rest Teil (ich wollte halte den blauen Teil intakt) sehen.

Dies muss in einer Unterklasse von NSSliderCell erfolgen:

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: es funktioniert. :)

Con: Es entfernt die abgerundeten Kanten der Bar und ich habe noch keinen Weg gefunden, dies neu zu zeichnen.

custom nsslider

UPDATE:

Ich habe eine Swift-Version der akzeptierte Antwort, es funktioniert sehr gut:

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

Funktioniert gut. Zeit, um die obere Antwort für Swift 3, 4 zu aktualisieren. Im nächsten Jahr kannst du es mit Swift 5 und Swift 6 noch einmal machen, und dann wird Apple eine neue Sprache herausbringen und die ganze Arbeit ablehnen, die du getan hast. – wcochran