【问题标题】:windowNumbersWithOptions: on Yosemite fails to return NSPanel windows of my applicationwindowNumbersWithOptions: on Yosemite 无法返回我的应用程序的 NSPanel 窗口
【发布时间】:2015-09-03 04:46:21
【问题描述】:

我有一个基于文档的应用程序,有一个主文档窗口和几个显示相关信息的“卫星”NSPanel 窗口。它们不是浮动的,它们可以(并且确实)成为关键,并且似乎与主窗口位于同一层。

我尝试像这样实现显示/隐藏操作:如果面板不可见 - 显示它。如果它是可见的,但不是前面 - 让它在前面。如果它是可见的并且在前面 - 隐藏它。

为此,我需要知道 NSPanel 是否是“最前面的”。遗憾的是没有 NSWindow API 存在。我尝试使用windowNumbersWithOptions 来比较我的面板的 z 顺序。

-(void) togglePanelVisibility:(PMXPanelController *)panelController {
    NSPanel *panel = [panelController window];
    if ([panel isVisible]) {
        NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:0];
        if ([panel windowNumber] == [[windowNumbers firstObject] integerValue]) {
            [panel orderOut:self];
        }
        else {
            [panel makeKeyAndOrderFront:self];
        }
    } else
        [panelController showWindow:self];
}

唉,我收到的数组只包含一个数字 - 用于我的主文档窗口。我可以在“窗口”菜单中看到我的面板,我可以单击它们将它们带到前面,我可以关闭它们并使用它们 - 但我无法通过 windowNumbersWithOptions 获取它们的编号:

有什么想法吗?

【问题讨论】:

    标签: cocoa nswindow z-order nspanel


    【解决方案1】:

    它没有在任何地方说明这一点,但从NSWindowNumberListAllApplications 返回的少量窗口来看,windowNumbersWithOptions 似乎只返回正常级别的窗口或应用某种不包括其他窗口的过滤.最好的选择是NSApplication 实例的orderedWindows 属性,但既然你提到了面板,请注意:

    只有通常可编写脚本的窗口才会包含在数组中。例如,不包括面板。

    请记住,这两种方法都依赖于 Quartz API,并且可能使用CGWindowListCopyWindowInfo——在最坏的情况下,您可以转到较低级别并使用它。

    【讨论】:

    • 非常感谢。我会尝试两种方式,但我的心是 CG 方式。
    • B.T.W,你不觉得很遗憾没有简单的 API 告诉我哪个窗口在前面吗?毕竟它隐藏了其他窗口,我可能会感兴趣......
    【解决方案2】:

    按照给定的建议,我终于提出了以下建议,这似乎对我有用。

    /* Here is the logic: If panel of panelController is frontMost - hide it.
        If it is visible, but not frontMost - bring it to front.
        If it is not visible - Show it, and bring it to front. */
    
    -(void) togglePanelVisibility:(PMXPanelController *)panelController 
    {
        NSWindow *panel = [panelController window];
        if ([panel isVisible]) {
            BOOL panelIsFront = [self isPanelFront:panel];
            if (panelIsFront)
               [panel orderOut:self];
            else
               [panel makeKeyAndOrderFront:self];
        } else
            [panelController showWindow:self];     
    }
    
    // Attempt to determine if a given panel (window) is front window
    -(BOOL) isPanelFront:(NSWindow *)panel 
    {
        BOOL panelIsFront = NO;
    #if 0
        // This simple implementation won't work because orderedWindows don't  contain panels.
        panelIsFront = [panel isEqualTo:[[NSApp orderedWindows] firstObject]];
    
        // This used to work, but broke on OS X 10.10 Yosemite. I only receive my main window.
        panelIsFront = ([panel windowNumber] == [[[NSWindow windowNumbersWithOptions:0] firstObject] integerValue]);
    #endif
    
        // Last resort, - using CoreGraphics window list. Seems to work on all systems up to 10.10.4
        NSMutableArray *windowNumbers = [NSMutableArray arrayWithCapacity:32];    // I rely on window numbers to determine "frontness".
        CFArrayRef windowInfoArray = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
        for (NSDictionary* nswindowsdescription in (__bridge NSArray*)windowInfoArray)  {
            NSNumber *windowLayer = (NSNumber*)[nswindowsdescription objectForKey:(NSString *)kCGWindowLayer];
            if (windowLayer.integerValue != 0)  // filter out windows not in our normal window layer.
                continue;
    
            NSNumber* windowid = (NSNumber*)[nswindowsdescription objectForKey:(NSString *)kCGWindowNumber];
            if(windowid)
                [windowNumbers addObject:windowid];
        }
        CFRelease(windowInfoArray);
    
        panelIsFront = ([panel windowNumber] == [[windowNumbers firstObject] integerValue]);
        return panelIsFront;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多