从Apple 的示例代码和阅读文档中,我看不到将其配置为与 Xcode 编辑器窗口中的“跳转栏NSPathControl
”类似的行为:
即让它代表一个路径(或其他类型的层次结构)并使路径的每个组件成为可点击的弹出窗口以导航层次结构..?
有没有人幸运地通过NSPathControlDelegate
听点击并在临时窗口中显示菜单来伪造这种行为?
似乎是一种常见的设计,人们甚至会期望一些 OSS 实现——但还没有这样的运气,还没有用谷歌搜索它..
从Apple 的示例代码和阅读文档中,我看不到将其配置为与 Xcode 编辑器窗口中的“跳转栏NSPathControl
”类似的行为:
即让它代表一个路径(或其他类型的层次结构)并使路径的每个组件成为可点击的弹出窗口以导航层次结构..?
有没有人幸运地通过NSPathControlDelegate
听点击并在临时窗口中显示菜单来伪造这种行为?
似乎是一种常见的设计,人们甚至会期望一些 OSS 实现——但还没有这样的运气,还没有用谷歌搜索它..
我创建了 NSPathControl 的子类,以便可以使用 mouseDown: 在正确位置弹出组件单元格的上下文菜单。我还在菜单中添加了一个代表,以按需创建更深层次的菜单。
- (void)mouseDown:(NSEvent *)event {
NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
NSPathCell *cell = self.cell;
NSPathComponentCell *componentCell = [cell pathComponentCellAtPoint:point
withFrame:self.bounds
inView:self];
NSRect componentRect = [cell rectOfPathComponentCell:componentCell
withFrame:self.bounds
inView:self];
NSMenu *menu = [componentCell menuForEvent:event
inRect:componentRect
ofView:self];
if (menu.numberOfItems > 0) {
NSUInteger selectedMenuItemIndex = 0;
for (NSUInteger menuItemIndex = 0; menuItemIndex < menu.numberOfItems; menuItemIndex++) {
if ([[menu itemAtIndex:menuItemIndex] state] == NSOnState) {
selectedMenuItemIndex = menuItemIndex;
break;
}
}
NSMenuItem *selectedMenuItem = [menu itemAtIndex:selectedMenuItemIndex];
[menu popUpMenuPositioningItem:selectedMenuItem
atLocation:NSMakePoint(NSMinX(componentRect) - 17, NSMinY(componentRect) + 2)
inView:self];
}
}
- (NSMenu *)menuForEvent:(NSEvent *)event {
if (event.type != NSLeftMouseDown) {
return nil;
}
return [super menuForEvent:event];
}
我稍微扩展了斯蒂芬的回答,以适应懒惰地加载菜单项。我创建了一个小协议来调用菜单,而不必为每个单元格提前构建菜单:
NSPathControlExtended.h
@protocol NSPathControlExtendedDelegate <NSPathControlDelegate>
@required
- (NSMenu *)pathControl:(NSPathControl *)pathControl menuForCell:(NSPathComponentCell *)cell;
@end
@interface NSPathControlExtended : NSPathControl
@property (weak) id <NSPathControlExtendedDelegate> delegate;
@end
NSPathControlExtended.m
#import "NSPathControlExtended.h"
@implementation NSPathControlExtended
@synthesize delegate;
- (instancetype)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void)mouseDown:(NSEvent *)event {
NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
NSPathCell *cell = self.cell;
NSPathComponentCell *componentCell = [cell pathComponentCellAtPoint:point
withFrame:self.bounds
inView:self];
NSRect componentRect = [cell rectOfPathComponentCell:componentCell
withFrame:self.bounds
inView:self];
NSMenu *menu = [delegate pathControl:self menuForCell:componentCell];
if (menu.numberOfItems > 0) {
NSUInteger selectedMenuItemIndex = 0;
for (NSUInteger menuItemIndex = 0; menuItemIndex < menu.numberOfItems; menuItemIndex++) {
if ([[menu itemAtIndex:menuItemIndex] state] == NSOnState) {
selectedMenuItemIndex = menuItemIndex;
break;
}
}
NSMenuItem *selectedMenuItem = [menu itemAtIndex:selectedMenuItemIndex];
[menu popUpMenuPositioningItem:selectedMenuItem
atLocation:NSMakePoint(NSMinX(componentRect) - 17, NSMinY(componentRect) + 2)
inView:self];
}
}
- (NSMenu *)menuForEvent:(NSEvent *)event {
if (event.type != NSLeftMouseDown) {
return nil;
}
return [super menuForEvent:event];
}
@end