NSOutlineView 设置最大列宽及其内容

发布于 2024-11-19 18:15:59 字数 67 浏览 2 评论 0原文

是否可以设置 NSOutlineView 的 NSTableColumn 最大宽度及其内容?

提前致谢。

Is it posible to set an NSOutlineView's NSTableColumn max width with its contents?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白况 2024-11-26 18:16:00

八个月后,我希望您继续选择一些足够好的宽度。然而,如果有人需要这种东西,这里有一个方法。它仍然有很大的局限性,所以请密切关注评论。

NSTableView 和 NSOutlineView 背后的整个理念是,它们在需要时才实例化其内容。这有利于效率,但意味着它们会主动阻止每个单元格的读取属性。要根据其内容调整列的大小,您确实必须查看每个单元格并测量其大小。这永远无法很好地扩展。

也就是说,如果您有一个非常小的 NSOutlineView,并且它都是文本,并且该文本来自数据源,那么这应该可以工作。

// sizeOutlineViewToContents
// This looks at the cells in an NSOutlineView and shrinks its rows and columns to fit, with the following limitations:
// 1. The data must come from an NSOutlineViewDataSource.  If the NSOutlineView gets its data through bindings, it will throw an exception.
// 2. Text and images will be handled, but other cell types will shrink to the column minimum width.
// 3. Only visible cells will be measured.  Any collapsed cells will be ignored.
// 4. This function has to read the contents of every cell and measure the size of their text.  This will be slow, and scale badly.  Only use on small views, with a few thousand cells at most.
- (void) sizeOutlineViewToContents:(NSOutlineView*) outlineView;
{
    if (outlineView)
    {
        NSInteger rowCount = [outlineView numberOfRows];
        CGFloat maxHeight = 0;

        // This implementation doesn't work if the OutlineView data arrive via bindings.  If you want to make it work, be my guest.
        if (![outlineView dataSource])
        {
            @throw [NSException exceptionWithName:@"DataSourceMissingException" reason:@"autosizeColumnsOfOutlineView only works when the outlineView has a dataSource." userInfo:nil];
        }
        else
        {
            for (NSTableColumn *tableColumn in [outlineView tableColumns])
            {
                // Start with the minimum width already specified for the column.
                CGFloat maxWidth = [tableColumn minWidth];

                // Allow the space needed for the cell.
                if (maxWidth < [[tableColumn headerCell] cellSize].width)
                    maxWidth = [[tableColumn headerCell] cellSize].width;

                for (NSInteger rowIndex = 0; rowIndex<rowCount; rowIndex++)
                {
                    // Find the formatting information used for this cell.
                    // For most tables, the generic [tableColumn dataCell] would tell us the formatting for all cells, and be faster.
                    // Given the way we read the header size, it may be tempting to read the cell size, but this will often just return the size of the most recently displayed cell.
                    NSCell *cell = [tableColumn dataCellForRow:rowIndex];

                    // Obtain the actual data in this cell from the dataSource.
                    id rowItem = [outlineView itemAtRow:rowIndex];
                    id cellObject = [[outlineView dataSource] outlineView:outlineView objectValueForTableColumn:tableColumn byItem:rowItem];

                    // If the cell has a formatter, assume it knows what to do with the object.
                    NSFormatter *cellFormatter = [cell formatter];
                    if (cellFormatter)
                        cellObject = [cellFormatter stringForObjectValue:cellObject];

                    // Text is already the difficult one.
                    if ([cellObject isKindOfClass:[NSString class]])
                    {
                        NSDictionary *cellTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                                            [cell font], NSFontAttributeName,
                                                            nil];

                        NSString *cellText = cellObject;
                        // Find the space needed to display the cell text.
                        CGSize size = [cellText sizeWithAttributes:cellTextAttributes];

                        // If the current column contains the outline view disclosure arrows, allow for the space needed for indentation.
                        if (tableColumn == [outlineView outlineTableColumn])
                            size.width += ([outlineView levelForRow:rowIndex]+1)*[outlineView indentationPerLevel];

                        // Cells have a small amount of additional space between them, defined by the outline view.
                        size.width+=[outlineView intercellSpacing].width;
                        size.height+=[outlineView intercellSpacing].height;
                        // There seems to be one extra pixel needed to display the text at its full width.  I'm not sure where this comes from.
                        size.width+=1;

                        // Update the maxima found.
                        if (maxWidth < size.width)
                            maxWidth = size.width;
                        if (maxHeight < size.height)
                            maxHeight = size.height;
                    }
                    else if ([cellObject isKindOfClass:[NSImage class]])
                    {
                        // Images just need their exact size.
                        NSImage *cellImage = cellObject;
                        CGSize size = [cellImage size];

                        // Update the maxima found.
                        if (maxWidth < size.width)
                            maxWidth = size.width;
                        if (maxHeight < size.height)
                            maxHeight = size.height;
                    }
                }

                // Having found the widest cell, apply it to the column.
                [tableColumn setWidth:maxWidth];
            }
        }
        // Having found the highest cell overall, apply it to the table.
        [outlineView setRowHeight:maxHeight];
    }
}

After eight months I hope you just went ahead and chose some widths that were good enough. However, if anyone needs this sort of thing, here is a method for the job. It still has significant limitations, so please pay close attention to the comments.

