Размер NSTableColumn, чтобы соответствовать содержанию - PullRequest
10 голосов
/ 13 января 2011

Я работаю в Mac OS X 10.6 (Snow Leopard) и против нее. Когда я дважды щелкаю между двумя заголовками столбцов моего NSTableView, размер столбца слева автоматически изменяется, как и следовало ожидать.

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

Я видел -[NSTableColumn sizeToFit] метод, но он учитывает только размер заголовка. Я также согласился бы отправить событие двойного щелчка в NSTableHeaderView, но также не мог понять, как это сделать.

Обновление - я понял, что важно упомянуть, что у меня есть NSArrayController (подкласс), предоставляющий данные для моей таблицы, поэтому у меня нет NSTableViewDataSource, для которого я мог бы вызвать -[tableView: objectValueForTableColumn: row:]. В этом суть проблемы: каждый столбец привязан к ключевому пути контроллера массива, и именно так он получает свои данные, поэтому он не может циклически просматривать его содержимое.

Ответы [ 7 ]

10 голосов
/ 22 января 2011

Вы можете получить длину каждой ячейки, получив ячейки из столбца.

NSCell myCell = [column dataCellForRow:i];

Тогда получите ширину ячейки.

width = [myCell cellSize].width;

После этого вы можете установить ширину ячейки как ширину столбца.

[column setMinWidth:width];
[column setWidth:width];
6 голосов
/ 21 ноября 2013

Следующая категория в 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
5 голосов
/ 01 июля 2015

Я нашел следующее, чтобы работать для меня (написано на 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()
}

Учитывая идентификатор столбца в качестве аргумента, он находит ячейку в этом столбце с самым длинным содержимым и изменяет размер столбца, чтобы соответствовать этому содержимому.

5 голосов
/ 04 февраля 2013

Для табличных представлений на основе представления (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;
    }];
}
1 голос
/ 19 января 2014

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

- (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;
}
1 голос
/ 01 ноября 2012

Вот некоторые методы расширения для определения размера столбцов по их содержимому в C # для разработчиков Monomac.

ПРИМЕЧАНИЕ: это размеры столбцов только по их содержанию, другие соображения не учитываются (например, пустые столбцы имеют ширину 10px).

Благодаря слешам для obj-cфрагмент.

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;

    }
1 голос
/ 08 февраля 2011

Мне нужно было сделать то же самое, и оказалось (по крайней мере, для меня), чтобы быть немного более вовлеченным; это не идеально, но довольно близко ;-) постскриптум Отредактировано для обработки ячеек на основе изображений

#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];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...