I am facing trouble in putting check boxes into a UITableView. I am posting a part of my code here.
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSButtonCell *cell=[[NSButtonCell alloc] init];
NSString *strDisplayPlaylistName;
strDisplayPlaylistName=[playListNameArray objectAtIndex:row];
[cell setTitle:strDisplayPlaylistName];
[cell setAllowsMixedState:YES];
[cell setButtonType:NSSwitchButton];
return cell;
}
- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
NSCell *aCell = [aTableColumn dataCellForRow:rowIndex];
[aCell setNextState];
//NSCell *aCell=[aAddedCells objectAtIndex:rowIndex];
//[aCell setNextState];
}
I got the checkboxes inside the UITableView. But the problem is that I can't uncheck the buttons. Is there anything more to do. I am new to cocoa programming.
You're missing a couple of important pieces. You need to update your model (data stcuture) in response to the tableValue:setObjectValue:forTableColumn:row: message, so that you can correctly return the new value from tableView:objectValueForTableColumn:row: method.
Here are some table data source methods assuming you have a 'myRows' array filled with objects with a 'booleanAttribute' property.
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [myRows count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
BOOL value = [[myRows objectAtIndex:row] booleanAttribute];
return [NSNumber numberWithInteger:(value ? NSOnState : NSOffState)];
}
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn *)column row:(NSInteger)row {
[[myRows objectAtIndex:row] setBooleanAttribute:[value booleanValue]];
}
You should also setup your table cell in interface builder. You can drag a button cell configured like a standard check box directly onto one of your table columns.
I'm not sure why you're creating the cell in code. You can just drag the cell onto the table column in Interface Builder.
Also, setObjectValue: is where you respond to the change in the cell's state. The user has already changed the cell's state to off; then you send setNextState and change it back. That's why the cell doesn't appear to uncheck: you keep re-checking it.
What you need to do is not touch the cell at all, but set the object value (which, for this column, will probably be a Boolean NSNumber containing either YES or NO) as the new value of the appropriate property in your model.
Also, of course, make sure the column is set as editable.
If you have your NSTableView content mode set to "Cell Based" it will be "View Based" when you move the checkbox over.
Related
I created a tableview and added image & text table view cell designed it now i thought to add another label in the row and assigned some values to the label based on the rows but it is not working and one more problem i cant hide label when the label in cell while in view i can able to hide
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSImage *profile=[NSImage imageNamed:#"header_menubg.png"];
NSString *identifer=[tableColumn identifier];
if([identifer isEqualToString:#"Mainidentifier"])
{
cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
[cellView.textField setStringValue:[_homearray objectAtIndex:row]];
[cellView.imageView setImage:profile];
return cellView;
}
if(row==0)
{
_countLabel.stringValue=#"40";
[cellView.textField setHidden:YES];
}
return nil;
}
And even i tried to hide text field in some rows that too not working what may be the problem
How can one have checkboxes and textfield (for section headings) in a single tableview column using NSTableViewDataSource Protocol?
My requirement is to use a Cell Based TableView.
I answered your other question without any code and i think you had trouble understanding it.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
array = [[NSMutableArray alloc]initWithObjects:#0,#1,#2, nil];//instead this you can add your class object
[self.myTableView reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [array count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSButtonCell * cell =[[NSButtonCell alloc]init];
[cell setButtonType:NSSwitchButton];
if([array objectAtIndex:row] == [NSNumber numberWithInt:0])
{
[tableColumn setDataCell:cell];
[[tableColumn dataCell]setTitle:#"Are you single?"];// instead this you can access title from your class object or from any other storage
}
else if ([array objectAtIndex:row] == [NSNumber numberWithInt:1])
{
[tableColumn setDataCell:[[NSTextFieldCell alloc]init]];
}
else if ([array objectAtIndex:row] == [NSNumber numberWithInt:2])
{
[tableColumn setDataCell:cell];
[[tableColumn dataCell]setTitle:#"Are you happy?"];
}
return [array objectAtIndex:row];
}
So thought this would help:) Cheers.
Here are the steps to make a single column tableview where the column can have row(s) that are section headings (NSTextFieldCells) followed by rows that are checkboxes (NSButtonCells) having descriptive titles. Similar to a listbox in MS MFC. To be compatible with older versions of OS X it needs to be a Cell based tableview:
Using IB drag a tableView control into the Application Window. In the Attributes inspector set Content Mode as "Cell Based", and Columns to 1.
Using IB drag a "Check Box Cell" control from the Object Library into the Application Window's column. (note: this step probably can be omitted since in the example code shown below, the cell type is being set explicitly to be either a NSButtonCell (checkbox) or NSTextFieldCell). If one needs to expand this example to use multiple columns, then probably want to set the Identifier for the NSTableColumn(s) in IB's Identity Inspector, in order that in the code one can filter by column/row instead of only by row (i.e. inside of the method objectValueForTableColumn).
Set the TableView's datasource and delegate to be the auto generated App Delegate object (in this case ApplicationAppDelegate.h). Do this by opening IB, and using the "Connection Inspector" click and drag from the datasource circle connection icon to the "App Delegate" object icon in the IB panel that shows objects that are loaded from the NIB such as controls, controllers etc.(icon for App Delegate is a blue cube). Do the same click and drag operation with the delegate circle icon.
Open the Assistant Editor, with the App Delegate's .h file showing in the left vertical pane and the IB view of the Table View in the right vertical pane. Select on the TableView control and create an IB outlet named "tableView" by holding the control key and dragging from the TableView Control to the section of the .h file where properties are listed.
Declare a NSMutableArray variable in the .h file. It should look like the following (Note: there has been added NSTableViewDataSource as a supported protocol of ApplicationAppDelegate):
#import <Cocoa/Cocoa.h>
#interface ApplicationAppDelegate : NSObject <NSApplicationDelegate,NSTableViewDataSource>
{
NSMutableArray *state;
}
#property (assign) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSTableView *tableView;
#end
6 . Add the following functions to the App Delegate implementation file (.m):
#import "ApplicationAppDelegate.h"
#implementation ApplicationAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
state = [[NSMutableArray alloc]initWithObjects:#"Section Heading:",#0,#1, nil];//Note: values passed to NSButtonCells should be 0 or 1 or YES or NO, and the state passed to NSTextFieldCell is a NSString
[self.tableView reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [state count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSButtonCell * cell =[[NSButtonCell alloc]init];
[cell setButtonType:NSSwitchButton];
if (row == 0)
{
[tableColumn setDataCell:[[NSTextFieldCell alloc]init]];
}
else if (row == 1)
{
[tableColumn setDataCell:cell];
[[tableColumn dataCell]setTitle:#"title row1"];
}
else if (row == 2)
{
[tableColumn setDataCell:cell];
[[tableColumn dataCell]setTitle:#"title row2"];
}
return [state objectAtIndex:row];
}
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn *)column row:(NSInteger)row
{
[state replaceObjectAtIndex:row withObject:value];
[tableView reloadData];
}
#end
First of all, I searched for 3 days and have not found what I am looking for.
Second point, I am VERY new to Xcode programming so PLEASE keep your answer as simple and/or detailed as possible!
Inside my NSTableView I need the first column to be text followed by X number of checkbox columns with the last column to be text. The X number of columns is a variable based on the number of entries I read from a SQLite file.
My questions are:
How do I define at runtime what type and how many columns I have?
How do I know whether a checkbox value is checked or not?
How do I add rows to the tableview if I don't know the number of cells it has?
Thanks for taking the time to answer!
Best regards,
Igor
You want to create a table at runtime, and you dont know how many columns will be there!!!
Thats a big deal.
Read NSTableView documentation and you will find addTableColumn: method. in the loop go on to create colmn and dont forget to give identifier to all columns.
And over this you want to have a checkbox. Creating checkbox is not difficult either.
EDIT:
For checkbox implementation, find a project here.
Draw a checkBoxCell in the column you want to have checkbox. Or you can do it programatically.
I did it through IB.
You should create an array that will store the states for each(number of rows) checkboxes.
- (id)init {
self = [super init];
if (self) {
states=[[NSMutableArray alloc] initWithObjects:#"1", #"0", #"1", nil];
}
return self; }
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
NSLog(#"Num of rows---- %ld", [names count]);
return [names count];
}
Check for tableIdentifier having value "check".
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
if ([[tableColumn identifier] isEqualTo:#"name"]) {
return [names objectAtIndex:row];
}
else if ([[tableColumn identifier] isEqualTo:#"check"]) {
return [states objectAtIndex:row];
}
else if ([[tableColumn identifier] isEqualTo:#"states"]) {
return [states objectAtIndex:row];
}
return 0;
}
Update the value of checkbox as per on/off.
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn *)column row:(NSInteger)row {
[states replaceObjectAtIndex:row withObject:value];
[tableView reloadData];
}
I have a NSTableView with a single NSTableCellView column that let's say, has an icon, name and an optional date.
When you edit a row, I want to replace the whole view with a simple NSTextField, and I will do some parsing to that text and extract that optional date, if present.
My question is, how would you implement this editing mechanism?
I tried returning a different view in the tableView:viewForTableColumn:row, something like:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
BOOL isSelected = [tableView isRowSelected:row];
if (isSelected)
{
NSView *view = [tableView makeViewWithIdentifier:#"editor" owner:self];
....snip....
return view;
}
else
{
TaskView *view = [tableView makeViewWithIdentifier:#"view" owner:self];
....snip....
return view;
}
}
and then whenever the selected row changes, trying to request a refresh on that row.
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
NSTableView *table = [aNotification object];
NSUInteger rowIndex = [table selectedRow];
[table reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex]
columnIndexes:[NSIndexSet indexSetWithIndex:0]];
}
It doesn't quite work, and the code feels a bit dirty.
It must be a better way of doing this, and I can't seem to find in the docs or online.
I have window with 3 table views (10.7.2, Xcode 4.2).
They are all created in IB and NSButtonCells are connected with outlets.
I created controller class and I filled all three views with some sample data:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
return 10;
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
NSButtonCell *buttonCell;
if(aTableView == dimensionTable) {
[dimensionButtonCell setTitle:#"Dimension"];
buttonCell = dimensionButtonCell;
}
else if(aTableView == shopTable) {
[shopButtonCell setTitle:#"Shop"];
buttonCell = shopButtonCell;
}
else if(aTableView == countryTable) {
[countryButtonCell setTitle:#"Country"];
buttonCell = countryButtonCell;
}
return buttonCell;
}
I have 2 questions:
I cannot change checkbox state through GUI. I can change it programatically, though. It blinks a bit, when you hold down mouse button, but doesn't allow change...
I tried to fill data as with views, without outlets to cells. It didn't work. Are NSButtonCell cels within cell views somehow different as view based Table Views or "normal" cel based Table Views?
After long struggle I manage to find the solution for the problem. One part of the problem was simple bug at the data model side, but it wasn't crucial, something much more difficult was to be done with NSTableView delegate and datasource.
THere were mainly 3 difficulties that prevented good understanding and managing this problem:
apple's documentation lacks of any reasonable explanation about differences and typical usage of - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndexin table view's data source and - (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row of its delegate. While it may seem that you would need latter method, because NSButtonCells are custom NSCells it turns out it is not necessary, but I left it at the end anyway.
internal conversions in NSTableView methods
problem is not documented almost anywhere on the net
Here are steps you should do:
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
buttonCell = [aTableColumn dataCell];
NSString *columnKey = [aTableColumn identifier];
return buttonCell;
}
You can see this method has to be implemented whether you use it or not.
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
buttonCell = [tableColumn dataCell];
NSString *columnKey = [tableColumn identifier];
if(tableView == dimensionTable) {
// returnObject = #"Dimension";
// [dimensionButtonCell setTitle:#"Dimension"];
// buttonCell = dimensionButtonCell;
}
else if(tableView == shopTable) {
[buttonCell setState:[[mySelectedShops objectAtIndex:row] integerValue]];
[buttonCell setTitle:[myShops objectAtIndex:row]];
}
else if(tableView == countryTable) {
[buttonCell setState:[[mySelectedCountries objectAtIndex:row] integerValue]];
[buttonCell setTitle:[myCountries objectAtIndex:row]];
}
return buttonCell;
}
you can see I used second method, however objectValueForTableColumn could be used solely.
You can also see, I have NSMutableArray mySelectedShops and mySelectedCountries to hold NSInteger (1 or 0) wrapped in NSNumber for each row in Table View.
If you set the state or integerValue of NSCell makes no difference. Both will check and uncheck NSButtonCell with values 1 or 0 of NSInteger type.
- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
NSString *columnKey = [aTableColumn identifier];
if(aTableView == dimensionTable) {
// [dimensionButtonCell setTitle:#"Dimension"];
// buttonCell = dimensionButtonCell;
}
else if(aTableView == shopTable) {
[mySelectedShops replaceObjectAtIndex:rowIndex withObject:[NSNumber numberWithInteger:[(NSCell*)anObject integerValue]]];
}
else if(aTableView == countryTable) {
[mySelectedCountries replaceObjectAtIndex:rowIndex withObject:[NSNumber numberWithInteger:[(NSCell*)anObject integerValue]]];
}
}
Although I passed NSInteger value to NSCell object, anObject here is of __NSCFBoolean type, which means something doesn't work as expected. To be able to replace object value to arrays I have casted it to NSCell only to get integerValues. It actually works without cast as well, so it is another mystery to me, but I like it more that way.
It is clear Apple is moving to view based cells like in UITableView. Still, I hope this will help to somebody.