Получение дубликата ячейки кнопки заголовка в NSTableView при использовании NSPopUpButtonCell

У меня есть динамический NSTableView, который может добавить количество столбцов в зависимости от предоставленных данных. Для каждого столбца я установил ячейку заголовка NSPopUpButtonCell. (Примечание: мне пришлось использовать пользовательский класс подкласса для NSTableHeaderView, иначе меню не всплыло). Все работает хорошо, кроме дубликата или дополнительной ячейки кнопки заголовка в правом верхнем углу. Он идеально отражает предыдущий выбор столбцов, как показано на скриншотах. Мой вопрос: как мне остановить NSTableView от повторного использования предыдущей всплывающей ячейки заголовка? (Кстати, я пробовал метод setCornerView, но он влияет только на область заголовка над вертикальной полосой прокрутки.)

Повторяющийся заголовок столбца popupbuttoncell

Повторяющийся заголовок столбца popupbuttoncell отражает выбранное значение предыдущего столбца

2 ответа

Решение

Я столкнулся с той же проблемой на этой неделе. Я пошел с быстрым решением,

[_tableView sizeLastColumnToFit];

(Однако после обсуждения с OP это требует, чтобы вы использовали подкласс NSPopUpButtonCell в заголовке, а также NSTableHeaderView. Я прилагаю свое решение ниже)

Вы можете к этому, сочетая подходы, изложенные здесь,

  1. PopUpTableHeaderCell
  2. DataTableHeaderView

Вот упрощенный фрагмент,

// 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

Вы можете связать все вместе в AppDelegate -awakeFromNib или похожие,

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

}

Кроме этого я не понял, как правильно исправить рисунок в этом регионе.

Кажется, что это изображение последней ячейки, которая дублируется. Таким образом, я немного более хакерский подход мог бы добавить дополнительный столбец к вашему табличному представлению с пустым именем, который намеренно игнорирует щелчки мыши. Надеюсь, установив свойства отображения последнего столбца, вы можете заставить его выглядеть так, как вы хотите.

Я не смог найти ни одного метода NSTableView или NSTableViewDelegate, который бы позволял управлять этим регионом, поэтому любое другое решение может быть очень сложным. Мне было бы интересно и хорошее решение, но я надеюсь, что это поможет вам начать!

У меня есть эта проблема, и я вообще не использую 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.

Другие вопросы по тегам