Determining width of a cell in an NSOutlineView
-
I only have a single column in my NSOutlineView.
The outline view looks like:> Collapsible Row 1
Item 1> Collapsible Row 2
Item 2
I need the height of a row an of an item displayed when the disclosure
triangle is clicked to be based on the width of the cell.
I can get the indentation level by doing:
NSInteger level = [outlineView levelForItem:item];
and the amount that is indented per level by doing:
CGFloat indentation = [outlineView indentationPerLevel];
Asking for the width of the column does not return the same width of
the bounds parameter when drawInteriorWithFrame is called for my cell.
What looks like could work is to get the frame of the NSOutlineView
and then subtract the width of the frame by:
indentation * (level + 1)
but this doesn't seem like it should be the right answer.
There doesn't seem to be a method I can call to obtain the bounds that
will be passed into drawInteriorWithFrame for my cell. Have I missed
something?
Any other ideas?
thank you. -
On Dec 19, 2008, at 1:35 PM, Eric Gorr wrote:> I only have a single column in my NSOutlineView.
>
> The outline view looks like:
>
>> Collapsible Row 1
> Item 1
>
>> Collapsible Row 2
> Item 2
>
> I need the height of a row an of an item displayed when the
> disclosure triangle is clicked to be based on the width of the cell.
>
> I can get the indentation level by doing:
>
> NSInteger level = [outlineView levelForItem:item];
>
> and the amount that is indented per level by doing:
>
> CGFloat indentation = [outlineView indentationPerLevel];
>
>
> Asking for the width of the column does not return the same width of
> the bounds parameter when drawInteriorWithFrame is called for my cell.
>
>
> What looks like could work is to get the frame of the NSOutlineView
> and then subtract the width of the frame by:
>
> indentation * (level + 1)
>
> but this doesn't seem like it should be the right answer.
>
>
> There doesn't seem to be a method I can call to obtain the bounds
> that will be passed into drawInteriorWithFrame for my cell. Have I
> missed something?
>
-frameOfCellAtColumn:row: is exactly what will be passed to your cell.
corbin -
On Dec 19, 2008, at 5:20 PM, Corbin Dunn wrote:>
> On Dec 19, 2008, at 1:35 PM, Eric Gorr wrote:
>
>> I only have a single column in my NSOutlineView.
>>
>> The outline view looks like:
>>
>>> Collapsible Row 1
>> Item 1
>>
>>> Collapsible Row 2
>> Item 2
>>
>> I need the height of a row an of an item displayed when the
>> disclosure triangle is clicked to be based on the width of the cell.
>>
>> I can get the indentation level by doing:
>>
>> NSInteger level = [outlineView levelForItem:item];
>>
>> and the amount that is indented per level by doing:
>>
>> CGFloat indentation = [outlineView indentationPerLevel];
>>
>>
>> Asking for the width of the column does not return the same width
>> of the bounds parameter when drawInteriorWithFrame is called for my
>> cell.
>>
>>
>> What looks like could work is to get the frame of the NSOutlineView
>> and then subtract the width of the frame by:
>>
>> indentation * (level + 1)
>>
>> but this doesn't seem like it should be the right answer.
>>
>>
>> There doesn't seem to be a method I can call to obtain the bounds
>> that will be passed into drawInteriorWithFrame for my cell. Have I
>> missed something?
>>
>
> -frameOfCellAtColumn:row: is exactly what will be passed to your cell.
Unfortunately, this does not work as calling this function causes
heightOfRowByItem to be called. So, an endless loop is entered.
I just need to know the width so I base the height on the width. -
On Dec 19, 2008, at 2:30 PM, Eric Gorr wrote:>
> On Dec 19, 2008, at 5:20 PM, Corbin Dunn wrote:
>
>>
>> On Dec 19, 2008, at 1:35 PM, Eric Gorr wrote:
>>
>>> I only have a single column in my NSOutlineView.
>>>
>>> The outline view looks like:
>>>
>>>> Collapsible Row 1
>>> Item 1
>>>
>>>> Collapsible Row 2
>>> Item 2
>>>
>>> I need the height of a row an of an item displayed when the
>>> disclosure triangle is clicked to be based on the width of the cell.
>>>
>>> I can get the indentation level by doing:
>>>
>>> NSInteger level = [outlineView levelForItem:item];
>>>
>>> and the amount that is indented per level by doing:
>>>
>>> CGFloat indentation = [outlineView indentationPerLevel];
>>>
>>>
>>> Asking for the width of the column does not return the same width
>>> of the bounds parameter when drawInteriorWithFrame is called for
>>> my cell.
>>>
>>>
>>> What looks like could work is to get the frame of the
>>> NSOutlineView and then subtract the width of the frame by:
>>>
>>> indentation * (level + 1)
>>>
>>> but this doesn't seem like it should be the right answer.
>>>
>>>
>>> There doesn't seem to be a method I can call to obtain the bounds
>>> that will be passed into drawInteriorWithFrame for my cell. Have I
>>> missed something?
>>>
>>
>> -frameOfCellAtColumn:row: is exactly what will be passed to your
>> cell.
>
> Unfortunately, this does not work as calling this function causes
> heightOfRowByItem to be called. So, an endless loop is entered.
Yes, of course...since it needs to know the height, but it does answer
your question of how to obtain the bounds that are passed to
drawInteriorWithFrame:.>
> I just need to know the width so I base the height on the width.
>
For that, you want to use -cellSizeForBounds: -- pass in a large
height, but a constrained width. Use a width that is equal to the
[tableColumn width] minus indentation * (level + 1) ---- although, the
actual value that outlineview uses for indentation is dependent on
some internal logic (ie: if you are using "group rows", or the "source
list highlighting style"). But, this should give you a value that is
fairly close to what you want.
corbin -
On Dec 19, 2008, at 6:03 PM, Corbin Dunn wrote:>
> For that, you want to use -cellSizeForBounds: -- pass in a large
> height, but a constrained width. Use a width that is equal to the
> [tableColumn width] minus indentation * (level + 1) ---- although,
> the actual value that outlineview uses for indentation is dependent
> on some internal logic (ie: if you are using "group rows", or the
> "source list highlighting style"). But, this should give you a value
> that is fairly close to what you want.
Vacation got in the way of replying sooner...
Thanks for the information.
While I believe this will work in my specific situation, I have filed
a bug (rdar://6472757) requesting that a method be added which can
simply return the width, taking into account things like "group rows"
and "source list highlighting style". -
On Dec 19, 2008, at 6:03 PM, Corbin Dunn wrote:>
> On Dec 19, 2008, at 2:30 PM, Eric Gorr wrote:
>
>>
>>
>> I just need to know the width so I base the height on the width.
>>
>
> For that, you want to use -cellSizeForBounds: -- pass in a large
> height, but a constrained width. Use a width that is equal to the
> [tableColumn width] minus indentation * (level + 1) ---- although,
> the actual value that outlineview uses for indentation is dependent
> on some internal logic (ie: if you are using "group rows", or the
> "source list highlighting style"). But, this should give you a value
> that is fairly close to what you want.
I guess I spoke to soon. This doesn't actually seem to work.
I have the following code in my -outlineView:heightOfRowByItem: method:
NSTableColumn *column = [outlineView outlineTableColumn];
NSUInteger nItems = [item count];
CGFloat indentation = [outlineView indentationPerLevel];
NSInteger level = [outlineView levelForItem:item];
NSRect bounds = NSMakeRect(0, 0, [column width],
10000);
NSCell *tableCell = [column dataCell];
CGFloat totalOffset = ( indentation * ( level + 1 ) );
NSSize cellSize = [tableCell cellSizeForBounds:bounds];
NSUInteger nItemsPerRow = ( cellSize.width - totalOffset ) / 80;
The width of the column is 711. However, cellSize.width is just 42.xx
when it should be around 700 as well.
Any thoughts? -
On Jan 5, 2009, at 8:56 AM, Eric Gorr wrote:>
> On Dec 19, 2008, at 6:03 PM, Corbin Dunn wrote:
>
>>
>> On Dec 19, 2008, at 2:30 PM, Eric Gorr wrote:
>>
>>>
>>>
>>> I just need to know the width so I base the height on the width.
>>>
>>
>> For that, you want to use -cellSizeForBounds: -- pass in a large
>> height, but a constrained width. Use a width that is equal to the
>> [tableColumn width] minus indentation * (level + 1) ---- although,
>> the actual value that outlineview uses for indentation is dependent
>> on some internal logic (ie: if you are using "group rows", or the
>> "source list highlighting style"). But, this should give you a
>> value that is fairly close to what you want.
>
> I guess I spoke to soon. This doesn't actually seem to work.
>
> I have the following code in my -outlineView:heightOfRowByItem:
> method:
>
> NSTableColumn *column = [outlineView outlineTableColumn];
> NSUInteger nItems = [item count];
> CGFloat indentation = [outlineView indentationPerLevel];
> NSInteger level = [outlineView levelForItem:item];
> NSRect bounds = NSMakeRect(0, 0, [column width],
> 10000);
> NSCell *tableCell = [column dataCell];
> CGFloat totalOffset = ( indentation * ( level + 1 ) );
> NSSize cellSize = [tableCell
> cellSizeForBounds:bounds];
> NSUInteger nItemsPerRow = ( cellSize.width - totalOffset ) /
> 80;
>
Thanks for logging the bug (re: other response).
Your code has some problems; it is asking for the cellSize before
accounting for the indentation. You probably want:
...
CGFloat totalOffset = ( indentation * ( level + 1 ) );
bounds.size.width -= totalOffset; // corbin
NSSize cellSize = [tableCell cellSizeForBounds:bounds];
At this point, cellSize.height should give you a good height to return
from the -heightForRow: method.
Now here:> NSUInteger nItemsPerRow = ( cellSize.width - totalOffset ) /
> 80;
I'm confused what this is trying to do; maybe your ultimate goal is
different than what I think it is. I figure you are trying to find the
appropriate row height for a given cell so it won't get clipped
(something like what Console on Leopard does).
corbin> The width of the column is 711. However, cellSize.width is just
> 42.xx when it should be around 700 as well.
>
> Any thoughts? -
On Jan 5, 2009, at 12:37 PM, Corbin Dunn wrote:>
> On Jan 5, 2009, at 8:56 AM, Eric Gorr wrote:
>
>>
>> On Dec 19, 2008, at 6:03 PM, Corbin Dunn wrote:
>>
>>>
>>> On Dec 19, 2008, at 2:30 PM, Eric Gorr wrote:
>>>
>>>>
>>>>
>>>> I just need to know the width so I base the height on the width.
>>>>
>>>
>>> For that, you want to use -cellSizeForBounds: -- pass in a large
>>> height, but a constrained width. Use a width that is equal to the
>>> [tableColumn width] minus indentation * (level + 1) ---- although,
>>> the actual value that outlineview uses for indentation is
>>> dependent on some internal logic (ie: if you are using "group
>>> rows", or the "source list highlighting style"). But, this should
>>> give you a value that is fairly close to what you want.
>>
>> I guess I spoke to soon. This doesn't actually seem to work.
>>
>> I have the following code in my -outlineView:heightOfRowByItem:
>> method:
>>
>> NSTableColumn *column = [outlineView outlineTableColumn];
>> NSUInteger nItems = [item count];
>> CGFloat indentation = [outlineView indentationPerLevel];
>> NSInteger level = [outlineView levelForItem:item];
>> NSRect bounds = NSMakeRect(0, 0, [column width],
>> 10000);
>> NSCell *tableCell = [column dataCell];
>> CGFloat totalOffset = ( indentation * ( level + 1 ) );
>> NSSize cellSize = [tableCell
>> cellSizeForBounds:bounds];
>> NSUInteger nItemsPerRow = ( cellSize.width -
>> totalOffset ) / 80;
>>
>
> Thanks for logging the bug (re: other response).
>
> Your code has some problems; it is asking for the cellSize before
> accounting for the indentation. You probably want:
> ...
> CGFloat totalOffset = ( indentation * ( level + 1 ) );
> bounds.size.width -= totalOffset; // corbin
> NSSize cellSize = [tableCell
> cellSizeForBounds:bounds];
>
> At this point, cellSize.height should give you a good height to
> return from the -heightForRow: method.
>
> Now here:
>
>> NSUInteger nItemsPerRow = ( cellSize.width -
>> totalOffset ) / 80;
>
>
> I'm confused what this is trying to do; maybe your ultimate goal is
> different than what I think it is. I figure you are trying to find
> the appropriate row height for a given cell so it won't get clipped
> (something like what Console on Leopard does).
Ah, I think there has been a miscommunication.
I ultimately need to be able to compute the height of the cell based
on the width. Based on your reply, it looks like I can determine the
width of the cell merely by doing:
NSTableColumn *column = [outlineView outlineTableColumn];
CGFloat totalCellWidth = [column width] - ( indentation *
( level + 1 ) );
The height of the cell should be based on that value so nItems with
nItemsPerRow can fit entirely inside of the cell. Each item I am
drawing will be 80x80 pixels.
It would seem that what I need to do does not require the use of -
cellSizeForBounds:. -
On Jan 5, 2009, at 12:59 PM, Eric Gorr wrote:>
> On Jan 5, 2009, at 12:37 PM, Corbin Dunn wrote:
>
>>
>> On Jan 5, 2009, at 8:56 AM, Eric Gorr wrote:
>>
>>>
>>> On Dec 19, 2008, at 6:03 PM, Corbin Dunn wrote:
>>>
>>>>
>>>> On Dec 19, 2008, at 2:30 PM, Eric Gorr wrote:
>>>>
>>>>>
>>>>>
>>>>> I just need to know the width so I base the height on the width.
>>>>>
>>>>
>>>> For that, you want to use -cellSizeForBounds: -- pass in a large
>>>> height, but a constrained width. Use a width that is equal to the
>>>> [tableColumn width] minus indentation * (level + 1) ----
>>>> although, the actual value that outlineview uses for indentation
>>>> is dependent on some internal logic (ie: if you are using "group
>>>> rows", or the "source list highlighting style"). But, this should
>>>> give you a value that is fairly close to what you want.
>>>
>>> I guess I spoke to soon. This doesn't actually seem to work.
>>>
>>> I have the following code in my -outlineView:heightOfRowByItem:
>>> method:
>>>
>>> NSTableColumn *column = [outlineView outlineTableColumn];
>>> NSUInteger nItems = [item count];
>>> CGFloat indentation = [outlineView indentationPerLevel];
>>> NSInteger level = [outlineView levelForItem:item];
>>> NSRect bounds = NSMakeRect(0, 0, [column width],
>>> 10000);
>>> NSCell *tableCell = [column dataCell];
>>> CGFloat totalOffset = ( indentation * ( level + 1 ) );
>>> NSSize cellSize = [tableCell
>>> cellSizeForBounds:bounds];
>>> NSUInteger nItemsPerRow = ( cellSize.width -
>>> totalOffset ) / 80;
>>>
>>
>> Thanks for logging the bug (re: other response).
>>
>> Your code has some problems; it is asking for the cellSize before
>> accounting for the indentation. You probably want:
>> ...
>> CGFloat totalOffset = ( indentation * ( level + 1 ) );
>> bounds.size.width -= totalOffset; // corbin
>> NSSize cellSize = [tableCell
>> cellSizeForBounds:bounds];
>>
>> At this point, cellSize.height should give you a good height to
>> return from the -heightForRow: method.
>>
>> Now here:
>>
>>> NSUInteger nItemsPerRow = ( cellSize.width -
>>> totalOffset ) / 80;
>>
>>
>> I'm confused what this is trying to do; maybe your ultimate goal is
>> different than what I think it is. I figure you are trying to find
>> the appropriate row height for a given cell so it won't get clipped
>> (something like what Console on Leopard does).
>
> Ah, I think there has been a miscommunication.
>
> I ultimately need to be able to compute the height of the cell based
> on the width. Based on your reply, it looks like I can determine the
> width of the cell merely by doing:
>
> NSTableColumn *column = [outlineView outlineTableColumn];
> CGFloat totalCellWidth = [column width] - ( indentation *
> ( level + 1 ) );
>
> The height of the cell should be based on that value so nItems with
> nItemsPerRow can fit entirely inside of the cell. Each item I am
> drawing will be 80x80 pixels.
>
> It would seem that what I need to do does not require the use of -
> cellSizeForBounds:.
The latest problem I am having with this is that an NSOutlineView will
not fully draw itself properly if the height of a row changes at the
window it is on is being resized.
I've got a couple of pictures of this which can be viewed at:
http://ericgorr.net/cocoadev/8h6pcc/largetosmall.tiff
http://ericgorr.net/cocoadev/8h6pcc/smalltolarge.tiff
The only redraw problem that makes a little sense to me is when making
the window bigger, the only part that is drawn problem is the part
that was added at the control got bigger.
Of course, once I let go of the mouse button and stop resizing the
window, it draws itself correctly.
What I have tried doing is responding to -windowDidResize: and running
the code:
[resourcesThumbnails reloadData];
[resourcesThumbnails setNeedsDisplay:YES];
[resourcesThumbnails display];
[[notification object] flushWindow];
resourcesThumbnails is the NSOutlineView, but this will not cause the
entire control to be drawn properly.
Is there anything else I can try? -
>
> The latest problem I am having with this is that an NSOutlineView
> will not fully draw itself properly if the height of a row changes
> at the window it is on is being resized.
Override -drawRect: in a subclass of NSOutlineView and just call
[super drawRect:] -- live resize caching is conflicting with what you
want. Ideally, overriding -preservesContentDuringLiveResize should
work, but unfortunately it does not work in Tiger/Leopard.
corbin


