【问题标题】:Is it possible to draw in the label area of NSToolbar?是否可以在 NSToolbar 的标签区域进行绘制?
【发布时间】:2011-05-29 17:32:11
【问题描述】:

我有一个NSToolbarItem,它使用类似于 Xcode 状态视图的视图。它目前没有标签,但我无法找到一种方法来绘制通常绘制项目标签的区域。我希望视图能够像 Xcode 状态视图一样扩展到该区域。我知道NSToolbar 像素的最底部部分超出了界限,但我看到其他应用程序绘制到标签区域。有什么想法吗?

编辑:为澄清起见,这是我在 Xcode 中所指的状态视图:

我希望我的视图的边界延伸到工具栏的标签区域之外,就像 Xcode 中的视图一样。

【问题讨论】:

    标签: objective-c cocoa nstoolbar nstoolbaritem


    【解决方案1】:

    Xcode 状态视图不是NSToolbarItem,而是插入NSToolbar 中的自定义NSView

    【讨论】:

      【解决方案2】:

      如果你登录

          NSLog(@" %@", [[self.window.contentView superview] subviews]);
      

      你会得到

      NSToolbarView 不会自动调整其子视图的大小,因此您在居中时会遇到问题。 而[self.window.contentView superview] 全屏时不包含工具栏视图。

      您可以在工具栏中心添加所需的视图到[self.window.contentView superview],而不是全屏并正确定位。它将自动调整大小并保持居中。 当切换到全屏时,将其从[self.window.contentView superview] 中删除并将其添加到中心的 NSToolbarView 中,这样它就会留在工具栏中,并且当您显示状态栏时它也会随着工具栏向下移动。

      您可以通过遍历子视图或使用私有方法来获取工具栏视图

      [[self.window toolbar] performSelector:@selector(_toolbarView)];
      

      更新: 我用调试器做了更多的挖掘,我发现这就是 Xcode 所做的。至少在没有全屏时。

          thealch3m1st$ sudo lldb 
      (lldb) process attach -p 11478
      Process 11478 stopped
      Executable module set to "/Applications/Xcode.app/Contents/MacOS/Xcode".
      Architecture set to: x86_64.
      (lldb) po [NSApplication sharedApplication]
      (id) $0 = 0x000000040013f5e0 <IDEApplication: 0x40013f5e0>
      (lldb) po [$0 mainWindow]
      (id) $1 = 0x0000000000000000 <nil>
      (lldb) po [$0 windows]
      (id) $2 = 0x0000000408278460 <__NSArrayM 0x408278460>(
      <IDEWelcomeWindow: 0x40141c1e0>,
      <IDEWorkspaceWindow: 0x401ef2780>,
      <NSComboBoxWindow: 0x402019be0>,
      <NSWindow: 0x4022adc60>,
      <IDEOrganizerWindow: 0x402951b20>
      )
      (lldb) po [$0 windows]
      (id) $3 = 0x0000000408820300 <__NSArrayM 0x408820300>(
      <IDEWelcomeWindow: 0x40141c1e0>,
      <IDEWorkspaceWindow: 0x401ef2780>,
      <NSComboBoxWindow: 0x402019be0>,
      <NSWindow: 0x4022adc60>,
      <IDEOrganizerWindow: 0x402951b20>
      )
      
      (lldb) [$3 objectAtIndex:1]
      error: '[$3' is not a valid command.
      (lldb) po [$3 objectAtIndex:1]
      (id) $4 = 0x0000000401ef2780 <IDEWorkspaceWindow: 0x401ef2780>
      (lldb) po [$4 contentView]
      (id) $5 = 0x0000000401ef0920 <NSView: 0x401ef0920>
      (lldb) po [$5 superview]
      (id) $6 = 0x0000000401ef2e20 <NSThemeFrame: 0x401ef2e20>
      (lldb) po [$6 subviews]
      (id) $7 = 0x0000000401ef3800 <__NSArrayM 0x401ef3800>(
      <_NSThemeCloseWidget: 0x401ef3120>,
      <_NSThemeWidget: 0x401ef3b80>,
      <_NSThemeWidget: 0x401ef40e0>,
      <NSView: 0x401ef0920>,
      <IDEActivityView: 0x4020cd700>,
      <_NSThemeFullScreenButton: 0x402017b20>,
      (<NSToolbarView: 0x4020192e0>: Xcode.IDEKit.ToolbarDefinition.Workspace),
      <DVTDualProxyWindowTitleView: 0x40225e0a0>,
      <NSThemeDocumentButton: 0x402698020>
      )
      
      (lldb) po [$7 objectAtIndex:4]
      (id) $8 = 0x00000004020cd700 <IDEActivityView: 0x4020cd700>
      (lldb) [$8 setHidden:YES]
      error: '[$8' is not a valid command.
      (lldb) po [$8 setHidden:YES]
      (id) $9 = 0x0000000000000000 <nil>
      (lldb) continue
      Process 11478 resuming
      (lldb) 
      

      活动视图消失了:)

      但在全屏时。它不会将其添加到 NSToolbarView 中,而是将其添加到 NSNextStepFrame 中,这是 NSToolbarView 的超级视图。全屏时,工具栏不包含在窗口的 contentview 超级视图中。我认为这与全屏行为和空间有关。

      【讨论】:

        【解决方案3】:

        你必须继承 NSToolbarItem:

        - (id)initWithItemIdentifier:(NSString *)itemIdentifier {
            self = [super initWithItemIdentifier:itemIdentifier];
            if (self) {
                self.hideLabel = NO;
            }
            return self;
        }
        
        - (NSView *)view {
            NSView *view = [super view];
        
            if (self.hideLabel) {
                CGRect frame = view.frame;
                frame.size.height = 45.0f;
                frame.origin.y = 8.0f;
                view.frame = frame;
            }
        
            return view;
        }
        
        - (NSString *)label {
            return self.hideLabel ? @"" : [super label];
        }
        

        创建工具栏:

        NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"Toolbar"];
        toolbar.delegate = self;
        self.window.toolbar = toolbar;
        

        使用 NSToolbarDelegate 用项目填充工具栏:

        - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
            return [NSArray arrayWithObjects:@"Button", @"LCD", NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, nil];
        }
        
        - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
            return [NSArray arrayWithObjects:@"Button", NSToolbarFlexibleSpaceItemIdentifier, @"LCD", NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, nil];
        }
        
        - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
            MyToolbarItem *item = [[MyToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
        
            if ([itemIdentifier isEqualToString:@"LCD"]) {
                item.view = self.lcdView;
                item.hideLabel = YES;
            } else if ([itemIdentifier isEqualToString:@"Button"]) {
                item.label = NSLocalizedString(@"Button", nil);
                item.image = [NSImage imageNamed:@"Button"];
                item.hideLabel = NO;
            }
        
            return item;
        }
        

        在你将它交给工具栏项之前,lcd 视图应该(在这种情况下)高 32 点。如果它更大,工具栏会太高。

        【讨论】:

          【解决方案4】:

          Xcode 状态视图实际上是一个浮动在工具栏上的单独窗口。 (这很容易测试:按 ⇧⌘4 并按空格来截取窗口的屏幕截图,然后将鼠标悬停在它上面。)

          【讨论】:

          • 也可以是菜单或菜单栏或抽屉。 :)
          • @Jason Boyle 他们是如何“修复”它的?
          • @Nano8Blazex:@Ahruman 区分主窗口和状态视图的方法在 Xcode 4.2 中不起作用。要么它不再是一个单独的窗口,要么已经设置了一些技巧来防止它以这种方式被检测到(假设它是或实际上是一个单独的窗口;我无法测试@Ahruman 的断言) .
          • @WTP:菜单栏和抽屉是窗口。 @Jason Boyle:我最初是从 Twitter 上的一位 Xcode 开发人员那里得到这些信息,然后我自己测试了它,当然你也不能测试这些断言中的任何一个。 ;-)
          • 仪器怎么样?它有一个 LCD 样式的工具栏项,其行为与常规项非常相似。它在“自定义”表和所有内容中。唯一不寻常的是您无法通过 cmd-drag 重新排列它。只是为了好玩,我强行将它放入溢出菜单,但它的菜单项是空白的。
          【解决方案5】:

          此代码安装了一个浮动在工具栏顶部的窗口。

          -(void)applicationWillFinishLaunching:(NSNotification *)aNotification {
              NSRect winframe = [self.window frame];
              NSRect viewrect = NSMakeRect(0, 0, 400, 50);
              NSRect winrect = viewrect;
              winrect.origin.x = NSMidX(winframe) - NSMidX(winrect);  
              winrect.origin.y = NSHeight(winframe) - NSHeight(winrect) - 18;
          
              NSWindow* win = [[[NSWindow alloc] initWithContentRect:winrect styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO] autorelease];
              [win setBackgroundColor:[NSColor clearColor]];
              [win setOpaque:NO];
              [win setIgnoresMouseEvents:YES];
          
              MyStatusView* v = [[[MyStatusView alloc] initWithFrame:viewrect] autorelease];
              [win setContentView: v];
          
              [self.window addChildWindow:win ordered:NSWindowAbove];
          }
          

          【讨论】:

            【解决方案6】:

            在标签区域延伸的 iTunes-XCode-LCD 不是NSToolbarItem。由于NSToolbar 不是NSView,因此您不能将子视图添加到NSToolbar 实例。 但是您可以直接在窗口框架中添加自定义视图,可以通过NSWindow 实例的contentView.superview 属性路径访问!

            即创建你自己的 NSWindowController 子类,并在 'windowDidLoad' 方法中加入一些类似的代码:

            - (void)windowDidLoad
            {  
            [super windowDidLoad];
            
            NSImage *image = [NSImage imageNamed:@"lcd"];
            NSRect lcdFrameRect = NSMakeRect(self.window.frame.size.width / 2 - image.size.width/2, self.window.frame.size.height - image.size.height - 20, 
            
                                             image.size.width, image.size.height);
            NSImageView *lcdView = [[NSImageView alloc] initWithFrame: lcdFrameRect];
            [lcdView setImage: image];
            lcdView.autoresizingMask = NSViewMinYMargin | NSViewMinXMargin | NSViewMaxXMargin;
            
            NSView * contentView = self.window.contentView;
            [contentView.superview addSubview: lcdView];
            }
            

            此代码在 Lion 的全屏模式下不起作用,因为在全屏模式下不会绘制框架窗口。为了解决这个问题,可以在浮动窗口中移动视图,主窗口的子窗口(只需检查 NSWindow addChildWindow:ordered: 方法)。

            【讨论】:

              猜你喜欢
              • 2019-06-12
              • 1970-01-01
              • 1970-01-01
              • 2015-08-15
              • 2018-08-29
              • 1970-01-01
              • 2019-05-25
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多