SortingTableViewByClickingColumnHeaderExample
last edited July 6, 2007 09:23:28 (75.71.216.154)
| |
|---|---|
| Edit / History / New / Search | Quick Links: Home / Recent Changes / Glossary / Jobs / Forums / Help |
|
One way to sort a table view that is expected by many users is to be able to click on a table column header cell to toggle the sort order. A prime example of this is found in the iTunes application.
One of the basic things you have to do is intercept mouse down events in order to get the table to sort itself. But there is no need to go the direct route, as the following discussion reveals: Using
brings two problems.
It is much better to use this delegate method which only gets triggered only when clicking the header cell (not when resizing a column):
To reverse the sorting of a column, you should reverse the array that the table is getting data from. Something like this (category method which extends NSMutableArray):
Here's a simple example that shows how to sort NSTableView columns in ascending or descending order by clicking the column header. It also illustrates two undocumented methods in NSTableView to display the familiar up and down arrows in the column header to indicate sorting order. (WARNING: Use undocumented method calls at your own risk. Apple could change or remove these without notice in a future release of OS X.) Our example has two classes: the Cartoon class is used to represent cartoon characters, which will be shown in a table view. The CartoonTableController class is used as the data source and delegate for the NSTableView. The Cartoon class is very simple, it has three instance variables and three corresponding accessors.
Next, we create an extension to the Cartoon class containing methods to compare two Cartoon objects. These methods could be put in Cartoon.h/.m, but we choose to put these methods in a separate file because they aren't part of the Cartoon's zen nature; they are only useful to the CartoonTableController object to sort the table. This is called creating a category. For details see ClassCategories. Note that the names for these sort routines are in a specific form, closely related to the method names for the Cartoon accessors.
Finally, let's create the CartoonTableController class. It has four instance variables to manage the list of Cartoon objects and keep sorting information. It also implements the NSTableDataSource protocol to act as a data source for the NSTableView, and one of the table view's delegate methods to respond to clicks in a column header.
The -tableView:didClickTableColumn: method is where we handle the user's column click action. We determine whether the clicked column is already selected, determine the new sorting order and re-sort the table. It constructs a selector name as a string, and uses NSSelectorFromString to find the selector by that name, which is stored in the columnSortSelector instance variable. Note the two class method calls [NSTableView _defaultTableHeaderSortImage] and [NSTableView _defaultTableHeaderReverseSortImage], which return NSImage objects; these calls will generate warning messages during compile, since the method names are not declared in the NSTableView header file. Finally, the [tableView setHighlightedTableColumn: tableColumn]; method call makes the selected column header display in blue. If you don't want this behavior, just remove that line.
That's it for the code. If you want to try this example, create a new Cocoa app, add the code above, and create CartoonTableController and NSTableView objects in Interface Builder. The table view should have three columns: Name, Shoe Size, and Tag Line that have identifiers of "name", "shoeSize", and "tagLine" respectively. Wire it all up, be sure to connect the table's data source and delegate to the CartoonTableController? object.
Enjoy! <fergy/> pdferguson@attbi.com
- For info about how to avoid using private methods (that might be removed) for sort arrows, see this link: http://cocoa.mamasam.com/MACOSXDEV/2001/06/1/7790.php - Resorting the array everytime the user clicks on a table header, just to change the order, isn't necessary and is often a bad idea. Instead just sort the array when you really need to (when new items are added or the user changes the column that decides the sort criteria). See http://forums.macnn.com/cgi-bin/ultimatebb.cgi?ubb=get_topic&f=34&t=002351 for info on this subject. /Tobias
Thanks, Tobias. I incorporated your suggestion about only re-sorting when necessary. It also halves the number of comparison methods needed on the Cartoon class, and simplifies the didClickTableColumn method. <fergy/>
Hillegass implements table sorting in an example in the second edition of his book using bindings and NSArrayController and sort descriptors.
Nary an (Note: Bindings are nice, but be aware that they are only available on Panther (10.3) and newer.) See JaguarOrPanther. This is no longer a limitation in most cases.
The documented way for displaying sorting arrows is using [NSImage imageNamed:@] as follows:
I'm leary of using private methods as they may change in the future.
But is there any way to know if the last clicked column is ascending or descending ? Or do you have to create the mecanism "by hand" ?
Why not just override - (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors in your table view data source (NSTableDataSource)?
Do this in conjunction with setting sort keys for each table column (can be done in Interface Builder) and you are done.
| |
| Edit / History / New / Search | Quick Links: Home / Recent Changes / Glossary / Jobs / Forums / Help |