Pagine

2013-06-20

Doppio click su una NSTableView

Può capitare di voler aggiungere una funzionalità piuttosto banale: la possibilità di aprire un dialogo o di far comparire un editor tramite un doppio click su una tabella.
Le motivazione possono essere diverse: vogliamo che un valore sia controllato prima di essere insere inserito definitivamente; oppure poter mostrare un po' di dati non presenti nella tabella ma relativi alla riga selezionata.

Bene: la cosa sembrerebbe molto semplice e in effetti è vero, spesso... ma non sempre.

La cosa che si consiglia di fare di solito è di collegare un outlet della tabella (chiamiamo la property theTable) e poi di impostare il target e la doubleAction come segue in qualche metodo chiamato all'inizio (awakeFromNib, per esempio):
[self.theTable setTarget:self];
[self.theTable setDoubleAction:@selector(doubleClickOnTable:)];
Se nel metodo doubleClickOnTable inseriamo un NSLog(@"doppioCliccato") e lanciamo il tutto, vedremo che in effetti nella console di Xcode viene lasciata la traccia del messaggio ogni volta che andiamo a fare un doppio click. Poi, usando i messaggi clickedRow e clickedColumn otterremo la cella che è stata doppio-cliccata (di solito ci basta sapere la riga, ma se serve...).
Ottimo, ma questo è un caso semplice...
Supponiamo di voler mantenere la comodità dell'azione sul doppio click, ma di voler lasciare la libertà all'utente di editare il contenuto di una colonna, ma non di altre: l'utente si aspetterà che un doppio click su quella colonna metta in edit la cella, mentre un doppio click su altre colonne chiamino la funzione di prima. Ok, impostiamo l'edit della colonna voluta tramite il metodo del delegate:
- (BOOL)tableView:(NSTableView *)table shouldEditTableColumn:(NSTableColumn *)col row:(NSInteger)row
{
  if (tableColumn == [[tableView tableColumns] objectAtIndex:[tableView columnWithIdentifier:@"daEditare"]]) {
    return YES;
  }
  return NO;
}
Lanciamo: vedremo che il doppio click continua a "rubare" l'azione: ovunque sia il doppio click, compresa la colonna che vorremmo editare, viene sempre interpretato come doppio click! Doppio sigh!
L'unico modo di editare la cella voluta è di selezionare la riga e dopo un attimo fare un altro click sulla cella e solo allora potremo editarne il contenuto.
Questo non è bello: l'utente si aspetta che un doppio click gli lasci editare il contenuto e se stiamo bene a sentire, udremo i suoi improperi, piuttosto coloriti, ad ogni evento...

Cercando bene nella documentazione di Apple, scopriamo, molto nascosto, che l'impostare la doubleAction via codice è cosa diversa da impostarla via binding!! Anzi, ci avvisa che se le impostiamo entrambe, verranno chiamate tutte e due, una dopo l'altra!
Allora... tremendo sospetto... Eliminiamo l'impostazione da codice, andiamo nello xib, selezioniamo la tabella (non la scrollView...), apriamo l'inspector dei binding e clicchiamo su Double Click Target: gli metteremo l'oggetto che contiene il metodo da chiamare, nel Model Key Path lasciamo self, mentre scriveremo il nome del metodo nel campo Selector Name.

Salviamo e lanciamo: vedremo che un doppio click sulla cella aprirà il modo di edit, mentre un doppio click sulla cella di un'altra colonna, trovando impedito l'edit dal delegate, verrà chiamato il metodo cercato!

La spiegazione... non c'è! Anzi: Apple ci dice che la doubleAction da binding viene chiamata prima di quella da codice, ma questo spiegherebbe il contrario... Bah, visto che funziona, siamo a posto. Speriamo solo che un giorno Apple non cambi qualcosa...