2012-09-18 26 views
9

我已經嘗試繪製自定義NSButton,但似乎我在這裏重新發明了輪子。有沒有辦法只更換用於關閉,最小化和縮放按鈕的默認圖像?如何繪製自定義窗口控件(關閉,最小化和縮放按鈕)

幾個應用程序已經做到這一點:

  • OSX 10.8的提醒應用程序(它們出現的窗口不是關鍵,深灰色VS大部分出現淺灰色)
  • Tweetbot(所有按鈕的外觀完全定製)

更多信息:

我可以生成系統默認爲這樣standardWindowButton:NSWindowCloseButton。但是從那裏起,setImage setter不會改變按鈕的外觀。

回答

26

編輯:由於我寫了這個,INAppStore已經實現了一個很好的方式來與INWindowButton做到這一點。如果您正在尋找拖放解決方案檢查,但下面的代碼仍然可以幫助您實現自己的解決方案。


所以我找不到方法來改變standardWindowButton s。以下是我如何創建自己的按鈕的演練。

注:有4種狀態的按鈕可以是

  • 窗口INACTIVE Window Inactive Controls
  • 窗口活性 - 正常Window Active Normal Controls
  • 窗口活性 - 懸停Window Active Hover Controls
  • 窗口活性 - 按Window Active Press Controls

在演練!

第1步:隱藏的預先存在的按鈕

NSButton *windowButton = [self standardWindowButton:NSWindowCloseButton]; 
[windowButton setHidden:YES]; 
windowButton = [self standardWindowButton:NSWindowMiniaturizeButton]; 
[windowButton setHidden:YES]; 
windowButton = [self standardWindowButton:NSWindowZoomButton]; 
[windowButton setHidden:YES]; 

第2步:設置在界面生成器視圖

你會發現懸停的按鈕都在改變自己的懸停狀態,所以我們需要一個容器視圖來拾取懸停。

  • 創建容器視圖爲54px寬×16px高。
  • 創建3個方形樣式NSButton s,每個14px寬×16px高的容器視圖內。
  • 將按鈕分隔開來,所以它們之間有6px的空白。

設置的按鈕

  • 在屬性檢查員,所述Image屬性爲每個按鈕設定爲窗口活性正常圖像。
  • Alternate圖像屬性設置爲窗口活動按下圖像。
  • 轉過Bordered關閉。
  • Type設置爲Momentary Change
  • 對於每個按鈕設置標識符closeminimizezoom(下面你會看到你如何使用這個方法,使NSButton子類簡單)

第3步:子類的容器視圖&按鈕

集裝箱:

創建一個新的文件,子類的NSView。在這裏,我們將使用通知中心告訴按鈕何時切換到懸停狀態。

HMTrafficLightButtonsContainer.m

// Tells the view to pick up the hover event 
- (void)viewDidMoveToWindow { 
    [self addTrackingRect:[self bounds] 
        owner:self 
       userData:nil 
      assumeInside:NO]; 
} 

// When the mouse enters/exits we send out these notifications 
- (void)mouseEntered:(NSEvent *)theEvent { 
    [[NSNotificationCenter defaultCenter] postNotificationName:@"HMTrafficButtonMouseEnter" object:self]; 
} 
- (void)mouseExited:(NSEvent *)theEvent { 
    [[NSNotificationCenter defaultCenter] postNotificationName:@"HMTrafficButtonMouseExit" object:self];   
} 

按鈕:

創建一個新的文件,這個時候子類NSButton。這一個更多的解釋,所以我只是發佈所有的代碼。

HMTrafficLightButton.m

@implementation HMTrafficLightButton { 
    NSImage *inactive; 
    NSImage *active; 
    NSImage *hover; 
    NSImage *press; 
    BOOL activeState; 
    BOOL hoverState; 
    BOOL pressedState; 
} 

-(id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if (self) {   
     [self setup]; 
    } 
    return self; 
} 

- (id)initWithFrame:(NSRect)frameRect { 
    self = [super initWithFrame:frameRect]; 
    if (self) { 
     [self setup]; 
    } 
    return self; 
} 

