2010-01-03 21 views
5

Sto provando a riscrivere un'applicazione che ho per Windows in Objective-C per il mio Mac, e voglio essere in grado di fare qualcosa come il caldo di Mac angoli. Se metto il mio mouse sul lato sinistro dello schermo renderà visibile una finestra, se la sposto al di fuori della posizione della finestra la finestra si nasconderà di nuovo. (la finestra verrebbe spostata sul lato sinistro dello schermo).Fare entrare e uscire una finestra dal bordo dello schermo

Qualcuno sa dove posso trovare qualche codice demo (o riferimento) su come farlo, o almeno come dire dove si trova il mouse, anche se l'applicazione corrente non è in cima. (non so come dire questo, troppo usato per il mondo Windows).

Grazie

-Brad

+0

Questo suona più come finestre come mensola di Quicksilver e Appunti di Storia, e (opzionalmente) elenco di contatti di Adium, in grado di entrare e uscire dal lato dello schermo quando il mouse colpisce quel bordo. E 'questo quello a cui stai pensando? –

+0

Sì, questo è quello che sto pensando. – Brad

risposta

1

Ecco cosa mi è venuta. Grazie a Peter per i suggerimenti di cui sopra.

@interface SlidingWindow : NSWindow 
    { 
     CGRectEdge _slidingEdge; 
     NSView *_wrapperView; 
    } 


    @property (nonatomic, assign) CGRectEdge slidingEdge; 
    @property (nonatomic, retain) NSView *wrapperView; 

    -(id)initWithContentRect:(NSRect) contentRect 
        styleMask:(unsigned int) styleMask 
        backing:(NSBackingStoreType) backingType 
         defer:(BOOL) flag; 

    - (NSView*)wrapperViewWithFrame:(NSRect)bounds; 

    - (BOOL)mayOrderOut; 

    @end 

    @interface SlidingWindow() 

    - (void)adjustWrapperView; 

    - (void)setWindowWidth:(NSNumber*)width; 
    - (void)setWindowHeight:(NSNumber*)height; 

    @end 


    @implementation SlidingWindow 


@synthesize slidingEdge = _slidingEdge; 
@synthesize wrapperView = _wrapperView; 


