I've got a view-based NSTableView, using Cocoa Bindings to change the values of some labels and images in the cell. It all works great. However, I want to add a button to the cell. I've got the button working, but its action method only has the button as sender, which means I have no idea of the content of the cell that the button is in. Somehow I need to store some extra data on the button - at the very least the row index that the button is in. I subclassed NSButton and used my subclass in the cell, but Interface Builder doesn't know about the extra property so I can't bind to it. If I wanted to bind it in code, I don't know the name of the object or keypath that would be passed to it.
How can I get this to work?
You can use rowForView in your action method to get the row value
- (IBAction)doSomething:(id)sender
{
NSInteger row = [_myTableView rowForView:sender];
}
You can use the Identity field in Interface Builder to associate a table cell view from the nib with an instance in your code:
Additionally you have to implement - tableView:viewForTableColumn:row: in your table view's delegate. (Don't forget to connect the delegate in IB)
- (NSView*)tableView:(NSTableView*)tableView viewForTableColumn:
(NSTableColumn*)tableColumn row:(NSInteger)row
{
SSWButtonTableCellView *result = [tableView makeViewWithIdentifier:#"ButtonView" owner:self];
result.button.title = [self.names objectAtIndex:row][#"name"];
result.representedObject = [self.names objectAtIndex:row];
return result;
}
I added representedObject property in my NSTableCellView subclass, which I set in the above table view delegate method.
Your custom table cell view can later use that object in it's action. e.g.:
- (IBAction)doSomething:(id)sender
{
NSLog(#"Represented Object:%#", self.representedObject);
}
Related
I have a View-based NSOutlineView, and have in the class a selection change event:
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
{
NSLog(#"Selected Row inside:%ld",[self selectedRow]);
}
This is the way I create my NSOutlineView:
ovc = [[OutlineViewController alloc] init];
[myOutlineView setDelegate:(id<NSOutlineViewDelegate>)ovc];
[myOutlineView setDataSource:(id<NSOutlineViewDataSource>)ovc];
MyOutlineView is created in IB.
Every time I click on a row, the event gets fired, however the result is always -1.
NSLog(#"Item 0:%#",[self viewAtColumn:1 row:0 makeIfNecessary:YES]);
Always returns NULL.
Is there something specific I should do ? Thanks.
=== EDIT ===
I have published my simplified code showing the issue: http://www.petits-suisses.ch/OutlineView.zip
Instead of checking the selectedRow of self object, which is just a object initialized in AppController which is a wrong instance. You need to check on the notification object as shown below.
NSLog(#"Selected Row:%ld",[[notification object] selectedRow]);
Also clickedRow is meaningful in the target’s implementation of the action. So the clickedRow gives correct value if checked inside a Action or DoubleAction method.
Your NSOutlineView "Controller" class is actually a subclass of NSOutlineView, this is different then the NSOutLineView in your XIB file. If you look at the notification object being sent it is an instance of NSOutlineView, not "OutlineViewController", therefore you are calling selectedRow on an incorrect instance.
This code should be place in a subclass of NSViewController as opposed to NSOutlineView. Then create an outlet from the outlineView to the controller.
How difficult is to implement a custom NSCell with a NSStepper and a label displaying the value incremented/decremented by the stepper?
I can't add subviews to it, so how can I add such subcomponents?
thanks
Yes it is possible that you can take NSStepperCell in your NSTableView. But for this value to be appear in your NSTableView, You have to take two NSTableColumn in one column drag and drop NSStepperCell and in another by default it will be textcell so let it be. Now bind both your column to array controller with model keypath. In NSStepperCell model key path should be float value and other will be sinple string value. Once you done this then write one action method and bind to the NSStepperCell. Below is the action method written to appear the value.
-(IBAction)doIncrement:(id)sender
{
step+=1.0; ///This step is the float value of NSStepperCell and binded with arrayController
NSNumber *num=[NSNumber numberWithFloat:step];
NSMutableDictionary *dict=[NSMutableDictionary dictionary];
for(dict in [arrayController arrangedObjects])
{
[dict setObject:num forKey:#"displayStepperValue"]; //#"displayStepperValue" this is another column textcell which will print steppercell value when you click on the arrows of NSStepperCell.
}
[arrayController rearrangeObjects]; //here refershing the arraycontroller
}
In my app's navigation controller is an UITableViewContoller then a ViewController. The user selects an item in the UITableViewContollrer, this calls the ViewController. If the user hits the back button I need to visually show which item was selected before. Doing this with a UIImage, basically want to hide or show it. Problem is I cannot find a method that will parse each cell in the UITableView and determine if the the cell was selected before when the UITable is called again.
Some background on the UITableView, it is based on an entity in core data. The selected item is stored in a different entity in core data.
Firstly declare NSIndexPath *selectedIndexPath and creates its property. Now in tableView Delegate:
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
{
selectedIndexPath = indexPath;
}
You have selected IndexPath of cell in tableView. When hits back button of navigator bar, ViewControllers viewWillApper will be called
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(selectedIndexPath)
{
//if you have custom cell then you will get custom cell which was selected just use custom cell object in place of UITableViewCell
UITableViewCell *cell = (UITableViewCell*)[YourtableView cellForRowAtIndexPath:selectedIndexPath];
//You have cell reference which was selected when one view controller was pushed in navigation controller.
// you can change image or label text which are present in your cell
// cell.ImageView or cell.labelText anything
}
}
Hope it is useful.
I have a view-based NSTableView that is populated through bindings. My textFields & imageViews are bound to the NSTableCellView's objectValue's properties.
If I want to have an edit/info button in my NSTableCellView:
Who should be the target of the button's action?
How would the target get the objectValue that is associated with the cell that the button is in?
I'd ultimately like to show a popover/sheet based on the objectValue.
I found an additional answer: The Answer above seems to assume you're using bindings on your table view. Since I'm kind of a noob I found a way to get the button inside the table view cell.
- (IBAction)getCellButton:(id)sender {
int row = [xmlTable rowForView:sender];
}
This way when you click on the button inside the row, you don't have to have the row selected. It will return the int value of the row to match up with a datasource in an array without bindings.
Your controller class can be the target. To get the object value:
- (IBAction)showPopover:(id)sender {
NSButton *button = (NSButton *)sender;
id representedObject = [(NSTableCellView *)[button superview] objectValue];
}
Or, use a subclass of NSTableCellView, make the cell view the target of the button's action, and call [self objectValue] to get the object.
I'm currently trying to use a new view-based NSOutlineView in my Cocoa app. As I'm not using bindings, so I implemented all required delegate and datasource methods in my controller.
In interface builder I've added a NSOutlineView with a highlighting set to SourceList and Content Mode set to View Based. Thus, there were two default table cell views provided (one Header cell with HeaderCell set as identifier and one data cell with DataCell set as identifier)
This is what it looks like in interface builder, header cell views correctly show a grey-blue textField while data cell views have a image view and a textField with correct color and font settings
To provide the views, I use the following code, to return a DataCell-view or a HeaderCell-view and set the textField of the cell accordingly, based on the corresponding identifier set in interface builder.
- (NSView *)outlineView:(NSOutlineView *)outlineView
viewForTableColumn:(NSTableColumn *)tableColumn
item:(id)item {
NSTableCellView *result = nil;
if ([item isKindOfClass:[NSMutableDictionary class]]) {
result = [outlineView makeViewWithIdentifier:#"HeaderCell" owner:self];
id parentObject = [outlineView parentForItem:item] ? [outlineView parentForItem:item] : groupedRoster;
[[result textField] setStringValue:[[parentObject allKeys] objectAtIndex:0]];
} else {
result = [outlineView makeViewWithIdentifier:#"DataCell" owner:self];
[item nickname] ? [[result textField] setStringValue:[item nickname]] : [[result textField] setStringValue:[[item jid] bare]];
}
return result;
}
Running everything it looks like the following.
Could anybody provide me with hints, to why the header cell is neither bold, nor correctly colored, when selected?
You need to implement the -outlineView:isGroupItem: delegate method and return YES for your header rows. That will standardize the font and replace the disclosure triangle on the left with a Show/Hide button on the right. You will still need to manually uppercase your string to get the full effect.
I'm not sure if the group row delegate method above makes the selection style look okay or not. However, you normally don't want the header rows to be selectable at all in source lists, which you by returning NO for header items from the -outlineView:shouldSelectItem: delegate method.
I have created a little sample project which includes a source list and also uses the -outlineView:isGroupItem: method as #boaz-stuller has suggested.
Display a list of items
Edit the items in a master-detail fashion
Remove and add items
Usage of bindings
Check out besi/mac-quickies on github.
Most of the stuff is either done in IB or can be found in the AppDelegate