我有一个动态NSTableView,它可以根据提供的数据添加多个列。对于每一列,我已将标题单元格设置为NSPopUpButtonCell。 (旁注:我必须为NSTableHeaderView使用自定义子类,否则菜单不会弹出)。除了右上角的重复或额外标题按钮单元格外,一切正常。它完全反映了之前的列选择,如屏幕截图所示。我的问题是如何阻止NSTableView回收以前的弹出标题单元格? (顺便说一下,我尝试了setCornerView方法但只影响垂直滚动条上方的标题区域。)
答案 0 :(得分:1)
本周我遇到了同样的问题。我选择了快速修复,
[_tableView sizeLastColumnToFit];
(但是,在与OP讨论之后,这要求您在标题和NSTableHeaderView中使用NSPopUpButtonCell的子类。我在下面附上我的解决方案)
您可以通过结合此处概述的方法来实现这一目标,
这是一个简化的摘录
// 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];
}
除此之外,我还没有想出如何正确纠正该地区的绘画。
似乎是最后一个单元格的复制图像。所以我稍微采用hack-ish的方法是在表视图中添加一个额外的列,并使用空白名称,并故意忽略鼠标单击。希望通过设置最后一列的显示属性,您可以使其看起来像您想要的那样。
我找不到任何允许控制该区域的NSTableView或NSTableViewDelegate方法,因此任何其他解决方案都可能非常复杂。我也会对一个很好的解决方案感兴趣,但我希望这能让你开始!
答案 1 :(得分:0)
我有这个问题,我根本不使用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。