CocoaGurus
September 09, 2010, 11:23:44 AM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News: Bienvenido a CocoaGurus
 
   Home   Help Search Calendar Login Register  
Pages: [1]
  Print  
Author Topic: Añadir un NSComboBoxCell a un Table View  (Read 797 times)
xphere
Newbie
*
Posts: 7



View Profile WWW
« on: May 01, 2009, 12:21:51 AM »

Hola!!!

Tengo una table view, y quiero añadir una combos con certoes elementos en cada uno de los rows (ver "layers.png").
Como podéis ver en la imagen, para cosas como la imagen en thumbail, o los textos, parece que todo funciona bien. Pero en el caso de la ComboBoxCell, parece que no funciona: No puedo añadir elementos, ni seleccionar un valor, el code que hay para cada vez que se crea un row (una layer) es:
Code:
GLImage *spImage;

(...)

NSComboBoxCell* comboCell = [[NSComboBoxCell alloc] init];
[spImage setOperation:comboCell];
[comboCell setControlSize:NSSmallControlSize];
[comboCell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
[comboCell setEditable:NO];
[comboCell addItemWithObjectValue:@"pepe1"];
[comboCell addItemWithObjectValue:@"pepe2"];
[comboCell addItemWithObjectValue:@"pepe3"];
[comboCell addItemWithObjectValue:@"pepe4"];
[comboCell setAction:@selector(selectedItem:)];
[comboCell setTarget:self];
Siendo 'spImage' el row a añadir, y 'setOperation' el método que "fija" el NSComboCell a mi row. En teoria, mi combo debería tener elementos "pepe1,pepe2...", pero no hay nada, como veis en la imagen...

Por si sirve de ayuda, añado el code de la estructura 'GLImage':
Code:
@interface GLImage : NSObject {

NSButton * _visible;
NSImage * _defaultThumbnail;
NSComboBoxCell * _operation;
NSString * _title;

}

#pragma mark Accessors

- (NSButton*)visible;
- (void)setVisible:(NSButton*)aValue;

- (NSImage*)defaultThumbnail;
- (void)setDefaultThumbnail:(NSImage*)aValue;

- (NSComboBoxCell*)operation;
- (void)setOperation:(NSComboBoxCell*)aValue;

- (NSString*)title;
- (void)setTitle:(NSString*)aValue;

@end

y los métodos de la NSComboBoxCell:
Code:
- (NSComboBoxCell*)operation
{
    return _operation;
}

- (void)setOperation:(NSComboBoxCell*)aValue
{
    NSComboBoxCell* oldOperation = _operation;
    _operation = [aValue retain];
    [oldOperation release];
}

Podeis mirar donde tengo mal el code?
« Last Edit: May 01, 2009, 12:31:40 AM by xphere » Logged

zon@n power!
xphere
Newbie
*
Posts: 7



View Profile WWW
« Reply #1 on: May 01, 2009, 01:23:08 AM »

doh! alguien puede mover este thread? está en el grupo equivocado... esto deberia ir a cocoa, no a cocoa touch!
Logged

zon@n power!
xphere
Newbie
*
Posts: 7



View Profile WWW
« Reply #2 on: June 22, 2009, 10:51:23 AM »

No sin mucho sufrir, he encontrado la solución!
Os pongo el link por si alguien se encuentra con el mismo problema que yo algún día:
http://www.cocoadev.com/index.pl?NSComboBoxCellExample

Y pongo un copy/paste... por si algun dia la pagina está down:
Quote
It took me a little while and some experimentation to understand how it works. I could not find a working sample code at the time so I will post one below. You need understand the following in order to use NSComboBoxCell and NSTableView:

    * obviously in interface builder you must drop the NSComboBoxCell control onto the table column... (from the data views palette);
    * in interface builder, the column now gives you access to two sets of properties: the column itself (name, identifier, etc.) and the NSComboBoxCell. You access the later by clicking on the little triangle in the column header;
    * the value you see in the table comes from tableView:objectValueForTableColumn:row:, not from the combo box, so you need to implement this method in the table data source;
    * when the user selects an entry in the combo box, the box posts a tableView:setObjectValue:forTableColumn:row: message to the table data source with the user selection, so you must implement this method too. Record the user selection and return it through tableView:objectValueForTableColumn:row:;
    * last but not least, the table view uses only one shared NSComboBoxCell for every line, so if you need different values depending on the line on the line you must implement tableView:willDisplayCell:forTableColumn:row: as well and update the list entries.

In other words, there are two controls (table view and combo box cell), each with a specific role. The table view displays the value and records the user selection (the last bit is somewhat counter-intuitive but it makes sense given how the table view works). The combo box cell displays the list of choices but it does not record the selection.

Here's the promised code sample. You will need to create a project (sorry, can't upload a project right now) and do some of the work in interface builder yourself:
Code:
    * add a table with two columns with the following identifier (important): pos and combo;
    * drop the NSComboBoxCell on the second column (combo);
    * create the class ComboBoxDS as a subclass of NSObject;
    * double-click the table and open the info palette, set ComboBoxDS as the table data source and delegate (important);
    * double-click the combo column, click the triangle in the column header to open the NSComboBoxCell info;
    * select "Uses Data Source" in the attributes (important);
    * you may check the "Editable" property;
    * set ComboBoxDS as the box data source;
    * create the files for ComboBoxDS;
    * back to Xcode, copy/paste the following code into the class (the .m file, you don't need to edit the generated header).

    #import "ComboBoxDS.h"

    /* for this example to work, the class must be set as:
       - data source for the table view
       - data source for the combo box
       - delegate for the table view */

    @implementation ComboBoxDS

    /* create, randomly initialize and release the data structure for the data source
       we'll store the data in an array, each line is a dictionary with 3 entries:
       - pos contains the line number (just an ordinary column)
       - combo contains the current selection for the combo column
       - combov contains an array with the values for the list */

    -(id)init
    {
       self = [super init];
       if(self)
          records = [[NSMutableArray arrayWithCapacity:25] retain];
       return self;
    }

    -(void)dealloc
    {
       [records release];
       [super dealloc];
    }

    -(void)awakeFromNib
    {
       srand([[NSDate date] timeIntervalSince1970]);
       int l = rand()/(int)(((unsigned)RAND_MAX + 1) / 25);
       int i, j;
       for(i = 0;i < l;i++)
       {
          int r = rand()/(int)(((unsigned)RAND_MAX + 1) / 15) + 1;
          NSMutableArray *list = [NSMutableArray arrayWithCapacity:r];
          for(j = 0;j < r;j++)
             [list addObject:[NSString stringWithFormat:@"data %d from line %d",j,i]];
          NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:3];
          [dic setObject:[NSNumber numberWithInt:i] forKey:@"pos"];
          [dic setObject:list forKey:@"combov"];
          [dic setObject:[list objectAtIndex:0] forKey:@"combo"];
          [records addObject:dic];
       }
    }

    /* data source for the NSComboBoxCell
       it reads the data from the representedObject
       the cell is responsible to display and manage the list of options
       (we set representedObject in tableView:willDisplayCell:forTableColumn:row:)
       this is optional, the alternative is to enter a list of values in interface builder */

    -(id)comboBoxCell:(NSComboBoxCell*)cell objectValueForItemAtIndex:(int)index
    {
       NSArray *values = [cell representedObject];
       if(values == nil)
          return @"";
       else
          return [values objectAtIndex:index];
    }

    -(int)numberOfItemsInComboBoxCell:(NSComboBoxCell*)cell
    {
       NSArray *values = [cell representedObject];
       if(values == nil)
          return 0;
       else
          return [values count];
    }

    -(int)comboBoxCell:(NSComboBoxCell*)cell indexOfItemWithStringValue:(NSString*)st
    {
       NSArray *values = [cell representedObject];
       if(values == nil)
          return NSNotFound;
       else
          return [values indexOfObject:st];
    }

    /* data source for the NSTableView
       the table is responsible to display and record the user selection
       (as opposed to the list of choices)
       this is required */

    -(int)numberOfRowsInTableView:(NSTableView*)tableView
    {
       return [records count];
    }

    -(id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(int)index
    {
       return [[records objectAtIndex:index] objectForKey:[tableColumn identifier]];
    }

    -(void)tableView:(NSTableView*)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn*)tableColumn row:(int)index
    {
       if(nil == value)
          value = @"";
       if([[tableColumn identifier] isEqual:@"combo"])
          [[records objectAtIndex:index] setObject:value forKey:@"combo"];
    }

    /* delegate for the NSTableView
       since there's only one combo box for all the lines, we need to populate it with the proper
       values for the line as set its selection, etc.
       this is optional, the alternative is to set a list of values in interface builder  */

    -(void)tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(int)index
    {
       if([[tableColumn identifier] isEqual:@"combo"] && [cell isKindOfClass:[NSComboBoxCell class]])
       {
          NSDictionary *dic = [records objectAtIndex:index];
          [cell setRepresentedObject:[dic objectForKey:@"combov"]];
          [cell reloadData];
          [cell selectItemAtIndex:[self comboBoxCell:cell indexOfItemWithStringValue:[dic objectForKey:@"combo"]]];
          [cell setObjectValue:[dic objectForKey:@"combo"]];
       }
    }

    @end
Note that the combo box data source and the table delegate are not required if the list of values is identical for every line. The indirection is only required if you need to set the list of values programmatically. The table data source is always required.

For simplicity, I have only one class that implements the two data sources and the delegate. For more complex applications, you may want to spread the code over multiple classes.

Let me know if it helps.
Logged

zon@n power!
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.8 | SMF © 2006-2008, Simple Machines LLC Valid XHTML 1.0! Valid CSS!