2015-04-19 33 views
7

Tôi đã có NSWindow và một NSSlider ngang.Thay đổi màu thanh NSSlider

Tôi muốn thay đổi màu của phần bên phải của thanh trượt khi màu nền cửa sổ thay đổi.

enter image description here

enter image description here

Hiện nay, phần bên phải của thanh là không nhìn thấy được nữa khi nền cửa sổ là bóng tối.

Lưu ý: nền cửa sổ thực sự là một gradient tôi vẽ bằng cách ghi đè drawRect trong lớp con của chế độ xem cửa sổ. Tôi nghĩ tôi có thể thay đổi màu tô thanh trượt bằng cách phân lớp NSSliderCell và ghi đè một số phương thức như drawBarInside nhưng tôi không hiểu cách hoạt động: tôi nên tạo một hình vuông nhỏ và vẽ nó nhiều lần nhô lên? Hoặc có thể chỉ vẽ một đường màu? Tôi chưa bao giờ làm điều này trước đây.

Tôi đã xem this question và thật thú vị nhưng đó là về cách vẽ núm và tôi không cần điều đó ngay bây giờ.

Tôi cũng đã có một cái nhìn tại this one mà dường như rất hứa hẹn, nhưng khi tôi cố gắng bắt chước mã này thanh trượt của tôi chỉ biến mất ...

Trong this question họ sử dụng drawWithFrame và có vẻ thú vị nhưng một lần nữa tôi không chắc nó hoạt động ra sao.

Tôi muốn thực hiện việc này bằng mã của riêng tôi thay vì sử dụng thư viện. Ai đó có thể cho tôi một gợi ý về làm thế nào để làm điều này xin vui lòng? :)

Tôi đang làm điều này trong Swift nhưng tôi có thể đọc/sử dụng Objective-C nếu cần.

+0

Tôi đoán bạn không thể truy cập những thuộc tính từ giao diện chuẩn. Liên kết thứ 2 có vẻ đầy hứa hẹn. Tôi đoán bạn nên làm cho nó chạy. Về cơ bản một thanh trượt là một cái nhìn đơn giản, nơi núm sau kéo-n-thả. –

Trả lời

10

này là chính xác, bạn phải phân lớp lớp NSSliderCell để vẽ lại thanh hoặc núm.

NSRect chỉ là một vùng chứa hình chữ nhật, bạn phải vẽ bên trong vùng chứa này. Tôi đã tạo một ví dụ dựa trên một tuỳ chỉnh NSLevelIndicator mà tôi có trong một chương trình của mình.

Trước tiên, bạn cần tính toán vị trí của núm. Bạn phải chú ý đến giá trị tối thiểu và tối đa của điều khiển. Tiếp theo, bạn vẽ NSBezierPath cho nền và hình nền khác cho phần bên trái.

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

Cảm ơn rất nhiều, có vẻ rất hữu ích. Tôi sẽ thích nghi điều này với Swift và kiểm tra nó càng sớm càng tốt. – Moritz

+0

Làm việc như một sự quyến rũ! Tôi đang đánh dấu câu trả lời của bạn là được chấp nhận, và tôi đang cập nhật của tôi với phiên bản Swift tôi đã làm từ ví dụ của bạn. Cảm ơn bạn ! – Moritz

+0

Có * đôi khi * một chút mờ như [this] (https://www.evernote.com/shard/s89/sh/3815fed6-c28a-43ba-a8a5-ebe11c96f90f/47918faa41523aa7cfa4c5a0e962ae35/deep/0/BoomBox.png) bật bên trái của núm khi nó di chuyển. Bạn có nghĩ rằng tôi cần phải buộc các giao diện người dùng để làm mới một nơi nào đó? – Moritz

9

Trước tiên, tôi đã tạo hình ảnh thanh trượt và sao chép hình ảnh đó trong dự án của mình.

Sau đó, tôi đã sử dụng hình ảnh này trong phương pháp drawBarInside để vẽ trong thanh recttrước bình thường một, vì vậy chúng tôi sẽ chỉ nhìn thấy phần còn lại (Tôi muốn giữ một phần màu xanh còn nguyên vẹn).

này phải được thực hiện trong một lớp con của 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: nó hoạt động. :)

Con: nó loại bỏ các cạnh tròn của thanh và tôi chưa tìm được cách vẽ lại.

custom nsslider

UPDATE:

tôi đã thực hiện một phiên bản Swift của câu trả lời được chấp nhận, nó hoạt động rất tốt:

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

Hoạt động tuyệt vời. Thời gian để cập nhật câu trả lời trên cho Swift 3, 4. Năm tới bạn có thể làm lại với Swift 5, và sau đó là Swift 6, và sau đó Apple sẽ phát hành một ngôn ngữ mới và không dùng hết tất cả công việc bạn đã làm. – wcochran

Các vấn đề liên quan