- (id)initWithContentRect:(NSRect) contentRect 
       styleMask:(unsigned int) styleMask 
        backing:(NSBackingStoreType) backingType 
        defer:(BOOL) flag 
{ 

    if ((self = [super initWithContentRect:contentRect 
           styleMask:NSBorderlessWindowMask 
            backing:backingType 
            defer:flag])) { 
     /* May want to setup some other options, 
     like transparent background or something */ 

     [self setSlidingEdge:CGRectMaxYEdge]; 
     [self setHidesOnDeactivate:YES]; 
     [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; 
    } 

    return self; 
} 

- (NSView*)wrapperViewWithFrame:(NSRect)bounds 
{ 
    return [[[NSView alloc] initWithFrame:bounds] autorelease]; 
} 

- (void)adjustWrapperView 
{ 
    if (self.wrapperView == nil) { 
     NSRect frame = [self frame]; 
     NSRect bounds = NSMakeRect(0, 0, frame.size.width, frame.size.height); 
     NSView *wrapperView = [self wrapperViewWithFrame:bounds]; 
     NSArray *subviews = [[[[self contentView] subviews] copy] autorelease]; 

     for (NSView *view in subviews) { 
      [wrapperView addSubview:view]; 
     } 

     [wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 
     [[self contentView] addSubview:wrapperView]; 

     self.wrapperView = wrapperView; 
    } 

    switch (self.slidingEdge) { 
     case CGRectMaxXEdge: 
      [self.wrapperView setAutoresizingMask:(NSViewHeightSizable | NSViewMaxXMargin)]; 
      break; 

     case CGRectMaxYEdge: 
      [self.wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)]; 
      break; 

     case CGRectMinXEdge: 
      [self.wrapperView setAutoresizingMask:(NSViewHeightSizable | NSViewMinXMargin)]; 
      break; 

     case CGRectMinYEdge: 
     default: 
      [self.wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; 
    } 
} 

- (void)makeKeyAndOrderFront:(id)sender 
{ 
    [self adjustWrapperView]; 

    if ([self isVisible]) { 
     [super makeKeyAndOrderFront:sender]; 
    } 
    else { 
     NSRect screenRect = [[NSScreen menubarScreen] visibleFrame]; 
     NSRect windowRect = [self frame]; 

     CGFloat x; 
     CGFloat y; 
     NSRect startWindowRect; 
     NSRect endWindowRect; 

     switch (self.slidingEdge) { 
      case CGRectMinXEdge: 
       x = 0; 
       y = (screenRect.size.height - windowRect.size.height)/2 + screenRect.origin.y; 
       startWindowRect = NSMakeRect(x - windowRect.size.width, y, 0, windowRect.size.height); 
       break; 

      case CGRectMinYEdge: 
       x = (screenRect.size.width - windowRect.size.width)/2 + screenRect.origin.x; 
       y = 0; 
       startWindowRect = NSMakeRect(x, y - windowRect.size.height, windowRect.size.width, 0); 
       break; 

      case CGRectMaxXEdge: 
       x = screenRect.size.width - windowRect.size.width + screenRect.origin.x; 
       y = (screenRect.size.height - windowRect.size.height)/2 + screenRect.origin.y; 
       startWindowRect = NSMakeRect(x + windowRect.size.width, y, 0, windowRect.size.height); 
       break; 

      case CGRectMaxYEdge: 
      default: 
       x = (screenRect.size.width - windowRect.size.width)/2 + screenRect.origin.x; 
       y = screenRect.size.height - windowRect.size.height + screenRect.origin.y; 
       startWindowRect = NSMakeRect(x, y + windowRect.size.height, windowRect.size.width, 0); 
     } 

     endWindowRect = NSMakeRect(x, y, windowRect.size.width, windowRect.size.height); 

     [self setFrame:startWindowRect display:NO animate:NO]; 

     [super makeKeyAndOrderFront:sender]; 

     [self setFrame:endWindowRect display:YES animate:YES]; 

     [self performSelector:@selector(makeResizable) 
        withObject:nil 
        afterDelay:1]; 
    } 
} 

- (void)makeResizable 
{ 
    NSView *wrapperView = self.wrapperView; 
    NSRect frame = [self frame]; 
    NSRect bounds = NSMakeRect(0, 0, frame.size.width, frame.size.height); 

    [wrapperView setFrame:bounds]; 
    [wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 
} 

- (void)orderOut:(id)sender 
{ 
    [self adjustWrapperView]; 

    NSRect startWindowRect = [self frame]; 
    NSRect endWindowRect; 

    switch (self.slidingEdge) { 
     case CGRectMinXEdge: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             0, 
             startWindowRect.size.height); 
      break; 

     case CGRectMinYEdge: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             startWindowRect.size.width, 
             0); 
      break; 

     case CGRectMaxXEdge: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x + startWindowRect.size.width, 
             startWindowRect.origin.y, 
             0, 
             startWindowRect.size.height); 
      break; 

     case CGRectMaxYEdge: 
     default: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y + startWindowRect.size.height, 
             startWindowRect.size.width, 
             0); 
    } 

    [self setFrame:endWindowRect display:YES animate:YES]; 

    switch (self.slidingEdge) { 
     case CGRectMaxXEdge: 
     case CGRectMinXEdge: 
      if (startWindowRect.size.width > 0) { 
       [self performSelector:@selector(setWindowWidth:) 
          withObject:[NSNumber numberWithDouble:startWindowRect.size.width] 
          afterDelay:0]; 
      } 
      break; 

     case CGRectMaxYEdge: 
     case CGRectMinYEdge: 
     default: 
      if (startWindowRect.size.height > 0) { 
       [self performSelector:@selector(setWindowHeight:) 
          withObject:[NSNumber numberWithDouble:startWindowRect.size.height] 
          afterDelay:0]; 
      } 
    } 

    [super orderOut:sender]; 
} 

- (void)setWindowWidth:(NSNumber*)width 
{ 
    NSRect startWindowRect = [self frame]; 
    NSRect endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             [width doubleValue], 
             startWindowRect.size.height); 

    [self setFrame:endWindowRect display:NO animate:NO];  
} 

- (void)setWindowHeight:(NSNumber*)height 
{ 
    NSRect startWindowRect = [self frame]; 
    NSRect endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             startWindowRect.size.width, 
             [height doubleValue]); 

    [self setFrame:endWindowRect display:NO animate:NO];  
} 

- (void)resignKeyWindow 
{ 
    [self orderOut:self]; 

    [super resignKeyWindow]; 
} 

- (BOOL)canBecomeKeyWindow 
{ 
    return YES; 
} 

- (void)performClose:(id)sender 
{ 
    [self close]; 
} 

- (void)dealloc 
{ 
    [_wrapperView release], _wrapperView = nil; 

    [super dealloc]; 
} 

@end 


@implementation NSScreen (MenubarScreen) 

+ (NSScreen*)menubarScreen 
{ 
    NSArray *screens = [self screens]; 

    if ([screens count] > 0) { 
     return [screens objectAtIndex:0]; 
    } 

    return nil; 
} 
@end 
+0

Dolce, grazie per il codice demo – Brad

