Objective c NSTableView中的自定义NSPopupButtonCell

Objective c NSTableView中的自定义NSPopupButtonCell,objective-c,cocoa,nspopupbuttoncell,Objective C,Cocoa,Nspopupbuttoncell,我正在尝试在tableview中创建自定义弹出菜单。据我所知,我应该能够通过调用传入自定义视图的[NSPopupButtonCell setView:myView]方法来实现这一点(这只是一个包含NSOutlineView的NSView) 因此,我创建了一个NSPopupButtonCell子类,在初始化过程中,我调用setView并传入自定义大纲视图 编辑 在IB中,我将表格列单元格设置为弹出按钮单元格,并设置 我的自定义LookupPopupButtonCell的类 我仍然无法显示自定义视图

我正在尝试在tableview中创建自定义弹出菜单。据我所知,我应该能够通过调用传入自定义视图的[NSPopupButtonCell setView:myView]方法来实现这一点(这只是一个包含NSOutlineView的NSView)

因此,我创建了一个NSPopupButtonCell子类,在初始化过程中,我调用setView并传入自定义大纲视图

编辑

在IB中,我将表格列单元格设置为弹出按钮单元格,并设置 我的自定义LookupPopupButtonCell的类

我仍然无法显示自定义视图,但可以显示自定义类 初始化方法似乎正在被调用

此后,我使用NSTableViewDelegate方法dataCellForTableColumn取代了这种方法。现在,弹出窗口显示我的自定义表视图

不过,调用NSOutlineViewDelegate方法仍然没有乐趣

编辑 好的,我已经通过在视图上使用NSpoupButton成功地使事情正常工作。委托工作查找和表视图显示良好。似乎使用NSPopupButtonCell委托方法永远不会被调用

@implementation LookupPopupButtonCell

- (id)init
{
    LOG(@"init called");
    self = [super init];
    if (self) {
        [self initialise];
    }
    return self;
}
- (void)initialise
{
    LOG(@"initialise called");
    
    [self setFont:[NSFont fontWithName:@"System Regular" size:11]];
    [self setBordered:NO];
    [self setBezeled:NO];
    
    // Set the Task Lookup Popup Menu
    NSMenu *newLookupMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Custom"];
    
    NSMenuItem *newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Lookup" action:nil keyEquivalent:@""];
    [newItem setEnabled:YES];
    
    TaskLookupViewController *viewController = [[TaskLookupViewController alloc] initWithNibName:@"TaskLookupViewController" bundle:nil];
    
    [newItem setView:[viewController view]];
    
    [newLookupMenu addItem:newItem];
    [newItem release];
    
    [self setMenu:newLookupMenu];
}
@end

@implementation TaskLookupViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialization code here.
        [self initialise];
    }
    
    return self;
}
- (void)awakeFromNib{
    LOG(@"awakeFromNib called...");
    [self viewDidLoad];
}

- (void)viewDidLoad {
    FLOG(@"viewDidLoad called for %@", self);
    /*
    FLOG(@" _outlineView is %@", _outlineView);
    FLOG(@" _outlineView is %@", [_outlineView identifier]);
    FLOG(@" _outlineView delegate is %@", [_outlineView delegate]);
    FLOG(@" _outlineView dataSource is %@", [_outlineView dataSource]);
     */
    [_outlineView setDataSource:self];
    [_outlineView setDelegate:self];
    [_outlineView reloadData];
    [_outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
    [_outlineView setNeedsDisplay];
    [_outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:2] byExtendingSelection:NO];
    /*
    FLOG(@" _outlineView delegate is %@", [_outlineView delegate]);
    FLOG(@" _outlineView dataSource is %@", [_outlineView dataSource]);
    */
    //NSTableColumn *tableColumn = [[_outlineView tableColumns] objectAtIndex:0];
    
    //LOG(@" setting bindings");
    
    //[tableColumn bind: @"value" toObject: _treeController withKeyPath: @"arrangedObjects.displayName" options: nil];

}
- (void)initialise {
    LOG(@"initialise called");
    
    _topLevelItems = [[NSArray arrayWithObjects:@"Project", @"Tasks and Deliverables", @"Finance", nil] retain];
    
    _childrenDictionary = [NSMutableDictionary new];
    
    [_childrenDictionary setObject:[NSArray arrayWithObjects:@"Scope", nil] forKey:@"Project"];
    
    //[_childrenDictionary setObject:[NSArray arrayWithObjects:@"Issues", @"Risks", nil] forKey:@"Quality"];

    [_childrenDictionary setObject:[NSArray arrayWithObjects:@"WBS", @"Functions", nil] forKey:@"Tasks and Deliverables"];
    
    [_childrenDictionary setObject:[NSArray arrayWithObjects:@"Expenses", @"Ongoing Costs", @"Timesheets", nil] forKey:@"Finance"];
    
    //[_childrenDictionary setObject:[NSArray arrayWithObjects:@"Applications", @"Interfaces", nil] forKey:@"IT Systems"];
    
    //[_childrenDictionary setObject:[NSArray arrayWithObjects:@"People", @"Setup", nil] forKey:@"Administration"];
    
}

