我正在开发和使用Mac OS X 10.6(Snow Leopard)。当我在我的两个NSTableView列标题之间双击时,左侧的列会自动调整大小,就像您期望的那样。
我想在上下文菜单中提供此功能,但似乎没有可公开访问的功能来执行此操作。我用谷歌搜索过,看了NSTableView,NSTableHeaderView和NSTableColumn的文档,但一无所获。我发现很难相信当他们明显编写代码时,他们不会暴露出如此有用的东西。
我看到了-[NSTableColumn sizeToFit]
方法,但只考虑了标头的大小。我也愿意将双击事件发送到NSTableHeaderView,但也无法弄清楚如何做到这一点。
更新 - 我意识到提到我有一个NSArrayController(子类)向我的表提供数据很重要,所以我没有NSTableViewDataSource
我可以调用{ {1}}。这就是问题的症结所在:每个列都绑定到数组控制器的一个键路径,这就是它获取数据的方式,所以它不能遍历其内容。
答案 0 :(得分:10)
您可以通过从列中获取单元格来获取每个单元格的长度。
NSCell myCell = [column dataCellForRow:i];
然后获得单元格的宽度。
width = [myCell cellSize].width;
之后,您可以将单元格的宽度设置为列的宽度。
[column setMinWidth:width];
[column setWidth:width];
答案 1 :(得分:6)
NSTableColumn上的以下类别将列重新调整为双击分隔符所产生的相同宽度。
@implementation NSTableColumn (resize)
- (void) resizeToFitContents
{
NSTableView * tableView = self.tableView;
NSRect rect = NSMakeRect(0,0, INFINITY, tableView.rowHeight);
NSInteger columnIndex = [tableView.tableColumns indexOfObject:self];
CGFloat maxSize = 0;
for (NSInteger i = 0; i < tableView.numberOfRows; i++) {
NSCell *cell = [tableView preparedCellAtColumn:columnIndex row:i];
NSSize size = [cell cellSizeForBounds:rect];
maxSize = MAX(maxSize, size.width);
}
self.width = maxSize;
}
@end
答案 2 :(得分:5)
对于基于视图的表视图(OS X 10.7和更高版本),您必须使用NSTableView
方法viewAtColumn:row:makeIfNecessary:
,然后获取大小。
如果您的单元格视图是NSTextField
,则以下代码有效。对于其他视图,您必须找出获得最小尺寸的方法。
[tableView.tableColumns enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {
NSTableColumn* column = (NSTableColumn*) obj;
CGFloat width = 0;
for (int row = 0; row < tableView.numberOfRows; row++) {
NSView* view = [tableView viewAtColumn: idx
row: row
makeIfNecessary: YES];
NSSize size = [[view cell] cellSize];
width = MAX(width, MIN(column.maxWidth, size.width));
}
column.width = width;
}];
}
答案 3 :(得分:5)
我发现以下内容适合我(用Swift编写):
func resizeColumn(columnName: String) {
var longest:CGFloat = 0 //longest cell width
let columnNumber = tableView.columnWithIdentifier(columnName)
let column = tableView.tableColumns[columnNumber] as! NSTableColumn
for (var row = 0; row < tableView.numberOfRows; row++) {
var view = tableView.viewAtColumn(columnNumber, row: row, makeIfNecessary: true) as! NSTableCellView
var width = view.textField!.attributedStringValue.size.width
if (longest < width) {
longest = width
}
}
column.width = longest
viewTable.reloadData()
}
将列的标识符作为参数,它会在该列中找到内容最长的单元格,并调整列的大小以适合该内容。
答案 4 :(得分:1)
我需要做这件事,事实证明(至少对我而言)要更多参与;这不是完美但非常接近;-) 附:编辑处理基于图像的单元格
#define GBLBIN(x) [[NSUserDefaults standardUserDefaults] boolForKey:(x)]
- (IBAction)autosizeColumns:(id)sender
{
NSMutableArray * widths = [NSMutableArray array];
NSIndexSet * rows = [table selectedRowIndexes];
NSArray * columns = [table tableColumns];
BOOL deslectAll = NO;
NSNumber * col = nil;
int i, j;
// If no row's selected, then select all, the default
if (![rows count])
{
[table selectAll:sender];
rows = [table selectedRowIndexes];
deslectAll = YES;
}
// Use the selected rows from which we'll use the columns' formatted data widths
for (i=[rows lastIndex]; i != NSNotFound; i=[rows indexLessThanIndex:i])
{
for (j=0; j<[columns count]; j++)
{
NSTableColumn * column = [columns objectAtIndex:j];
id item = [[table dataSource]
tableView:table objectValueForTableColumn:column row:i];
NSCell * cell = [column dataCell];
float width, minWidth=10;
// Depending on the dataCell type (image or text) get the 'width' needed
if ([cell isKindOfClass:[NSTextFieldCell class]])
{
NSFont * font = ([cell font]
? [cell font] : [NSFont controlContentFontOfSize:(-1)]);
NSDictionary * attrs =
[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
NSFormatter * formatter = [cell formatter];
NSString * string = item;
// We want a string, as IB would have formatted it...
if (![item isKindOfClass:[NSString class]])
if (formatter)
string = [formatter stringForObjectValue:item];
else
string = [NSString stringWithFormat:@"%@", item];
width = [string sizeWithAttributes:attrs].width + minWidth;
}
else
{
// We have NSButtonCell, NSImageCell, etc; get object's width
width = MAX(minWidth,[[cell image] size].width);
}
// First time seeing this column, go with minimum width
if (j == [widths count])
{
[widths addObject:[NSNumber numberWithFloat:minWidth]];
}
col = [widths objectAtIndex:j];
width = MAX([col floatValue], width);
[widths replaceObjectAtIndex:j withObject:[NSNumber numberWithInt:width]];
}
}
// Now go resize each column to its minimum data content width
for (j=0; j<[widths count]; j++)
{
NSTableColumn * column = [columns objectAtIndex:j];
float width = [[widths objectAtIndex:j] floatValue];
if (GBLBIN(@"debug"))
{
NSLog(@"col:%d '%@' %.f", j, [column identifier], width);
}
[column setWidth:width];
}
// Undo select all if we did it
if (deslectAll)
{
[table deselectAll:sender];
}
}
答案 5 :(得分:1)
以下是一些扩展方法,用于根据Monomac开发人员在C#中的内容调整列的大小。
注意:此列仅按其内容调整列,其他注意事项未考虑(例如,空列的宽度为10px)。
感谢obsh-c片段的slashlos。
public static void SizeColumnsByContent(this NSTableView tableView, int minWidth = 10) {
Contract.Requires(tableView != null);
Contract.Requires(tableView.DataSource != null);
var columns = tableView.TableColumns();
var widths = new List<int>();
for (int row=0; row< tableView.RowCount; row++) {
for (int col=0; col < tableView.ColumnCount; col++) {
// Determine what the fit width is for this cell
var column = columns[col];
var objectValue = tableView.DataSource.GetObjectValue(tableView, column, row);
var width = column.DataCell.DetermineFitWidth(objectValue, minWidth);
// Record the max width encountered for current coolumn
if (row == 0) {
widths.Add(width);
} else {
widths[col] = Math.Max(widths[col], width);
}
}
// Now go resize each column to its minimum data content width
for (int col=0; col < tableView.ColumnCount; col++) {
columns[col].Width = widths[col];
}
}
}
public static int DetermineFitWidth(this NSCell cell, NSObject objectValueAtCell, int minWidth = 10) {
int width;
if (cell is NSTextFieldCell) {
var font = cell.Font ?? NSFont.ControlContentFontOfSize(-1);
var attrs = NSDictionary.FromObjectAndKey(font, NSAttributedString.FontAttributeName);
// Determine the text on the cell
NSString cellText;
if (objectValueAtCell is NSString) {
cellText = (NSString)objectValueAtCell;
} else if (cell.Formatter != null) {
cellText = cell.Formatter.StringFor(objectValueAtCell).ToNSString();
} else {
cellText = objectValueAtCell.Description.ToNSString();
}
width = (int)cellText.StringSize(attrs).Width + minWidth;
} else if (cell.Image != null) {
// if cell has an image, use that images width
width = (int)Math.Max(minWidth, (int)cell.Image.Size.Width);
} else {
// cell is something else, just use its width
width = (int)Math.Max(minWidth, (int)cell.CellSize.Width);
}
return width;
}
答案 6 :(得分:1)
我在实现其他一些解决方案时遇到了麻烦...但是当我使用单元格的字符串值创建单元格时,我设法让列自动调整宽度。到目前为止似乎工作得很好!
- (id)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *identifier = [tableColumn identifier];
NSUInteger col = [keys indexOfObject:identifier];
// Get an existing cell with the MyView identifier if it exists
NSTextField *cell = [tableView makeViewWithIdentifier:identifier owner:self];
// Get cell data
NSDictionary *dict = [self.tableContents objectAtIndex:row];
NSString *stringValue = [dict objectForKey:[keys objectAtIndex:col]];
// There is no existing cell to reuse so create a new one
if (cell == nil) {
// Create the new NSTextField with a frame of the {0,0} with the width of the table.
// Note that the height of the frame is not really relevant, because the row height will modify the height.
NSRect rect = NSRectFromCGRect(CGRectMake(0, 0, 64, 24));
cell = [[NSTextField alloc] initWithFrame:rect];
[cell setBordered:NO];
[cell setBackgroundColor:[NSColor clearColor]];
[cell setAutoresizesSubviews:YES];
// autosize to fit width - update column min width
NSRect rectAutoWidth = [stringValue boundingRectWithSize:(CGSize){CGFLOAT_MAX, 24} options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:cell.font}];
if ( tableColumn.minWidth < rectAutoWidth.size.width )
{
[tableColumn setMinWidth:rectAutoWidth.size.width+20]; // add padding
}
// The identifier of the NSTextField instance is set to MyView. This allows the cell to be reused.
cell.identifier = identifier;
}
// result is now guaranteed to be valid, either as a reused cell or as a new cell, so set the stringValue of the cell to the nameArray value at row
// set value
cell.stringValue = stringValue;
// Return the result
return cell;
}