+0

Ho appena notato che ho mescolato min & max ogni posto ma in -adjustWrapperView –

+0

@PierreBernard hai risolto il minimo e il massimo nella risposta o è ancora indietro ... inoltre, non c'è 'interfaccia @ 'per questo' @ implementation', e non è _exactly_ chiaro che cosa dovrebbe esserci dentro ... per esempio, nessuno dei 'slidingEdge' sono definiti, ecc. –

2

Stai andando a voler implementare una finestra invisibile sul bordo dello schermo con l'ordine finestra di impostare in modo che sia sempre in primo piano. Quindi, puoi ascoltare gli eventi mossi dal mouse in questa finestra.

Per impostare la finestra per essere invisibili e sulla parte superiore, fare un uso finestra sottoclasse definisce come:

[self setBackgroundColor:[NSColor clearColor]]; 
[self setExcludedFromWindowsMenu:YES]; 
[self setCanHide:NO]; 
[self setLevel:NSScreenSaverWindowLevel]; 
[self setAlphaValue:0.0f]; 
[self setOpaque:NO]; 
[self orderFrontRegardless]; 

poi, per accendere il mouse eventi spostati,

[self setAcceptsMouseMovedEvents:YES]; 

causerà la finestra per ottenere le chiamate verso:

- (void)mouseMoved:(NSEvent *)theEvent 
{ 
    NSLog(@"mouse moved into invisible window."); 
} 

Così si spera che sia sufficiente per darvi un inizio.

-Ken

+0

L'altro pezzo del puzzle sta facendo entrare e uscire la finestra. Dovrai mettere le sottoview immediate della vista del contenuto della finestra in un'altra vista e rendere * quella * la vista del contenuto. Imposta la maschera di autorizzazione della vista vista all'interno del contenuto per non ridimensionarla e pinzarla all'orlo sinistro (nel tuo esempio) della vista del contenuto. Per nascondere la finestra, ridimensiona la finestra a 1 pixel di larghezza. Per mostrarlo, ripristina la sua dimensione corretta. Se vuoi ridimensionare la finestra, dovrai cambiare la maschera di autorizzazione della vista dopo aver mostrato/nascosto la finestra. –

+0

Il motivo per cui non si dovrebbe semplicemente spostare la finestra dentro e fuori è perché l'utente potrebbe avere un'altra schermata nell'area in cui si troverà la finestra. Quindi, non stai nascondendo la finestra, ma spostandola su un'altra schermata, non su ciò che l'utente desidera. (Per quanto riguarda il modo in cui l'utente mostrerebbe la finestra in questa situazione, l'utente potrebbe avere la finestra su o giù oltre il bordo dello schermo più piccolo, dandogli qualcosa da colpire.) –

+0

Alcune cose che ho dimenticato per la finestra di sovrapposizione: [self setHasShadow: NO]; e [self setIgnoresMouseEvents: NO]; così la tua finestra invisibile non blocca effettivamente i clic. Sono sicuro al 99% che continuerai a spostare gli eventi del mouse. –

2

Ecco AutoHidingWindow - una sottoclasse di SlidingWindow che si apre quando il mouse colpisce il bordo dello schermo. Feedback benvenuto

@interface ActivationWindow : NSWindow 
{ 
    AutoHidingWindow *_activationDelegate; 
    NSTrackingArea *_trackingArea; 
} 

- (ActivationWindow*)initWithDelegate:(AutoHidingWindow*)activationDelegate; 

@property (assign) AutoHidingWindow *activationDelegate; 
@property (retain) NSTrackingArea *trackingArea; 

- (void)adjustWindowFrame; 
- (void)adjustTrackingArea; 

@end 

@interface AutoHidingWindow() 

- (void)autoShow; 
- (void)autoHide; 

@end 


@implementation AutoHidingWindow 

- (id)initWithContentRect:(NSRect) contentRect 
       styleMask:(unsigned int) styleMask 
        backing:(NSBackingStoreType) backingType 
        defer:(BOOL) flag 
{ 

    if ((self = [super initWithContentRect:contentRect 
           styleMask:NSBorderlessWindowMask 
            backing:backingType 
            defer:flag])) { 
     _activationWindow = [[ActivationWindow alloc] initWithDelegate:self]; 
    } 

    return self; 
} 

@synthesize activationWindow = _activationWindow; 

- (void)dealloc 
{ 
    [_activationWindow release], _activationWindow = nil; 

    [super dealloc]; 
} 

- (void)makeKeyAndOrderFront:(id)sender 
{ 
    [super makeKeyAndOrderFront:sender]; 

} 

- (void)autoShow 
{ 
    [self makeKeyAndOrderFront:self]; 

    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(autoHide) object:nil]; 
    [self performSelector:@selector(autoHide) withObject:nil afterDelay:2]; 
} 

- (void)autoHide 
{ 
    NSPoint mouseLocation = [NSEvent mouseLocation]; 
    NSRect windowFrame = [self frame]; 

    if (NSPointInRect(mouseLocation, windowFrame)) { 
     [self performSelector:@selector(autoHide) withObject:nil afterDelay:2]; 
    } 
    else { 
     [self orderOut:self]; 
    } 
} 

@end 


@implementation ActivationWindow 

- (ActivationWindow*)initWithDelegate:(AutoHidingWindow*)activationDelegate 
{ 
    if ((self = [super initWithContentRect:[[NSScreen mainScreen] frame] 
           styleMask:NSBorderlessWindowMask 
            backing:NSBackingStoreBuffered 
            defer:NO]) != nil) { 
     _activationDelegate = activationDelegate; 

     [self setBackgroundColor:[NSColor clearColor]]; 
     [self setExcludedFromWindowsMenu:YES]; 
     [self setCanHide:NO]; 
     [self setHasShadow:NO]; 
     [self setLevel:NSScreenSaverWindowLevel]; 
     [self setAlphaValue:0.0]; 
     [self setIgnoresMouseEvents:YES]; 
     [self setOpaque:NO]; 
     [self orderFrontRegardless]; 

     [self adjustWindowFrame]; 
     [self.activationDelegate addObserver:self 
           forKeyPath:@"slidingEdge" 
            options:0 
            context:@"slidingEdge"]; 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(screenParametersChanged:) 
                name:NSApplicationDidChangeScreenParametersNotification 
                object:nil];  
    } 

    return self; 
} 

@synthesize activationDelegate = _activationDelegate; 
@synthesize trackingArea = _trackingArea; 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([@"slidingEdge" isEqual:context]) { 
     [self adjustTrackingArea]; 
    } 
    else { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 


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

    [self.activationDelegate removeObserver:self forKeyPath:@"slidingEdge"]; 
    _activationDelegate = nil; 

    [_trackingArea release], _trackingArea = nil; 

    [super dealloc]; 
} 

- (void)screenParametersChanged:(NSNotification *)notification 
{ 
    [self adjustWindowFrame]; 
} 

- (void)adjustWindowFrame 
{ 
    NSScreen *mainScreen = [NSScreen mainScreen]; 
    CGFloat menuBarHeight = [NSMenuView menuBarHeight]; 
    NSRect windowFrame = [mainScreen frame]; 

    windowFrame.size.height -= menuBarHeight; 

    [self setFrame:windowFrame display:NO]; 
    [self adjustTrackingArea]; 
} 

- (void)adjustTrackingArea 
{ 
    NSView *contentView = [self contentView]; 
    NSRect trackingRect = contentView.bounds; 
    CGRectEdge slidingEdge = self.activationDelegate.slidingEdge; 
    CGFloat trackingRectSize = 2.0; 

    switch (slidingEdge) { 
     case CGRectMaxXEdge: 
      trackingRect.origin.x = trackingRect.origin.x + trackingRect.size.width - trackingRectSize; 
      trackingRect.size.width = trackingRectSize; 
      break; 

     case CGRectMaxYEdge: 
      trackingRect.origin.y = trackingRect.origin.y + trackingRect.size.height - trackingRectSize; 
      trackingRect.size.height = trackingRectSize; 
      break; 

     case CGRectMinXEdge: 
      trackingRect.origin.x = 0; 
      trackingRect.size.width = trackingRectSize; 
      break; 

     case CGRectMinYEdge: 
     default: 
      trackingRect.origin.y = 0; 
      trackingRect.size.height = trackingRectSize; 
    } 


    NSTrackingAreaOptions options = 
    NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | 
    NSTrackingActiveAlways | 
    NSTrackingEnabledDuringMouseDrag; 

    NSTrackingArea *trackingArea = self.trackingArea; 

    if (trackingArea != nil) { 
     [contentView removeTrackingArea:trackingArea]; 
    } 

    trackingArea = [[NSTrackingArea alloc] initWithRect:trackingRect 
               options:options 
                owner:self 
               userInfo:nil]; 

    [contentView addTrackingArea:trackingArea]; 

    self.trackingArea = [trackingArea autorelease]; 
} 

- (void)mouseEntered:(NSEvent *)theEvent 
{ 
    [self.activationDelegate autoShow]; 
} 


- (void)mouseMoved:(NSEvent *)theEvent 
{ 
    [self.activationDelegate autoShow]; 
} 

- (void)mouseExited:(NSEvent *)theEvent 
{ 
} 

@end 
Problemi correlati