- (void)setup { 
    // Setup images, we use the identifier to chose which image to load 
    active = [NSImage imageNamed:[NSString stringWithFormat:@"window-button-%@-active",self.identifier]]; 
    hover = [NSImage imageNamed:[NSString stringWithFormat:@"window-button-%@-hover",self.identifier]]; 
    press = [NSImage imageNamed:[NSString stringWithFormat:@"window-button-%@-press",self.identifier]]; 
    inactive = [NSImage imageNamed:@"window-button-all-inactive"]; 

    // Checks to see if window is active or inactive when the `init` is called 
    if ([self.window isMainWindow] && [[NSApplication sharedApplication] isActive]) { 
     [self setActiveState]; 
    } else { 
     [self setInactiveState]; 
    } 

    // Watch for hover notifications from the container view 
    // Also watches for notifications for when the window 
    // becomes/resigns main 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(setActiveState) 
               name:NSWindowDidBecomeMainNotification object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(setInactiveState) 
               name:NSWindowDidResignMainNotification object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(hoverIn) 
               name:@"HMTrafficButtonMouseEnter" 
               object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(hoverOut) 
               name:@"HMTrafficButtonMouseExit" 
               object:nil]; 
} 

- (void)mouseDown:(NSEvent *)theEvent { 
    pressedState = YES; 
    hoverState = NO; 
    [super mouseDown:theEvent]; 
} 

- (void)mouseUp:(NSEvent *)theEvent { 
    pressedState = NO; 
    hoverState = YES; 
    [super mouseUp:theEvent]; 
} 

- (void)setActiveState { 
    activeState = YES; 
    if (hoverState) { 
     [self setImage:hover]; 
    } else { 
     [self setImage:active]; 
    } 
} 

- (void)setInactiveState { 
    activeState = NO; 
    [self setImage:inactive]; 
} 

- (void)hoverIn { 
    hoverState = YES; 
    [self setImage:hover]; 
} 

- (void)hoverOut { 
    hoverState = NO; 
    if (activeState) { 
     [self setImage:active]; 
    } else { 
     [self setImage:inactive]; 
    } 
} 

- (void)dealloc { 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

@end 

在IB設置的容器視圖的自定義類,所有3個按鈕各自的類,我們剛剛創建。

步驟4:設定按鈕動作

這些方法中,從視圖控制器調用,是一樣的standardWindowButton S'。將它們鏈接到IB中的按鈕。

- (IBAction)clickCloseButton:(id)sender { 
    [self.view.window close]; 
} 
- (IBAction)clickMinimizeButton:(id)sender { 
    [self.view.window miniaturize:sender]; 
} 
- (IBAction)clickZoomButton:(id)sender { 
    [self.view.window zoom:sender]; 
} 

5步:添加視圖到窗口

我對窗口控件單獨XIB和視圖控制器設置具體。視圖控制器被稱爲HMWindowControlsController

(HMWindowControlsController*) windowControlsController = [[HMWindowControlsController alloc] initWithNibName:@"WindowControls" bundle:nil]; 
NSView *windowControlsView = windowControlsController.view; 
// Set the position of the window controls, the x is 7 px, the y will 
// depend on your titlebar height. 
windowControlsView.frame = NSMakeRect(7.0, 10.0, 54.0, 16.0); 
// Add to target view 
[targetView addSubview:windowControlsView]; 

希望這有助於。這是一篇相當冗長的文章,如果您認爲我犯了一個錯誤或者遺漏了某些內容,請告訴我。

+1

這不是一個冗長的帖子,它是一個**很棒的**答案。爲未來參考收藏。 – sosborn

+0

@sosborn謝謝,欣賞反饋:) –

+0

本文不處理可訪問性和第一鼠標行爲等問題。這些都很難得到正確的...最好的事情就是使用系統的按鈕! (請注意,截至優勝美地,工具欄和窗口標題欄可以組合,窗口按鈕將垂直居中。) – jtbandes

相關問題