NSButtonCell checkbox inside NSTableView is always getting NSOffState. Why? - objective-c

Hi guys I'm new to Cocoa programming and I am getting always NSOffState whether I'm checking or unchecking an NSButtonCell (Check Box Cell in the UI dragged to a cell in an NSTableView).
I have a #property IBOutlet NSButtonCell *mySelection, connected to the respective UI and the following code.
- (void) tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
MediaAComparar *media = [mediasRecesEnStock objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
if ([identifier isEqualToString:#"seleccion"])
{
if ([mySelection state] == NSOnState)
{
[media setValue:object forKey:#"seleccion"];
NSLog(#"on state");
}
if ([mySelection state] == NSOffState)
{
[media setValue:object forKey:#"seleccion"];
NSLog(#"off state");
}
}
}
I never get the NSOnState to execute, the only NSLog message I get is: off state.
Can anyone give me some help?
Thanks!!

If you have one outlet ("mySelection") and multiple rows, which row did you think the outlet connects to? (Answer: none of them. You probably hooked it up to the prototype cell, which is never displayed or used directly.)
But no matter, you don't need to check the state before you set it. Assuming your other code is correct, you should be able to do something like:
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
MediaAComparar *medium = [mediasRecesEnStock objectAtIndex:row];
if ([tableColumn.identifier isEqualToString:#"seleccion"])
medium.seleccion = object.booleanValue;
}
Less code is better code.

Related

cocoa-How to use tableViewSelectionDidChange:?

I have a NSTableview in my view and I want to do some other thing when the user select a particular row. I tried tableViewSelectionDidChange method but it seemed not working.
-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row = [self.InfoTable selectedRow];
if (row == -1) {
return;
}else{
self.NumberInputTextField.stringValue = studentsInTable[row][0];
self.NameInputTextField.stringValue = studentsInTable[row][1];
self.ClassnumberInputTextField.stringValue = studentsInTable[row][1];
}
}
and I have
#interface ViewController : NSViewController <NSTableViewDelegate,NSTableViewDataSource>
and
self.InfoTable.dataSource = self;
self.InfoTable.dataSource = self;
Also, I've googled but haven't found a useful answer.
Can any one give me a hint on it?
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification is delegate method but you are only setting dataSource to self.
[self.InfoTable setDelegate:self];
If you have a cell-based or view-based NSTableView then nothing as such is required. Just make sure the tableView's delegate is set to the controller class, and you implement them.
Or you can do the above with codes:
self.InfoTable.dataSource = self;
self.InfoTable.delegate = self; //Note you used dataSource twice
And make sure you implement these methods if you are not doing binding to load the tableView.
- (void)tableViewSelectionDidChange:(NSNotification *)notification{
NSLog(#"Your seleceted a row...");
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [self.anArray count];
}
- (id) tableView:(NSTableView *)TableView
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(int)row {
return self.anArray[row];
}

Populating NSTableView from NSMutableArray at button pressed

in an OSX app i'm currently developping to get familiar with obj-c, I want to populate a TableView. After some hours spent reading way too much blog posts, I can't understand how to add a row in my TableView.
Here is what I've done following this guide:
I have an NSMutableArray in my ViewController, this ViewController implement both interfaces NSTableViewDataSource and NSTableViewDelegate. And I implement both methodes as indicated in the guide. I also have a button and a tableView. When I click on the button, I fill my array with my own object, that's works great.
But what I want now, is when my array is populated, my tableview is too. I'm aware I need to bind those two in some way, but I have no idea how, can someone give some indication ?
Here is my code for my ViewController:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableViewEpisodes.delegate = self;
self.tableViewEpisodes.dataSource = self;
}
- (IBAction)btRefresh:(id)sender {
CalendarReader* reader = [[CalendarReader alloc]init];
self.episodes = [Episode getEpisodeFromEKEvents:[reader getLastMonthEventsForCalendarName:#"TV Shows"]];
[self.tableViewEpisodes reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(NSTableView *)tableView
{
return [self.episodes count];
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColum row:(NSInteger)row {
// Retrieve to get the #"MyView" from the pool or,
// if no version is available in the pool, load the Interface Builder version
NSTableCellView *result = [tableView makeViewWithIdentifier:#"MyView" owner:self];
// Set the stringValue of the cell's text field to the nameArray value at row
result.textField.stringValue = [self.episodes objectAtIndex:row];
// Return the result
return result;
}
First, you are creating a cell view with an identifier which you have not declared, you need to do something like this (assuming you correctly adopted the UITableView protocol in your class):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *Ident = #"Ident";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Ident];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:Ident] autorelease];
}
[cell.textLabel setText: [yourArray objectAtIndex:indexPath.row];
return cell;
}
This is a delegate method for your NSTableView. It is called when the view is loaded so you need to provide a data source at runtime.
Second, I'm assuming you want one section with a number of rows equal to your data array. If this is so, you need to change the delegate method:
- (NSInteger)numberOfSectionsInTableView:(NSTableView *)tableView
to:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Finally, keep in mind these above methods populate the ROWS, not the COLUMNS as you have it now. Once you populate your array, you need to invoke the method:
[yourTableView reloadData]
In order to refresh the table.
Hope this helps.
Thanks to #bryan-wheeler, I notice a message log when testing his code, and I found out, I was not implementing the correct method: here is my code for my ViewController now:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableViewEpisodes.delegate = self;
self.tableViewEpisodes.dataSource = self;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return 1;
}
-(id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex{
return [self.episodes objectAtIndex:rowIndex];
}
For beginner like me, you'll also have to implement the NSCopying protocol for the class stored in your data source array.
Right now, I only have one element in my TableView and it only show its memory address, but I'll update this answer as soon as I found out how to make it works for future beginner in my case.
EDIT: OK, it works !! My mistake was that: in the tableView:objectValueForTableColumn:row: method, I though I needed to return the Object representing the row given in parameter, but I had to return the one for the AND the cell given in parameter, now I found out, it's pretty obvious, but as a French, I didn't understand the method name correctly. Here is my code now:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableViewEpisodes.delegate = self;
self.tableViewEpisodes.dataSource = self;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [self.episodes count];
}
-(id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex{
if([[aTableColumn title] isEqual: #"Serie's name"]){
return [[self.episodes objectAtIndex:rowIndex] seriesName];
}else if([[aTableColumn title] isEqual: #"Season number"]){
return [NSString stringWithFormat:#"%ld", (long)[[self.episodes objectAtIndex:rowIndex] seasonNumber]];
}else if([[aTableColumn title] isEqual: #"Episode number"]){
return [NSString stringWithFormat:#"%ld", (long)[[self.episodes objectAtIndex:rowIndex]episodeNumber]];
}else{
return nil;
}
}
There is some optimisation to do for sure, feel free to propose. But it's doing the job.

Tooltip for Cell-based NSTableView

I have a view which (among other elements) holds a cell based NSTableView. I made the ViewController the delegate of the table. The view controller is created programmatically and added to an NSStatusItem.
I implemented:
- (BOOL)tableView:(NSTableView *)tableView shouldShowCellExpansionForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
return YES;
}
- (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(NSCell *)aCell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation {
return #"A tooltip";
}
- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
return YES;
}
- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
NSLog(#"Display");
}
But when I run my code the only one of these methods that gets called is:
- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex;
Any idea what might be wrong?
My real objective is to dinamycally define the tooltips for my cells.
I've just needed to solve this problem for my app's development.
These delegate methods you mentioned above are only for the expansion tooltip of a text cell, that shows full text when truncated.
A possible solution is to add an observer of NSViewFrameDidChangeNotification in which the tooltip rectangles are rearranged using addToolTipRect:owner:userData:. The code is something like:
NSTableView *tableView; // the target tableview
- (void)tableViewSizeDidChange:(NSNotification *)theNotification {
[tableView removeAllToolTips];
for (NSInteger row = 0; row < tableView.numberOfRows; row ++) {
NSRect rowRect = [tableView rectOfRow:row];
for (NSInteger col = 0; col < tableView.numberOfColumns; col ++) {
NSRect colRect = [tableView rectOfColumn:col];
NSRect cellRect = NSIntersectionRect(rowRect, colRect);
[tableView addToolTipRect:cellRect owner:
/* Tooltip string for cell at row and col */ userData:NULL];
}}
}
- (void)windowDidLoad {
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(tableViewSizeDidChange:)
name:NSViewFrameDidChangeNotification object:tableView];
...
You may also need to call tableViewSizeDidChange: when a table column was moved or resized.

NSScrollView displaying problems in Xcode 5 after scrolling

NSScrollView displaying NSTableView based on custom view (Image, checkbox and text label). When I scroll - I have lag (bug?) with redrawing rows.
Normal:
Bugged after scroll:
Project (and .xib file) was updated from Xcode 4 to Xcode 5 format. I think this bug appeared after it, but I'm not sure.
Any suggestions how to fix it?
Realisation of NSTableViewDataSource, NSTableViewDelegate protocols:
- (NSInteger) numberOfRowsInTableView: (NSTableView *) aTableView {
return [arrayOfObjects count];
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
CMListItem *currentObject = [arrayOfObjects objectAtIndex: row];
NSString *currentName = [currentObject name];
BOOL currentState = [currentObject state];
NSImage *currentImage = [currentObject getArtwork];
NSString *identifier = [tableColumn identifier];
if ([identifier isEqualToString:#"MainCell"]) {
CMTableCellView *cellView = [tableView makeViewWithIdentifier: identifier owner: self];
cellView.textField.stringValue = currentName;
cellView.button.state = currentState;
cellView.imageView.image = currentImage;
return cellView;
}
return nil;
}
NSScrollView not modified.
My own table cell view - subclass of NSTableCellView with few additional outlets.
UPDATE: this thing helped me: set Can Draw Concurrently for all NSTableView at On state, then turn it to Off state.
I think I have seen this problem sometimes when "Copy On Scroll" is enabled. Try disabling this option in IB (in the attribute inspector, scrollview section, behavior).

NSTableView no selection highlight, but keep track of what row is selected

I've seen some threads with a similar question to this (not exactly the same) but the solutions there didn't solve my problem. I've create a NSTableView with a couple clickable elements in each TableCellView -- a TextField, a DatePicker and a Button -- and I need to be able to click into each of these without first selecting the row they are in. I achieved this by using setSelectionHighlightStyle: NSTableViewSelectionHighlightStyleNone However, I still need to know the index of the row that is being edited, because I need to pass the edits into a model object associated with each row. I tried writing the following, which was the suggestion of some of the other threads I mentioned, but it didn't do anything.
- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
return YES;
}
I'm not 100% sure if that's the wrong method to use for this, or if I'm just implementing it incorrectly. Any tips on how I could go about this would be awesome.
Edit:
Here's my attempt at implementing Steve Waddicor's suggestions:
Making the ViewController the NSTableViewDataSource and set the TableCellView as the delegates for the objects (code is in MyViewController.m):
- (void)awakeFromNib{
[self.tableView setDataSource:self];
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
CustomTableCellView *view = [self.tableView makeViewWithIdentifier:#"MyIdentifier" owner:self];
[view.textField setDelegate:view];
[view.datePicker setDelegate:view];
return view;
}
//-----------------------
//-----------------------
//----------------------- NSTableViewDataSource Protocol Requirements:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [self.tableView numberOfRows];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
return [self.tableView rowViewAtRow:rowIndex makeIfNecessary:NO];
}
and in CustomTableCellView, this is the delegate method which isn't being called when I click on the TextField, which leads me to believe that the delegates aren't being set for the objects correctly:
- (void)mouseDown:(NSEvent*) theEvent{
NSLog(#"TEST");
}
You could set the your tableCellView as the delegate of the controls. From there you could
NSTableView* tableView = self.superview;
NSUInteger row = [tableView rowForView:self];
Edit
To make a delegate. In your tableView dataSource you have a method something like this:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
MyTableCellView* view = [outlineView makeViewWithIdentifier:#"MyIdentifier" owner:self];
[view.textField setDelegate:view];
[view.datePicker setDelegate:view];
[view.button setDelegate:view];
return view;
}
try this delegate
- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex
{
return YES;
}