【问题标题】:NSWindow - click outside to hide windowNSWindow - 点击外部隐藏窗口
【发布时间】:2012-08-18 15:30:52
【问题描述】:

我正在为 Mac 进行编程。我只有很少的 iOS 开发经验。 我需要构建非常简单的应用程序,坐在菜单栏中。 我希望它有点习惯,决定使用 NSWindow 并将其附加到 NSStatusItem。

我的 AppDelegate 是这样的:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application

    float width = 30.0;
    float height = [[NSStatusBar systemStatusBar] thickness];
    NSRect viewFrame = NSMakeRect(0, 0, width, height);
    statusItem = [[NSStatusItem alloc] init];
    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:30];
    [statusItem setView:[[TSStatusBarItem alloc] initWithFrame:viewFrame]];


}

- (void)buttonClicked:(int)posx posy:(int)posy {
    [_window setLevel:kCGMaximumWindowLevelKey];
    opened = !opened;
    NSLog(@"Window is shown: %i", opened);

    [_window setFrameTopLeftPoint:NSMakePoint(posx, posy)];

    if(opened == YES) {
        _window.isVisible = YES;
    } else {
        _window.isVisible = NO;
    }

}

是TSStatusBarItem的代码

- (void)drawRect:(NSRect)rect
{
    // Drawing code here.

    if (clicked) {
        [[NSColor selectedMenuItemColor] set];
        NSRectFill(rect);
    }

    NSImageView *subview = [[NSImageView alloc] initWithFrame:CGRectMake(3, 0, 20, 20)];
    [subview setImage:[NSImage imageNamed:@"icon.png"]];
    [self addSubview:subview];


}

- (void)mouseDown:(NSEvent *)event
{

    NSRect frame = [[self window]frame];
    NSPoint pt = NSMakePoint(NSMinX(frame), NSMinY(frame));
    NSLog(@"X: %f and Y: %f", pt.x, pt.y);

    [self setNeedsDisplay:YES];
    clicked = !clicked;

    [appDelegate buttonClicked:pt.x posy:pt.y];


}

窗口显示和隐藏得很好,但前提是我点击了 StatusItem。我想添加隐藏窗口的行为,当用户点击外部或在菜单栏中选择另一个项目时(与典型的 NSMenu 应用程序类似)。

怎么做?如果您知道如何简化我的代码(对不起,我是 Mac 编码的新手)- 请说。

【问题讨论】:

  • 为什么每次调用draw rect时都添加一个新的图像视图?我建议将那部分代码添加到 init 方法中,或者以编程方式绘制图像。 ;)
  • @TannerSilva - 谢谢!我这样做了。
  • 另外,点击状态项时是否会出现 NSMenu?
  • @TannerSilva 不。我只是“打开”NSWindow 并移动到 NSStatusItem 点。
  • 好的。我在想你可以让你的 AppDelegate 成为一个 NSMenuDelegate,它会在状态菜单关闭时通知你。

标签: xcode cocoa nswindow nsstatusitem


【解决方案1】:

注册NSWindowDidResignKeyNotificationNSWindowDidResignMainNotification 以在窗口失去焦点时收到通知:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    SEL theSelector = @selector(closeWindow); 
    NSNotificationCenter* theCenter = [NSNotificationCenter defaultCenter]; 
    NSWindow* theWindow = [self window]; 
    [theCenter addObserver:self selector:theSelector name:NSWindowDidResignKeyNotification object:theWindow]; 
    [theCenter addObserver:self selector:theSelector name:NSWindowDidResignMainNotification object:theWindow]; 
}

现在在窗口失去焦点的情况下执行以下操作:

-(void)closeWindow
{
    [[self window] close];
}

或者使用NSPanel,它会在失去焦点时自动隐藏。

【讨论】:

  • 感谢您的回答!嗯……点击外面好像没什么反应。我什至尝试调用 NSLog,但徒劳无功。还尝试了 NSWindowDidBecomeKeyNotification 和 NSWindowDidBecomeMainNotification。也没有用。 :(
  • 只有在我启用了标题栏时才有效。启用标题栏时也是如此,WebKit 工作正常,但如果没有,它会产生奇怪的事情。 ;/
  • 非常感谢。这是一个快速的帮助。
  • 似乎当标题栏被禁用时,窗口永远不会成为关键。为了解决这个问题,继承 NSWindow 并覆盖 canBecomeKey 属性以返回 true。然后覆盖 NSWindowDelegate 中的 windowDidResignKey。
【解决方案2】:
-(void)applicationDidResignActive:(NSNotification *)notification
{
    [self window] close];
}

试试看 这仅在您的应用处于焦点时才有效。 为了让它集中...也试试这个 - :

[NSApp activateIgnoringOtherApps:YES];

【讨论】:

    【解决方案3】:

    @Anne 回答的 Swift 5 版本:

    NotificationCenter.default.addObserver(forName: NSWindow.didResignKeyNotification, object: nil, queue: OperationQueue.main) { _ in
        self.window?.close()
    }
    
    NotificationCenter.default.addObserver(forName: NSWindow.didResignMainNotification, object: nil, queue: OperationQueue.main) { _ in
        self.window?.close()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 2015-08-11
      • 2012-05-04
      • 1970-01-01
      • 2022-12-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多