2012-09-18 12 views
9

Podjęłam próbę narysowania niestandardowych przycisków NS, ale wydaje mi się, że wymyślam tutaj koło. Czy istnieje sposób, aby po prostu zastąpić domyślne obrazy używane do zamykania, minimalizowania i powiększania?Jak narysować niestandardowe elementy sterujące okna (przyciski zamykania, minimalizowania i powiększania)

Kilka aplikacje już zrobić:

  • OSX 10.8 za Przypomnienia app (pojawiają się one ciemnoszary, gdy okno nie jest kluczem, vs najbardziej pojawiają jasnoszary)
  • Tweetbot (Wszystkie przyciski wyglądają zupełnie niestandardowy)

Więcej informacji:

mogę wygenerować domyślnych systemowych jako taki standardWindowButton:NSWindowCloseButton. Ale stamtąd setImage Seter nie zmienia wyglądu przycisków.

Odpowiedz

26

Edytuj : Od kiedy to napisałem, INAppStore zaimplementował całkiem niezły sposób na zrobienie tego z INWindowButton. Jeśli szukasz rozwiązania typu "przeciągnij i upuść", sprawdź poniższy kod, ale nadal pomoże Ci wdrożyć własne.


Więc nie mogłem znaleźć sposobu na zmianę standardWindowButton s. Oto opis tworzenia własnych przycisków.

Uwaga: Dostępne są 4 stany przyciski mogą być w

  • okna nieaktywnego Window Inactive Controls
  • Okno aktywne - normalna Window Active Normal Controls
  • Okno aktywne - unoszą Window Active Hover Controls
  • aktywne okno - naciśnij Window Active Press Controls

W przewodniku!

Krok 1: ukryć istniejące wcześniej przyciski

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

Krok 2: Konfiguracja widoku w konstruktorze Interface

Zauważysz na najechaniu przyciski wszystkie zmiany ich aktywowaniu stan, więc potrzebujemy widoku kontenera, aby podnieść wskaźnik.

  • Utwórz widok kontenera o szerokości 54 pikseli i wysokości 16 pikseli.
  • Utwórz 3 kwadratowe style NSButton s, każdy o rozmiarze 14 pikseli x 16 pikseli w widoku kontenera.
  • Przestań przyciskami, aby uzyskać 6px odstępów między nimi.

konfiguracja przycisków

  • W Inspektorze atrybutów, należy ustawić właściwość dla każdego przycisku Image do okna czynne normalnego obrazu.
  • Ustawia właściwość obrazu Alternate na obraz aktywowany przez okno.
  • Wyłączenie Bordered.
  • Ustaw Type na Momentary Change.
  • Dla każdego przycisku ustawić identyfikator do close, minimize lub zoom (poniżej zobaczysz, jak można to wykorzystać, aby podklasa NSButton prostsze)

Krok 3: podklasa widok kontenera & przycisków

opakowaniu:

Utwórz nowy plik, podklasy NSView. Tutaj zamierzamy użyć Centrum powiadomień, aby poinformować przyciski, kiedy powinny przejść do swojego stanu zawisu.

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];   
} 

Przyciski:

Utwórz nowy plik, tym razem podklasę NSButton. Ten jest nieco więcej do wyjaśnienia, więc po prostu opublikuję cały kod.

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 

W IB ustawić niestandardową klasę widoku kontenera i wszystkie 3 przyciski do swoich klasach że właśnie utworzone.

Krok 4: Ustaw działania przycisków

Metody te, zwane od kontrolera widok, są takie same jak standardWindowButton s'. Połącz je z przyciskami w 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]; 
} 

Krok 5: Dodawanie widoku do okna

mam oddzielną konfigurację xib i widok kontrolera specjalnie dla kontroli okiennych. Kontroler widoku nazywa 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]; 

Nadzieja to pomaga. To dość długa wiadomość, jeśli uważasz, że popełniłem błąd lub coś zostawiłem, daj mi znać.

+1

To nie jest długa wiadomość, to ** świetna ** odpowiedź. Dodane do zakładek do wykorzystania w przyszłości. – sosborn

+0

@sosborn dzięki, doceń informację zwrotną :) –

+0

Ten post nie traktuje problemów, takich jak dostępność i zachowanie na pierwszym myszy. Są trudne do uzyskania ... najlepiej jest użyć przycisków systemu! (Zauważ, że od Yosemite paski narzędzi i paski tytułu okna mogą być łączone, a przyciski okna będą wyśrodkowane w pionie.) – jtbandes

Powiązane problemy