About the automatic table column identifier - cocoa

I have create a NSTableView and 2 NSTableColumn in the view. Both of the identifiers of these 2 NSTableColumn set to "Automatic" in Interface Builder.
In the method:
(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
I use
NSLog(#"%#", [tableColumn identifier])
to check the identifier of these 2 NSTableColumn.
I found the identifier of the first column is AutomaticTableColumnIdentifier.0 but the second is (null).
Is there any reason that the second column doesn't have a identifier?
I have reduced the attribute "Columns" of NSTableView to 1 and increased it to 2 later, so the first column is included in the NSTableView but the second is not.

This is likely the reason:
I have reduced the attribute "Columns" of NSTableView to 1 and increased it to 2 later, so the first column is included in the NSTableView but the second is not.
If it's causing you problems, set the identifiers in the nib.

Related

NSView-based table view with auto layout grows, but does not shrink rows

I have a NSTableView in view-based mode (not cell-based) with usesAutomaticRowHeights=YES. The rows have dynamic height that might change at any time. This setup successfully grows table view rows (row content is never clipped), but table view rows don't shrink to the intrinsic row view height when rows get shorter. Calling noteHeightOfRowsWithIndexesChanged: on the table view after layout does not seem to fix the problem, my tableView:heightOfRow: is also not called again after noteHeightOfRowsWithIndexesChanged:.
Is there anything I have missed/isn't documented about using auto layout in NSView-based tableviews with variable row height? After all, growing rows always works without any additional code, they just do not shrink on their own.
NSTableView* tv = [[NSTableView alloc] init];
[tv setTranslatesAutoresizingMaskIntoConstraints:NO];
[tv setUsesAutomaticRowHeights:YES]; // Use auto layout for row height
NSTableColumn* column = [[NSTableColumn alloc] init];
[tv addTableColumn:column];
// Set table view data source and delegate, rows are then loaded...
After debugging the default table view layout for a long time, I finally found the issue. The table view row views come with some autoresizingmask settings that interfere with content, when using autolayout for the row content views. You need to set the row view's translatesAutoresizingMaskIntoConstraints to NO. This can be achieved for a view-based NSTableView using the delegate method tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row:
- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
{
// Remember that rowView != row content view!
[rowView setTranslatesAutoresizingMaskIntoConstraints:NO]; // Disable constraints interfering with row view content
}
Interestingly, this does not seem to be an issue if content does not shrink past the initial row height or maximum row height it has grown to, due to dynamic height increases.

NSTableview column identifier

I have an NSTableview, in this table view I populate columns with objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row.
I would like a column that is not populated. If I place a column with no identifier or an identifier that doesn't match a key I receive an error for not being key coding compliant.
Now what I have done to circumvent this is add a column with an identifier named 'skip', I check for this condition in my code with this...
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
Pizza* pizza = [pizza objectAtIndex:row];
NSString* identifier = [tableColumn identifier];
if ([identifier isEqualToString:#"skip"]) {
return nil;
}
return [pizza valueForKey:identifier];
}
I also have to reciprocate this in the setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row as well.
It seems to work fine, but it seems like a bit of a hack.
Is there a better way to do this?
Furthermore, the reason I want empty columns is because I want to place objects such as buttons that don't belong to the array that the table view is referencing.
Thanks for you input!
It's not a hack. That's how it's done. You're supposed to check the column identifier to figure out what object value to return for it. You wanted to just pass that choice through to the Pizza object, but it's common for a view to have aspects that aren't embodied in the model and therefore the controller has to mediate. If you want, you could override -valueForUndefinedKey: in the Pizza class but, in my opinion, that would be a hack. By the way, once you have a check of the column identifier, you don't have to use "skip". You can check for an empty identifier as easily.

Getting a column in an NSTableView with editable column order

I have an NSTableView where I would like to be notified if the user clicks in a column "ClickMe". I linked the entire table view to a method which can extract the clickedColumn:, but I get an absolute number and not a reference to the "ClickMe" column (which may have been moved to another place).
I could of course program my own search algorithm to see if column X is actually the "Clickme" column, but that would not be very elegant. Is there a way to identify columns properly, and to receive that ID programmatically?
I found a way to do my own search in a fairly fast way, but I still have a feeling I am putting too much effort in this:
First, set the Identifier of the desired column in the Interface Builder to "ClickMeColumn". Then:
NSInteger cmColumn = [tableView columnWithIdentifier:#"ClickMeColumn"];
if ( [tableView clickedColumn] == cmColumn )
NSLog(#"Clicked me!");
I am looking for something along the lines of [tableView clickedColumnIdentifier].
What about querying NSTableView's columnAtPoint: in your table views mouseDown: or mouseUp: method?
Use any of the methods below. Called by the tableView's delegate on selection. You can extract the identifier and the title string from the relevant tableColumn.
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn {
NSLog(#"tableView:didClickTableColumn: %#, titleString: %#", [tableColumn identifier], [[tableColumn headerCell] stringValue]);
}
- (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn {
NSLog(#"tableView:mouseDownInHeaderOfTableColumn: %#, titleString: %#", [tableColumn identifier], [[tableColumn headerCell] stringValue]);
}
From: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class

Sorting NSTableView

I have two coloumn in NSTableView as Name and Salary with 5-10 values. I want to sort these coloumn after click on header of both the column. There is lots of data present in Internet but I am not able to use these. Please help me to do this in cocoa.
Thanks in advance and appreciate any help.
Each table column has a method setSortDescriptorPrototype
Sort descriptors are ways of telling the array how to sort itself (ascending, descending, ignoring case etc.)
Iterate over each of the columns you want as sortable and call this method on each of those columns, and pass the required sort descriptor (In my case I'll be using the column identifier)
for (NSTableColumn *tableColumn in tableView.tableColumns ) {
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:tableColumn.identifier ascending:YES selector:#selector(compare:)];
[tableColumn setSortDescriptorPrototype:sortDescriptor];
}
After writing this piece of initialization code, NSTableViewDataSource has a method - (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors that notifies you whenever a sort descriptor is changed, implement this method in the data source and send a message to the data array to sort itself
- (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
self.data = [self.data sortedArrayUsingDescriptors:sortDescriptors];
[aTableView reloadData];
}
This method will get fired each time a column header is clicked, and NSTableColumn shows a nice little triangle showing the sorting order.
I stumbled upon this question while looking for the easiest way of implementing something similar. Although the original question is old, I hope someone finds my answer useful! Please note that I am using Xcode 5.1.1
Ok so to do this you need to:
select the actual column you want to sort in your table.
In your Attributes Inspector you need to fill in two fields: Sort Key, and Selector.
In the Sort Key field, you need to enter the value of your Identifier. The value of your Identifier is located in your Identity Inspector.
In the Selector field you need to enter a suitable selector method based on the object type in the column. The default method is; compare:
Based on the Table View Programming Guide for Mac. The compare: method works with NSString, NSDate, and NSNumber objects. If your table column contains only strings, you may want to consider using the caseInsensitiveCompare: method if case sensitivity is unimportant. However, consider replacing these method signatures with the localizedCompare: or localizedCaseInsensitiveCompare: methods to take into the account the user’s language requirements.
Finally, you need to declare the tableView:sortDescriptorsDidChange: method in your Table View Controller in the format shown below:
-(void)tableView:(NSTableView *)mtableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
[listArray sortUsingDescriptors: [mtableView sortDescriptors]];
[tableView reloadData];
}
Just had lately the same issue to get tableView sorted.
My approach :
bind your sortDescriptors to tableview's arrayController
bind tableview's sortDescriptors to Arraycontroller's sort descriptor
perform the settings in attribute inspector (see Tosin's answer above)
Worked perfect for me. No need to set prototypes for columns or something else.
Thanks very much ,It is usefullly for my question.
my code like this
First, set unique values in the XIB interface,like name...
- (void)viewDidLoad {
[super viewDidLoad];
self.itemTableView.dataSource = self;
self.itemTableView.delegate = self;
self.itemTableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleRegular;
self.itemTableView.usesAlternatingRowBackgroundColors = YES;
for (NSTableColumn *tableColumn in self.itemTableView.tableColumns ) {
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:tableColumn.identifier ascending:NO selector:#selector(compare:)];
[tableColumn setSortDescriptorPrototype:sortDescriptor];
}
}
-(void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors{
NSLog(#"sortDescriptorsDidChange:%#",oldDescriptors);
[self.itemArr sortUsingDescriptors:[tableView sortDescriptors]];
[self.itemTableView reloadData];
}

NSTableView - NSButtonCell Data Source type?

I've got a table with checkbox-style cells, and I can't figure out how to get these buttons to take on the titles that they're supposed to. Should the data source be an array of strings? An array of dictionaries (string/boolean)? An array of NSButtonCells? None of these seem to work =/
NSButtonCell uses integer values (as NSNumbers) as its data source:
NSMixedState = -1,
NSOffState = 0,
NSOnState = 1
That doesn't help you with the title of course, you have to set that separately. If you're using bindings, NSButtonCell defines a title binding you can bind to an array of strings. Otherwise, you can use the NSTableView delegate method - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex to set the title for each row.

Resources