Re: Sizing table columns to fit data - a solution looking for suggestions
On Jan 30, 2009, at 8:33 AM, Steve Cronin wrote: Corbin; Hey thanks for replying! First off, don't use the 'tableView:' prefix for your own delegate methods. Consider what would happen if AppKit introduced the same delegate method in a future release. Well, I can tell you from experience that it won't be good. So, please make it something like "scTableView:...". This method is an existing method provided by NSObject from Apple! I didn't make the name up, I used an already existing delegate mechanism. Am I not understanding your point? Hah! No -- that was totally an error on my part; I thought you were making up your own delegate method...I didn't read the name carefully enough. Sorry about that mistake! Use CGFloat not float. OK, but why? For 64-bit compatibility. You can read up on CGFloat / NSInteger for more info. Setting the width in a loop is not good for performance; it might cause the table to relayout a lot of times. The code you cited is NOT inside a loop!?? Or am I not understanding how something works? No; your right here too; I wasn't reading it closely enough... NSCell *cell = [tableView preparedCellAtRow:i column:column]; 10.5 Only -- I wanted a 10.4 compatible solution. I didn't say that and I should have. Ah, that's a bummer :) That means you have to use float instead of CGFloat. corbin ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Sizing table columns to fit data - a solution looking for suggestions
Corbin; Hey thanks for replying! First off, don't use the 'tableView:' prefix for your own delegate methods. Consider what would happen if AppKit introduced the same delegate method in a future release. Well, I can tell you from experience that it won't be good. So, please make it something like "scTableView:...". This method is an existing method provided by NSObject from Apple! I didn't make the name up, I used an already existing delegate mechanism. Am I not understanding your point? Use CGFloat not float. OK, but why? Setting the width in a loop is not good for performance; it might cause the table to relayout a lot of times. The code you cited is NOT inside a loop!?? Or am I not understanding how something works? NSCell *cell = [tableView preparedCellAtRow:i column:column]; 10.5 Only -- I wanted a 10.4 compatible solution. I didn't say that and I should have. Thanks, Steve On Jan 30, 2009, at 10:10 AM, Corbin Dunn wrote: Below is a reasonably generic Cocoa solution for implementing this behavior. The tableView I developed this for uses an arrayController with individual column bindings; not the old school -dataSource methods for handling the data. This code should exist in tableView's delegate. This solution handles both strings and images. I don't like the reliance on calling the arrayController directly but for now it serves my purpose Overall, I would do it slightly differently; I would subclass NSTAbleHeaderView, figure out what column needs it to be autoresized and when (ie: double click), and then ask the delegate (optionally) what size it wants. But, I would make a default implementation based on -cellSize (possibly doing a monte carlo simulation on the number of rows, if there were a lot of rows, to help with performance). Here are comments on your version: I am interested in both criticisms and improvements - both will serve the Cocoa community.. - (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn { NSEvent *event = [NSApp currentEvent]; if ([event clickCount]==2) { NSPoint location = [event locationInWindow]; NSTableHeaderView *header = [tableView headerView]; location = [header convertPoint:location fromView:nil]; if (location.x>=2.0) location.x-=2; // offset point 2 pixels 'cause the 'split' cursor is a little 'permissive' NSTableColumn *thisColumn = [[tableView tableColumns] objectAtIndex:[header columnAtPoint:location]]; NSString *maxStr = @""; id thisObj; NSCell *dCell; float newWidth, maxStringWidth = 0.0 ,maxImageWidth = 0.0; Use CGFloat not float. // me don't like the next line NSArray *theValues = [[myArrayController arrangedObjects] valueForKey:[thisColumn identifier]]; //dump the tableColumn values to an array Instead of this hardcoded access, do this (sorry, not complete, but you should understand the idea): CGFloat maxWidth = 0; for (NSInteger i = 0; i < tableView.numberOfRows; i++) { NSCell *cell = [tableView preparedCellAtRow:i column:column]; NSSize size = [cell cellSize]; if (size.width > maxWidth) maxWidth = size.width; } [tableColumn setWidth:maxWidth]; The code above is *much* more generic. Note that it doesn't consider the indentation for outlineviews. if ([thisColumn width] != newWidth) { [thisColumn setWidth:newWidth]; Setting the width in a loop is not good for performance; it might cause the table to relayout a lot of times. Anyways, as usual, it never hurts to log feature requests for AppKit to do this for you. corbin } else { //if already max then here double-click sets to half max! (maybe NOT do this if images were found?) [thisColumn setWidth:newWidth/2.0]; } } } ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Sizing table columns to fit data - a solution looking for suggestions
Below is a reasonably generic Cocoa solution for implementing this behavior. The tableView I developed this for uses an arrayController with individual column bindings; not the old school -dataSource methods for handling the data. This code should exist in tableView's delegate. This solution handles both strings and images. I don't like the reliance on calling the arrayController directly but for now it serves my purpose Overall, I would do it slightly differently; I would subclass NSTAbleHeaderView, figure out what column needs it to be autoresized and when (ie: double click), and then ask the delegate (optionally) what size it wants. But, I would make a default implementation based on -cellSize (possibly doing a monte carlo simulation on the number of rows, if there were a lot of rows, to help with performance). Here are comments on your version: I am interested in both criticisms and improvements - both will serve the Cocoa community.. - (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn { First off, don't use the 'tableView:' prefix for your own delegate methods. Consider what would happen if AppKit introduced the same delegate method in a future release. Well, I can tell you from experience that it won't be good. So, please make it something like "scTableView:...". NSEvent *event = [NSApp currentEvent]; if ([event clickCount]==2) { NSPoint location = [event locationInWindow]; NSTableHeaderView *header = [tableView headerView]; location = [header convertPoint:location fromView:nil]; if (location.x>=2.0) location.x-=2; // offset point 2 pixels 'cause the 'split' cursor is a little 'permissive' NSTableColumn *thisColumn = [[tableView tableColumns] objectAtIndex:[header columnAtPoint:location]]; NSString *maxStr = @""; id thisObj; NSCell *dCell; float newWidth, maxStringWidth = 0.0 ,maxImageWidth = 0.0; Use CGFloat not float. // me don't like the next line NSArray *theValues = [[myArrayController arrangedObjects] valueForKey:[thisColumn identifier]]; //dump the tableColumn values to an array Instead of this hardcoded access, do this (sorry, not complete, but you should understand the idea): CGFloat maxWidth = 0; for (NSInteger i = 0; i < tableView.numberOfRows; i++) { NSCell *cell = [tableView preparedCellAtRow:i column:column]; NSSize size = [cell cellSize]; if (size.width > maxWidth) maxWidth = size.width; } [tableColumn setWidth:maxWidth]; The code above is *much* more generic. Note that it doesn't consider the indentation for outlineviews. if ([thisColumn width] != newWidth) { [thisColumn setWidth:newWidth]; Setting the width in a loop is not good for performance; it might cause the table to relayout a lot of times. Anyways, as usual, it never hurts to log feature requests for AppKit to do this for you. corbin } else { //if already max then here double-click sets to half max! (maybe NOT do this if images were found?) [thisColumn setWidth:newWidth/2.0]; } } } ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Sizing table columns to fit data - a solution looking for suggestions
Folks; iTunes and Excel both have a feature wherein if you double-click on the column divider in the tableHeader then the table column width is adjusted to the maximum width of the data in the column. Below is a reasonably generic Cocoa solution for implementing this behavior. The tableView I developed this for uses an arrayController with individual column bindings; not the old school -dataSource methods for handling the data. This code should exist in tableView's delegate. This solution handles both strings and images. I don't like the reliance on calling the arrayController directly but for now it serves my purpose I am interested in both criticisms and improvements - both will serve the Cocoa community.. - (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn { NSEvent *event = [NSApp currentEvent]; if ([event clickCount]==2) { NSPoint location = [event locationInWindow]; NSTableHeaderView *header = [tableView headerView]; location = [header convertPoint:location fromView:nil]; if (location.x>=2.0) location.x-=2; // offset point 2 pixels 'cause the 'split' cursor is a little 'permissive' NSTableColumn *thisColumn = [[tableView tableColumns] objectAtIndex: [header columnAtPoint:location]]; NSString *maxStr = @""; id thisObj; NSCell *dCell; float newWidth, maxStringWidth = 0.0 ,maxImageWidth = 0.0; // me don't like the next line NSArray *theValues = [[myArrayController arrangedObjects] valueForKey:[thisColumn identifier]]; //dump the tableColumn values to an array if ((theValues!=nil) && ([theValues count]>0)) { NSEnumerator *valEnum = [theValues objectEnumerator]; // find the longest string or widest image while ((thisObj = [valEnum nextObject]) != nil) { if ([thisObj isKindOfClass:[NSString class]]) { if ([thisObj length] > [maxStr length]) maxStr = thisObj; // keep the string 'cause later we use dataCell to get -width } else if ([thisObj isKindOfClass:[NSImage class]]) { if ([thisObj size].width > maxImageWidth) maxImageWidth = [thisObj size].width; } } //below covers the case where a mix of strings and images were found - chooses the wider of the two if ([maxStr length]> 0) { dCell = [thisColumn dataCell]; [dCell setStringValue:maxStr]; maxStringWidth = [dCell cellSize].width; } newWidth = (maxStringWidth > maxImageWidth) ? maxStringWidth : maxImageWidth; //this check prevents anything from happing unless we have found something actionable if (newWidth>0) { //bump up max if necessary if (newWidth>[thisColumn maxWidth]) [thisColumn setMaxWidth:newWidth]; //set width to max if not already max if ([thisColumn width] != newWidth) { [thisColumn setWidth:newWidth]; } else { //if already max then here double-click sets to half max! (maybe NOT do this if images were found?) [thisColumn setWidth:newWidth/2.0]; } } } } } ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com