Anyone knows how to allow users to choose which columns of an NSTableView to be displayed by right clicking and then selecting? Just like iTunes does.
I have implemented this and the following should be usable without any subclassing.
First implement an empty menu in IB and connect to the menu output of the Table Header View.
This method (called from awakeFromNib) constructs the contents of the menu from the header (and includes a test to prevent users hiding a primary column)
- (void)initViewHeaderMenu:(id)view {
//create our contextual menu
NSMenu *menu = [[view headerView] menu];
//loop through columns, creating a menu item for each
for (NSTableColumn *col in [view tableColumns]) {
if ([[col identifier] isEqualToString:COLUMNID_NAME])
continue; // Cannot hide name column
NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle:[col.headerCell stringValue]
action:@selector(toggleColumn:) keyEquivalent:@""];
mi.target = self;
mi.representedObject = col;
[menu addItem:mi];
}
return;
}
This invokes the following to do the actual hiding/unhiding
- (void)toggleColumn:(id)sender {
NSTableColumn *col = [sender representedObject];
[col setHidden:![col isHidden]];
}
You also need to set the delegate of the Menu and implement the following to set states:-
#pragma mark NSMenu Delegate Methods
-(void)menuWillOpen:(NSMenu *)menu {
for (NSMenuItem *mi in menu.itemArray) {
NSTableColumn *col = [mi representedObject];
[mi setState:col.isHidden ? NSOffState : NSOnState];
}
}
I extended Milliways' great answer based on this blog post and added the following functionality:
NSUserDefaults
Initial Setup:
// Your intial Startup code
[self setupHeaderMenu:self.yourTableView];
Creating the menu:
Important: Because of col.identifier
you'll have to set an "Identify Identifier" for each Table view column in IB for this to work.
#pragma mark - Show Hide Columns
- (void)setupHeaderMenu:(NSTableView *)tableView {
NSDictionary *savedCols = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kUserDefaultsKeyVisisbleColumns];
NSMenu *menu = [NSMenu new];
for (NSTableColumn *col in tableView.tableColumns) {
NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle:[col.headerCell stringValue]
action:@selector(toggleColumn:)
keyEquivalent:@""];
mi.target = self;
if(savedCols){
BOOL isVisible = [savedCols[col.identifier] boolValue];
[col setHidden:!isVisible];
}
mi.state = (col.isHidden ? NSOffState: NSOnState);
mi.representedObject = col;
[menu addItem:mi];
}
tableView.headerView.menu = menu;
return;
}
The toggle method
The toggle method saves the new configuration in NSUserDefaults
- (void)toggleColumn:(NSMenuItem *)menu {
NSTableColumn *col = menu.representedObject;
BOOL shouldHide = !col.isHidden;
[col setHidden:shouldHide];
menu.state = (col.isHidden ? NSOffState: NSOnState);
NSMutableDictionary *cols = @{}.mutableCopy;
for( NSTableColumn *column in self.yourTableView.tableColumns){
cols[column.identifier] = @(!column.isHidden);
}
[[NSUserDefaults standardUserDefaults] setObject:cols forKey:kUserDefaultsKeyVisibleColumns];
if(shouldHide){
[self.yourTableView sizeLastColumnToFit];
} else {
[self.yourTableView sizeToFit];
}
}
Menu delegate
-(void)menuWillOpen:(NSMenu *)menu {
for (NSMenuItem *mi in menu.itemArray) {
NSTableColumn *col = [mi representedObject];
[mi setState:col.isHidden ? NSOffState : NSOnState];
}
}
The Result
So now you can check / uncheck each column and the configuration will be saved even after a restart of your App.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With