- (NSArray *)_childrenForItem:(id)item {
    LOG(@"_childrenForItem called");
    NSArray *children;
    if (item == nil) {
        children = _topLevelItems;
    } else {
        children = [_childrenDictionary objectForKey:item];
    }
    //FLOG(@" children are %@", children);
    
    return children;
}
@end

@implementation TaskLookupViewController (NSOutlineViewDataSource)

- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
    LOG(@"outlineViewSelectionDidChange: called");
    if ([_outlineView selectedRow] != -1) {
        NSObject *item = [_outlineView itemAtRow:[_outlineView selectedRow]];
        if ([_outlineView parentForItem:item] != nil) {
            // Only change things for non-root items (root items can be selected, but are ignored)
            FLOG(@" selected item is %@", item);
        }
    }
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
    FLOG(@"outlineView:child:ofItem: called for item %@", item);
    return [[self _childrenForItem:item] objectAtIndex:index];
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
    LOG(@"outlineView:isItemExpandable: called");
    if ([outlineView parentForItem:item] == nil) {
        return YES;
    } else {
        return YES;
    }
}

- (NSInteger) outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
    LOG(@"outlineView:numberOfChildrenOfItem: called");
    FLOG(@" children count is %d", [[self _childrenForItem:item] count]);
    return [[self _childrenForItem:item] count];
}
@end

@implementation TaskLookupViewController (NSOutlineViewDelegate)

- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
    LOG(@"outlineView:isGroupItem: called");
    return [_topLevelItems containsObject:item];
}

- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    LOG(@"willDisplayCell called");
    [cell setTitle:@"Cell Title"];
}

- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    LOG(@"outlineView:viewForTableColumn called");
    // We just return a regular text view.

    if ([_topLevelItems containsObject:item]) {
        NSTextField *result = [outlineView makeViewWithIdentifier:@"HeaderTextField" owner:self];
        // Uppercase the string value, but don't set anything else. NSOutlineView automatically applies attributes as necessary
        NSString *value = [item uppercaseString];
        [result setStringValue:value];
        return result;
    } else  {

        NSTextField *result = [outlineView makeViewWithIdentifier:@"ItemTextField" owner:self];
        [result setStringValue:value];
        return result;
    }
}

- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item;
{
    LOG(@"outlineView:shouldExpandItem: called");
        return YES;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
{
    LOG(@"outlineView:shouldSelectItem: called");
    return YES;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item;
{
    LOG(@"outlineView:shouldCollapseItem: called");
    return NO;
}
@end

@implementation TaskLookupViewController (NSTableViewDelegate)
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    LOG(@"tableView:dataCellForTableColumn:row: called");

    NSString *identifier = [tableColumn identifier];
    
    if ([identifier isEqualToString:@"task"]) {
        //LOG(@" task column setting the cell");

        LookupPopupButtonCell *cellView = [[LookupPopupButtonCell alloc] init];
        return cellView;
    }
    
    NSTextFieldCell *cellView = [tableView makeViewWithIdentifier:@"hoursCell" owner:self];
    return cellView;
    
}
@end

似乎必须使用基于视图的tableView来获取代理消息。诸如此类,现在要弄清楚如何将其中一个绑定到核心数据,希望不是太难

有没有办法对每一行重复使用相同的菜单?我想,只要每次都不重新创建数据源,这可能还不算太糟糕,但在这个层次结构中仍然可能有很多行


我是否缺少一些东西==>代码添加了代码。LookupPopupButtonCell是NSPopupButtonCell的子类。注意:弹出窗口似乎可以工作并显示tableview,但视图中没有数据。调用reloadData会导致调用DataSource方法。调用selectRowIndexes还会导致调用outlineViewSelectionDidChange(嗯,我认为这是一个委托回调,而不是数据源)。