The entire philosophy behind NSTableView and NSOutlineView is that they don't instantiate their contents until needed. This is good for efficiency, but means that they actively discourage reading properties of every cell. To size a column to its contents, you really do have to look at every cell, and measure its size. This can never scale well.

That said, if you have a very small NSOutlineView, and it's all text, and that text comes from a dataSource, this should work.

// sizeOutlineViewToContents
// This looks at the cells in an NSOutlineView and shrinks its rows and columns to fit, with the following limitations:
// 1. The data must come from an NSOutlineViewDataSource.  If the NSOutlineView gets its data through bindings, it will throw an exception.
// 2. Text and images will be handled, but other cell types will shrink to the column minimum width.
// 3. Only visible cells will be measured.  Any collapsed cells will be ignored.
// 4. This function has to read the contents of every cell and measure the size of their text.  This will be slow, and scale badly.  Only use on small views, with a few thousand cells at most.
- (void) sizeOutlineViewToContents:(NSOutlineView*) outlineView;
{
    if (outlineView)
    {
        NSInteger rowCount = [outlineView numberOfRows];
        CGFloat maxHeight = 0;

        // This implementation doesn't work if the OutlineView data arrive via bindings.  If you want to make it work, be my guest.
        if (![outlineView dataSource])
        {
            @throw [NSException exceptionWithName:@"DataSourceMissingException" reason:@"autosizeColumnsOfOutlineView only works when the outlineView has a dataSource." userInfo:nil];
        }
        else
        {
            for (NSTableColumn *tableColumn in [outlineView tableColumns])
            {
                // Start with the minimum width already specified for the column.
                CGFloat maxWidth = [tableColumn minWidth];

                // Allow the space needed for the cell.
                if (maxWidth < [[tableColumn headerCell] cellSize].width)
                    maxWidth = [[tableColumn headerCell] cellSize].width;

                for (NSInteger rowIndex = 0; rowIndex<rowCount; rowIndex++)
                {
                    // Find the formatting information used for this cell.
                    // For most tables, the generic [tableColumn dataCell] would tell us the formatting for all cells, and be faster.
                    // Given the way we read the header size, it may be tempting to read the cell size, but this will often just return the size of the most recently displayed cell.
                    NSCell *cell = [tableColumn dataCellForRow:rowIndex];

                    // Obtain the actual data in this cell from the dataSource.
                    id rowItem = [outlineView itemAtRow:rowIndex];
                    id cellObject = [[outlineView dataSource] outlineView:outlineView objectValueForTableColumn:tableColumn byItem:rowItem];

                    // If the cell has a formatter, assume it knows what to do with the object.
                    NSFormatter *cellFormatter = [cell formatter];
                    if (cellFormatter)
                        cellObject = [cellFormatter stringForObjectValue:cellObject];

                    // Text is already the difficult one.
                    if ([cellObject isKindOfClass:[NSString class]])
                    {
                        NSDictionary *cellTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                                            [cell font], NSFontAttributeName,
                                                            nil];

                        NSString *cellText = cellObject;
                        // Find the space needed to display the cell text.
                        CGSize size = [cellText sizeWithAttributes:cellTextAttributes];

                        // If the current column contains the outline view disclosure arrows, allow for the space needed for indentation.
                        if (tableColumn == [outlineView outlineTableColumn])
                            size.width += ([outlineView levelForRow:rowIndex]+1)*[outlineView indentationPerLevel];

                        // Cells have a small amount of additional space between them, defined by the outline view.
                        size.width+=[outlineView intercellSpacing].width;
                        size.height+=[outlineView intercellSpacing].height;
                        // There seems to be one extra pixel needed to display the text at its full width.  I'm not sure where this comes from.
                        size.width+=1;

                        // Update the maxima found.
                        if (maxWidth < size.width)
                            maxWidth = size.width;
                        if (maxHeight < size.height)
                            maxHeight = size.height;
                    }
                    else if ([cellObject isKindOfClass:[NSImage class]])
                    {
                        // Images just need their exact size.
                        NSImage *cellImage = cellObject;
                        CGSize size = [cellImage size];

                        // Update the maxima found.
                        if (maxWidth < size.width)
                            maxWidth = size.width;
                        if (maxHeight < size.height)
                            maxHeight = size.height;
                    }
                }

                // Having found the widest cell, apply it to the column.
                [tableColumn setWidth:maxWidth];
            }
        }
        // Having found the highest cell overall, apply it to the table.
        [outlineView setRowHeight:maxHeight];
    }
}
度的依靠╰つ 2024-11-26 18:16:00

关于选择足够好的宽度:我将 TableViewCell 的宽度设置为 10,000,这是 XCode/Cocoa 允许的最大值。这解决了项目在几个字符后被省略号截断的问题。

我在导航器区域Table Column 对象的Table Cell View 项下选择了Table View Cell。然后,在“实用工具区域”中,我选择了“尺寸检查器”,并将“视图”窗格中的“宽度”字段设置为 10,000。

Regarding choosing widths that are good enough: I set the width of my TableViewCell to 10,000, which is the maximum that XCode/Cocoa allow. This fixed the problem of items being cut off with ellipses after a few characters.

I chose the Table View Cell under the Table Cell View item in the Table Column object in the Navigator Area. Then, in the Utility Area, I selected the Size Inspector, and set the Width field in the View pane to 10,000.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文