NSTableView列头中的复选框

4
我需要在NSTableView列标题中添加一个复选框。 我已经能够在上述列的所有行中添加复选框。但是我需要在表头级别上添加一个复选框,以实现全选功能。我无法在表头级别上添加一个复选框。如果有示例代码或想法将非常有帮助。
谢谢, Subrat

它始于将NSTableHeaderCell定义为子类。请参见以下链接以寻求正确的方向:https://dev59.com/Om445IYBdhLWcg3wq8BY - SSteve
2个回答

2
创建NSButtonCell的子类。
@interface CheckboxHeaderCell : NSButtonCell {
    NSButtonCell *cellCheckBox;
    NSColor *bkColor;
}

-(void)setTitle:(NSString *)title;
-(void)setBkColor:(NSColor *)color;
-(BOOL)getState;
-(void)onClick;

@end  

@implementation CheckboxHeaderCell

- (id)init
{
    if (self = [super init])
    {
        bkColor = nil;

        cellCheckBox = [[ NSButtonCell alloc] init];
        [cellCheckBox setTitle:@""];
        [cellCheckBox setButtonType:NSSwitchButton];
        [cellCheckBox setBordered:NO];
        [cellCheckBox setImagePosition:NSImageRight];
        [cellCheckBox setAlignment:NSLeftTextAlignment];
        [cellCheckBox setObjectValue:[NSNumber numberWithInt:0]];

        [cellCheckBox setControlSize:NSSmallControlSize];
        [cellCheckBox setFont:[NSFont systemFontOfSize:[NSFont
                                                        smallSystemFontSize]]];
    }
    return self;
}

- (void)dealloc
{
    [cellCheckBox release];
    [bkColor release];
    [super dealloc];
}

-(void)setTitle:(NSString *)title
{
    [cellCheckBox setTitle:title];
}

-(void)setBkColor:(NSColor *)color
{
    [color retain];
    [bkColor release];
    bkColor = color;
}

-(BOOL)getState
{
    return [[cellCheckBox objectValue] boolValue];
}

-(void)onClick
{
    BOOL state = ![[cellCheckBox objectValue] boolValue];
    [cellCheckBox setObjectValue:[NSNumber numberWithBool:state]];
}

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    if (bkColor != nil)
        [cellCheckBox setBackgroundColor:bkColor];

    [cellCheckBox drawWithFrame:cellFrame inView:controlView] ;
}

@end 

如何使用:

CheckboxHeaderCell *mHeaderCell = [[CheckboxHeaderCell alloc] init];
    NSTableColumn *checkBoxColumn = [mOutlineView tableColumnWithIdentifier:@"state"];
    [checkBoxColumn setHeaderCell:mHeaderCell];  

- (void)tableView: (NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn
{
    NSLog(@"didClickTableColumn");
    CheckboxHeaderCell *headerCell = [tableColumn headerCell];
    [headerCell onClick];
}

1
使用新版的Xcode,可以直接将复选框拖放到表格视图的标题单元格中。 - Parag Bafna
Xcode的哪个版本?看起来这似乎不适用于Xcode 5。 - Michael Teper
@JonathanMitchell 你也可以将复选框拖放到表视图标题单元格中。 - Parag Bafna
@JonathanMitchell 我能够解决这个问题。http://stackoverflow.com/questions/42173471/password-field-not-visible-on-password-protected-pdf/42173506#42173506 - Parag Bafna
Swift 5 版本,macOS 11.0 测试通过:https://gist.github.com/Lessica/176c2314336fc861398de1e1045aa368 - i_82
显示剩余3条评论

1
使用自定义的NSCell实例是行不通的,原因很简单,协调NSHeaderCell实例的NSTableHeaderView处理所有鼠标事件处理。因此,表头中的单元格按钮永远不会响应鼠标事件。
解决方案是将所需的NSControl实例添加到自定义的NSTableHeaderView中。可以在IB中为表视图设置自定义子类。控件是像这样添加到已识别的表列中的:
[(BPTableHeaderView *)self.tableView.headerView addSubview:self.passwordTableHeaderButton
                                          columnIdentifier:@"password"
                                                 alignment:NSLayoutAttributeRight];

任何一个NSView实例都可以添加到列标题中,尽管添加一个NSControl实例可能是最常见的。
NSTableHeaderView子类。
@interface BPTableHeaderView : NSTableHeaderView

- (void)addSubview:(NSView *)view columnIdentifier:(NSString *)identifier alignment:(NSLayoutAttribute)alignment;

@end

@interface BPTableHeaderView()

// collections
@property (strong) NSMutableDictionary<NSString *, NSDictionary *> *store;

// primitives
@property (assign, nonatomic) BOOL subviewsVisible;

@end

@implementation BPTableHeaderView

- (id)initWithFrame:(NSRect)frameRect
{
    self = [super initWithFrame:frameRect];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
         [self commonInit];
    }
    return self;
}

- (void)commonInit
{
    _subviewsVisible = YES;
    _store = [NSMutableDictionary new];
}

#pragma mark -
#pragma mark Accessors

- (void)setSubviewsVisible:(BOOL)subviewsVisible
{
    if (_subviewsVisible == subviewsVisible) return;

    _subviewsVisible = subviewsVisible;

    for (NSString *identifier in self.store.allKeys) {
        NSDictionary *info = self.store[identifier];
        NSView *view = info[@"view"];
        view.hidden = !_subviewsVisible;
    }
}

#pragma mark -
#pragma mark Drawing

- (void)drawRect:(NSRect)dirtyRect {

    [super drawRect:dirtyRect];

    if (self.draggedColumn != -1 || self.resizedColumn != -1) {
        [self layoutSubviews];
    }
}

#pragma mark -
#pragma mark View management

- (void)addSubview:(NSView *)view columnIdentifier:(NSString *)identifier alignment:(NSLayoutAttribute)alignment
{
    self.store[identifier] = @{@"view" : view, @"alignment" : @(alignment)};
    [self addSubview:view];
    self.needsLayout = YES;
}

#pragma mark -
#pragma mark Layout

- (void)layout
{
    [super layout];
    [self layoutSubviews];
}

- (void)layoutSubviews
{
    for (NSString *identifier in self.store.allKeys)
    {
        // info
        NSDictionary *info = self.store[identifier];
        NSView *view = info[@"view"];
        NSLayoutAttribute alignment = [info[@"alignment"] integerValue];

        // views and cells
        NSTableColumn *column = [self.tableView tableColumnWithIdentifier:identifier];
        NSTableHeaderCell *headerCell = column.headerCell;
        NSInteger idx = [self.tableView.tableColumns indexOfObject:column];
        if (idx == NSNotFound) continue;

        // rects
        NSRect headerRect = [self headerRectOfColumn:idx];
        NSRect sortIndicatorRect = NSZeroRect;
        if (column.sortDescriptorPrototype) {
            sortIndicatorRect = [headerCell sortIndicatorRectForBounds:headerRect];
        }

        // position view
        NSPoint viewOrigin = NSMakePoint(0, 0);
        CGFloat y = (headerRect.size.height - view.frame.size.height)/2;
        CGFloat xDelta = 3;
        if (alignment == NSLayoutAttributeLeft) {
            viewOrigin = NSMakePoint(headerRect.origin.x + xDelta, y);
        }
        else {
            viewOrigin = NSMakePoint(headerRect.origin.x + headerRect.size.width - view.frame.size.width - sortIndicatorRect.size.width - 5, y);
        }
        [view setFrameOrigin:viewOrigin];
    }

}
@end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接