Objective c 是否可以在NSToolbar的标签区域中绘制?

Objective c 是否可以在NSToolbar的标签区域中绘制?,objective-c,cocoa,nstoolbar,nstoolbaritem,Objective C,Cocoa,Nstoolbar,Nstoolbaritem,我有一个NSToolbarItem,它使用类似于Xcode状态视图的视图。它目前没有标签,但我想不出一种方法来画进通常会画项目标签的区域。我希望视图能够像Xcode状态视图一样扩展到该区域。我知道NSToolbar的像素的最底部超出了范围,但我看到其他应用程序进入了标签区域。有什么想法吗 编辑:为了澄清,这是我在Xcode中提到的状态视图: 我希望视图的边界像Xcode中的视图一样延伸到工具栏的标签区域之外。Xcode状态视图不是NSToolbarItem是插入NSToolbar中的自定义NS

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

编辑:为了澄清,这是我在Xcode中提到的状态视图:


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

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

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

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

-(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];
}

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

也就是说,创建自己的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:method)。

如果您登录

    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) 
thealch3m1st$sudo lldb
(lldb)工艺附件-第11478页
进程11478已停止
可执行模块设置为“/Applications/Xcode.app/Contents/MacOS/Xcode”。
架构设置为:x86_64。
(lldb)po[应用程序共享应用程序]
(id)$0=0x000000040013f5e0
(lldb)采购订单[$0主窗口]
(id)$1=0x0000000000000000
(lldb)采购订单[$0窗口]
(id)$2=0x0000000408278460(
,
,
,
,
)
(lldb)采购订单[$0窗口]
(id)$3=0x0000000408820300(
,
,
,
,
)
(内陆开发银行)[3美元目标指数:1]
错误:“[$3”不是有效的命令。
(lldb)采购订单[$3目标指数:1]
(id)$4=0x0000000401ef2780
(lldb)采购订单[$4 contentView]
(id)$5=0x0000000401ef0920
(lldb)采购订单[$5 superview]
(id)$6=0x0000000401ef2e20
(lldb)po[$6子视图]
(id)$7=0x0000000401ef3800(
,
,
,
,
,
,
(:Xcode.IDEKit.ToolbarDefinition.Workspace),
,
)
(lldb)采购订单[$7目标指数:4]
(id)$8=0x00000004020cd700
(内陆开发银行)[8美元:是]
错误:“[$8”不是有效的命令。
(lldb)采购订单[$8 setHidden:是]
(id)$9=0x0000000000000000
(lldb)继续
进程11478恢复
(lldb)

“活动”视图已消失:)


但在全屏模式下。它不会将其添加到NSToolbarView,而是将其添加到NSNextStepFrame,后者是NSToolbarView的superview。在全屏模式下,工具栏不包含在窗口的contentview superview中。我认为它与全屏行为和空间有关。

必须将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点。如果较大,工具栏将过高。

也可能是菜单、菜单栏或抽屉。@Jason Boyle他们是如何“修复”的它?@Nano8Blazex:@Ahruman区分主窗口和状态视图的方法在Xcode 4.2中不起作用。要么它不再是一个单独的窗口,要么已经采取了一些诡计来防止它以这种方式被检测到(假设它是或实际上是一个单独的窗口;我没有办法测试@Ahruman的断言)。@WTP:菜单栏和抽屉都是窗口。@Jason Boyle:我最初从Twitter上的一个Xcode开发人员那里获得了这一信息,然后自己测试了它,当然你也不能测试这两个断言中的任何一个。;-)仪器呢?它有一个LCD样式的工具栏项目,它的行为很像一个普通项目。它在自定义表和所有东西中。唯一不寻常的是,你不能拖动它来重新排列。只是为了好玩,我把它强制进入溢出菜单,但它的菜单项是空的。