2010-01-03 95 views
5

我正在尝试重新编写一个应用程序,我在Windows中使用Objective-C为我的Mac创建了一个应用程序,并且我希望能够像Mac的热点角落。如果我将鼠标移动到屏幕的左侧,它会使窗口可见,如果将它移动到窗口位置之外,窗口将再次隐藏。 (窗口将被推到屏幕的左侧)。制作一个窗口弹出和跳出屏幕边缘

有没有人知道我在哪里可以找到一些演示代码(或参考)如何做到这一点,或至少如何判断鼠标在哪里,即使当前的应用程序不在最前面。 (不知道该怎么说,也习惯了Windows世界)。

谢谢

-Brad

+0

这听起来更象水银一样的货架和剪贴板历史记录,和(可选)的Adium的联系人列表窗口,当鼠标点击该边缘可以弹出并在屏幕的一侧。那是你在想什么? – 2010-01-03 10:10:52

+0

是的,那是我在想什么。 – Brad 2010-01-03 21:36:31

回答

1

这是我想出了。感谢Peter提供上述提示。

@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

甜,感谢您的演示代码 – Brad 2010-05-02 21:00:34

+0

只是注意到我混合最小和最大的每个地方,但在-adjustWrapperView – 2010-05-05 17:26:58

+0

@PierreBernard你是否修复答案中的最小和最大值,还是它仍然是倒退..也没有'@接口'对于这个'@ implementation',并不是_exactly_明确什么需要在其中......例如,没有'slidingEdge'被定义,等等。 – 2012-05-01 03:15:55

2

你会想与窗顺序设置屏幕的边缘实现一种无形的窗口,它总是在最前面。然后,您可以在此窗口中侦听鼠标移动的事件。

设置窗口为不可见,并在上面,使窗口子类中使用要求,如:

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

然后,打开鼠标移动事件,

[self setAcceptsMouseMovedEvents:YES]; 

会导致窗口拨打电话:

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

所以希望这足以让您有个开始。

-Ken

+0

拼图的另一部分是让窗口实际上弹出和弹出。您需要将窗口的内容视图的直接子视图放到另一个视图中,然后制作* that *内容视图。将view-within-the-content-view中的自动调整大小的掩码设置为不调整大小,并将其原点装订到内容视图的左边缘(在您的示例中)。要隐藏窗口,请将窗口大小调整为1像素宽。要显示它,请恢复其适当的大小。如果您希望窗口可调整大小,则需要在显示/隐藏窗口后切换视图的自动调整屏蔽。 – 2010-01-04 03:23:56

+0

你不会简单地将窗口移入和移出的原因是因为用户可能在窗口移出的区域具有另一个屏幕。那么,你并没有隐藏窗口,只是将它移动到另一个屏幕上 - 而不是用户想要的。 (至于用户在这种情况下如何显示窗口,用户可以将窗口向上或向下移动到较小屏幕的边缘,给他一些东西打。) – 2010-01-04 03:27:00

+0

我忘了覆盖窗口的一些东西: [self setHasShadow:NO]; 和 [self setIgnoresMouseEvents:NO]; 因此您的隐形窗口实际上并不会阻止点击。我99%确定你仍然会得到鼠标移动的事件。 – 2010-01-04 15:32:06

2

这里是AutoHidingWindow--当鼠标碰到屏幕边缘时弹出的SlidingWindow的子类。反馈欢迎。

@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 
相关问题