簡體   English   中英

NSTableColumn大小適合內容

[英]NSTableColumn size to fit contents

我正在開發和反對Mac OS X 10.6(Snow Leopard)。 當我在我的兩個NSTableView列標題之間雙擊時,左側的列會自動調整大小,就像您期望的那樣。

我想在上下文菜單中提供這個,但似乎沒有可公開訪問的功能來執行此操作。 我用谷歌搜索過,看了NSTableView,NSTableHeaderView和NSTableColumn的文檔,但一無所獲。 我發現很難相信當他們明顯編寫代碼時,他們不會暴露出如此有用的東西。

我看到了-[NSTableColumn sizeToFit]方法,但只考慮了標題的大小。 我也願意將雙擊事件發送到NSTableHeaderView,但也無法弄清楚如何做到這一點。

更新 - 我意識到重要的是要提到我有一個NSArrayController(子類)向我的表提供數據,所以我沒有可以調用的NSTableViewDataSource -[tableView: objectValueForTableColumn: row:] 這就是問題的症結所在:每個列都綁定到數組控制器的一個鍵路徑,這就是它獲取數據的方式,因此無法遍歷其內容。

您可以通過從列中獲取單元格來獲取每個單元格的長度。

NSCell myCell = [column dataCellForRow:i];

然后獲得單元格的寬度。

width = [myCell cellSize].width;

之后,您可以將單元格的寬度設置為列的寬度。

[column setMinWidth:width];
[column setWidth:width];

對於基於視圖的表視圖(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;
    }];
}

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

我發現以下內容適合我(用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()
}

給定列的標識符作為參數,它會在該列中找到內容最長的單元格,並調整列的大小以適合該內容。

下面是一些擴展方法,用於根據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;

    }

我在實現其他一些解決方案時遇到了麻煩......但是我設法讓列在使用單元格的字符串值創建單元格時自動調整寬度。 到目前為止似乎工作得很好!

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

我需要做到這一點,事實證明(至少對我來說)更多的參與; 這不是完美但非常接近;-) ps編輯處理基於圖像的細胞

#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];
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM