3

我有一个动态 NSTableView 可以根据提供的数据添加许多列。对于每一列,我将标题单元格设置为 NSPopUpButtonCell。(旁注:我必须为 NSTableHeaderView 使用自定义子类,否则菜单不会弹出)。一切都很好,除了右上角的重复或额外的标题按钮单元格。它完美地反映了之前的列选择,如屏幕截图所示。我的问题是如何阻止 NSTableView 回收以前的弹出标题单元格?(顺便说一句,我尝试了 setCornerView 方法,但这只会影响垂直滚动条上方的标题区域。)

重复的列标题弹出按钮单元格

重复列标题 popupbuttoncell 镜像上一列的选定值

4

2 回答 2

1

这周我遇到了同样的问题。我选择了快速修复,

[_tableView sizeLastColumnToFit];

(但是,在与 OP 讨论后,这要求您在标题中使用 NSPopUpButtonCell 的子类以及 NSTableHeaderView。我在下面附上了我的解决方案)

您可以通过结合此处概述的方法来实现这一点,

  1. PopUpTableHeaderCell
  2. 数据表头视图

这是一个简化的片段,

// PopUpTableHeaderCell.h
#import <Cocoa/Cocoa.h>
/* Credit: http://www.cocoabuilder.com/archive/cocoa/133285-placing-controls-inside-table-header-view-solution.html#133285 */

@interface PopUpTableHeaderCell : NSPopUpButtonCell
@property (strong) NSTableHeaderCell *tableHeaderCell; // Just used for drawing the background

@end

// PopUpTableHeaderCell.m
@implementation PopUpTableHeaderCell

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

        // Init our table header cell and set a blank title, ready for drawing
        _tableHeaderCell = [[NSTableHeaderCell alloc] init];
        [_tableHeaderCell setTitle:@""];

        // Set up the popup cell attributes
        [self setControlSize:NSMiniControlSize];
        [self setArrowPosition:NSPopUpNoArrow];
        [self setBordered:NO];
        [self setBezeled:NO];
        [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
    }
    return self;
}

// We do all drawing ourselves to make our popup cell look like a header cell
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView{

    [_tableHeaderCell drawWithFrame:cellFrame inView:controlView];

    // Now draw the text and image over the top
    [self drawInteriorWithFrame:cellFrame inView:controlView];
}

@end

现在为 NSTableViewHeader 子类。

//DataTableHeaderView.h
#import <Cocoa/Cocoa.h>

/* Credit: http://forums.macnn.com/79/developer-center/304072/problem-of-nspopupbuttoncell-within-nstableheaderview/ */

@interface DataTableHeaderView : NSTableHeaderView
@end

//DataTableHeaderView.m
#import "DataTableHeaderView.h"

/* Credit: http://forums.macnn.com/79/developer-center/304072/problem-of-nspopupbuttoncell-within-nstableheaderview/ */

@implementation DataTableHeaderView

- (id)initWithFrame:(NSRect)frame {

    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}

- (void)mouseDown:(NSEvent *)theEvent {

    // Figure which column, if any, was clicked
    NSPoint clickedPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];
    NSInteger columnIndex = [self columnAtPoint:clickedPoint];
    if (columnIndex < 0) {
        return [super mouseDown:theEvent];
    }

    NSRect columnRect = [self headerRectOfColumn:columnIndex];

    // I want to preserve column resizing. If you do not, remove this
    if (![self mouse:clickedPoint inRect:NSInsetRect(columnRect, 3, 0)]) {
        return [super mouseDown:theEvent];
    }

    // Now, pop the cell's menu
    [[[self.tableView.tableColumns objectAtIndex:columnIndex] headerCell] performClickWithFrame:columnRect inView:self];
    [self setNeedsDisplay:YES];
}

- (BOOL)isOpaque {
    return NO;
}


- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect]; 
    // Drawing code here.
}

@end

-awakeFromNib您可以在 AppDelegate或类似中将所有内容捆绑在一起,

-(void) awakeFromNib {

    /* NB the NSTableHeaderView class is changed to be an DataTableHeaderView in IB! */

    NSUInteger numberOfColumnsWanted = 5;
    for (NSUInteger i=0; i<numberOfColumnsWanted; i++) {

        PopUpTableHeaderCell *headerCell;
        headerCell = [[PopUpTableHeaderCell alloc] init];

        [headerCell addItemWithTitle:@"item 1"];
        [headerCell addItemWithTitle:@"item 2"];
        [headerCell addItemWithTitle:@"item 3"];

        NSTableColumn *column;
        [column setHeaderCell:headerCell];
        [column sizeToFit];

        [_tableView addTableColumn:column];
    }

    /* If we don't do this we get a final (space filling) column with an unclickable (dummy) header */
    [_tableView sizeLastColumnToFit];

}

除此之外,我还没有弄清楚如何正确纠正该区域的绘图。

似乎这是被复制的最后一个单元格的图像。所以我稍微有点hack-ish的方法是在你的表格视图中添加一个额外的列,名称为空白,并且故意忽略鼠标点击。希望通过设置最后一列的显示属性,您可以使它看起来像您想要的那样。

我找不到任何允许控制该区域的 NSTableView 或 NSTableViewDelegate 方法,因此任何其他解决方案都可能非常复杂。我也会对一个不错的解决方案感兴趣,但我希望这能让你开始!

于 2014-01-20T23:41:34.740 回答
1

我有这个问题,我根本不使用 NSPopUpButtonCell。我只想告诉其他方法如何隐藏这个奇怪的标题。此方法不会删除奇数表列,即如果您有 2 个“合法”列并隐藏这个额外的第 3 列标题,您仍然可以在第 2 列和第 3 列之间移动分隔符。但在这种情况下,即使您想调整任何列的大小,您也不会看到多余的标题。我仍然需要解决方案如何完全删除冗余列,以及为什么会这样。(以及为什么 Apple 不会修复这个错误?)

所以......你可以计算这个标题所属的列的索引,并根据这个绘制你的标题或不。首先,子类化NSTableHeaderCell并将其设置为列的单元类。假设您的子类名为TableHeaderCell

for column in self.tableView.tableColumns {
    let col:NSTableColumn = column as! NSTableColumn
    //you can operate with header cells even for view-based tableView's 
    //although the documentation says otherwise.
    col.headerCell = TableHeaderCell(textCell: col.title) 
    //or what initialiser you will have
}

然后在 TableHeaderCell 的drawWithFrame方法中你应该有:

override func drawWithFrame(cellFrame: NSRect, inView controlView: NSView) {
    let headerView = controlView as! HashTableHeaderView
    let columnIndex = headerView.columnAtPoint(cellFrame.origin)
    if columnIndex == -1 {
        return
    }

    //parent's drawWithFrame or your own draw logic:
    super.drawWithFrame(cellFrame, inView: controlView)
}

在此之后,您将不会绘制多余的标题,因为它不属于任何列,并且columnAtPoint方法将返回 -1。

于 2015-05-19T19:14:33.003 回答