-------------------------------------------------------------Implementazione della logica
-------------------------------------------------------------Dopo aver definito la nostra interfaccia, passiamo a definire la logica della nostra applicazione.
Creeremo una classe Controller che si preoccuperà di coordinare le varie operazioni dell'interfaccia utente e una classe CalculateLogic che implementerà la logica dei calcoli.
Classe Controller
-----------------------Questa classe, deve conoscere tutti gli oggetti specificati nell'interfaccia quindi necessità di OUTLETS per poter collegare l'istanza della classe dei vari oggetti (es. pulsanti, campo di immissione ecc.) e deve rispondere a tutte le
azioni previste dai vari elementi dell'interfaccia (implementa quindi delle ACTIONS).
La classe Controller, sarà anche la classe che fornirà i dati per la Tabella (NSTableView), sarà quindi il DATASOURCE della tabella implementando quindi i metodi del protocollo datasource (NSTableViewDataSource
protocol) e sarà infine DELEGATE per la tabella, implementando quindi i metodi di delegato per la tabella NSTableView. (NSTableViewDelegate Protocol)
Ma andiamo con ordine.
Prima creiamo la classe
quindi selezioniamo Objective-C class
Le diamo un nome, FGController e diciamo che è una classe che deriva da NSObject.
(NSObject è la classe base di Cocoa)
Dopo di chè non ci resta che confermare la creazione
Ora nel navigation panel si sono due nuovi files
FGController.h (la definizione della classe) e FGController.m (l'implementazione della classe).
//
//
//
//
//
//
//
FGConroller.h
FGFolderSize
Created by francesco on 8/3/13.
Copyright (c) 2013 Softech di Germinara Francesco. All rights reserved.
#import <Foundation/Foundation.h>
@interface FGConroller : NSObject
@end
//
//
//
//
//
//
//
FGConroller.m
FGFolderSize
Created by francesco on 8/3/13.
Copyright (c) 2013 Softech di Germinara Francesco. All rights reserved.
#import "FGConroller.h"
@implementation FGConroller
@end
A questo punto iniziamo a creare gli OUTLETS per poter collegare gli oggetti della nostra interfaccia grafica.
Ad esempio, noi vogliamo che il pulsante SFOGLIA sia attivo solo se non è già attivo un calcolo, per poter controllare la proprietà di tale pulsante dalla nostra classe dobbiamo in qualche modo "far conoscere" alla nostra classe il
pulsante SFOGLIA.
Per prima cosa, controlliamo a quale classe appartiene il pulsante SFOGLIA,
dopo averlo selezionato nell'elenco delle viste gerarchiche, tramite l'ispettore IDENTITY, vedo che è un NSButton.
a questo punto, passiamo sul file di definizione della nostra classe FGController.h e andiamo a creare l'outlet a cui collegheremo tale pulsante.
@property (nonatomic,weak)
IBOutlet NSButton *btnSfoglia; //Outlet per collegamento con pulsante sfoglia
In questa riga sono indicate diverse cose importanti:
1) @property dichiara che stiamo definendo una proprietà di nome btnSfoglia della nostra classe FGController, significa che potremo accedere a tale proprietà utilizzando il nome della
variabile della classe . (punto) nome della proprietà.
Esempio: all'interno della stessa classe, accederemo con self.btnSfoglia
2)(nonatomic,weak) weak, specifica che l'oggetto non è gestito direttamente dalla nostra classe (infatti è un istanza dell'interfaccia grafica creata in modo automatico)
3) IBOutlet non è una semplice proprietà ma un collegamento con un oggetto all'interfaccia grafica
4) NSButton l'oggetto a cui sarà collegato è un NSButton
5) *btnSfoglia il nome che stiamo assegnando a questa proprietà della classe FGController.
NOTA
Nella parte del navigatore accanto alla nuova riga appena creata, compare questo simbolo, che indica che è un OUTLET non ancora connessa.
diventa così quando sarà connessa all'oggetto dell'interfaccia
Se si attiva la vista per classi, notiamo una cosa curiosa,
in automatico il sistema riconosce la proprietà e genera internamente i metodi setter e getter (per approfondimenti si rimanda a documentazione Apple o Google)
Rimane ora da capire come collegare la nostra nuova proprietà con il pulsante Sfoglia dell'interfaccia.
Per poter fare i collegamenti dobbiamo avere nella nostra interfaccia una ISTANZA della classe FGController, che quindi diventa un OGGETTO con cui potremo far dialogare gli altri oggetti.
Vediamo come fare.
portiamoci sull'interfaccia grafica selezionando MainMenu.xib
ora cerchiamo nella libreria oggetti, l'oggetto NSObject
lo trasciniamo nella parte di disegno, non direttamente sulla finestra, e rilasciamo.
Ci troviamo ora in questa situazione
ora occorre semplicemente dire che l'oggetto Object che ha creato, non è una classe NSObject, ma la nostra FGController (che è derivata da NSObject)
da ispettore IDENTITY,
seleziono FGController
se attivo ispettore CONNECTIONS
mi trovo la proprietà btnSfoglia che è collegabile con un oggetto.
per collegarla click sul simbolo
e mantenendo premuto il tasto del mouse mi sposto sull'oggetto (Pulsante SFOGLIA) da collegare.
Se tutto corretto, mi ritrovo
NOTA
Se ho sbagliato e voglio eliminare il collegamento, clic su x
esempio solo NSButton).
, quando si muove il mouse per selezionare l'oggetto da collegare, solo gli oggetti del tipo previsto dall'outlet della classe saranno selezionabili (nel nostro
Anche dalla visualizzazione del navigator ora vedo che è connesso
se voglio sapere a cosa è connesso click sul pallino
Effettuiamo la stessa operazione per tutti i vari elementi, tenendo presente che la proprietà da creare deve essere della stessa classe dell'oggetto a cui collegarlo (es. NSTableView per il collegamento con la tabella, NSTextField
per il campo di immissione ecc.)
Ed ovviamente la CPTGraphHostingView dovrà essere collegata ad una proprietà dello stesso tipo.
Al termine dei collegamenti e della creazione delle proprietà avremo
//
//
//
//
//
//
//
FGConroller.h
FGFolderSize
Created by francesco on 8/3/13.
Copyright (c) 2013 Softech di Germinara Francesco. All rights reserved.
#import <Foundation/Foundation.h>
#import <CorePlot/CorePlot.h> //da includere per utilizzare il framework coreplot altrimenti CPTGraphHostingView è sconosciuta e da errore
@interface FGConroller : NSObject
@property
@property
@property
@property
@property
@property
(weak)
(weak)
(weak)
(weak)
(weak)
(weak)
IBOutlet
IBOutlet
IBOutlet
IBOutlet
IBOutlet
IBOutlet
NSButton
NSButton
NSButton
NSButton
NSButton
NSButton
*btnSfoglia;
*btnAdd;
*btnRemove;
*chkFastMode;
*btnStart;
*btnStop;
//Outlet
//Outlet
//Outlet
//Outlet
//Outlet
//Outlet
per
per
per
per
per
per
collegamento
collegamento
collegamento
collegamento
collegamento
collegamento
con
con
con
con
con
con
pulsante sfoglia
pulsante +
pulsante check box fast mode
pulsante start
pulsante stop
@property
@property
@property
@property
(weak)
(weak)
(weak)
(weak)
IBOutlet
IBOutlet
IBOutlet
IBOutlet
NSTextField *txtFolder;
//Outlet per collegamento con campo immissione
NSTableView *tblFoldes;
//Outlet per collegamento con tabella cartelle da elaborare
NSProgressIndicator *prgBar;
//Outlet per collegamento con barra di progresso
CPTGraphHostingView *graphResult;
//Outlet per collegamento con grafico risultato
@end
Vediamo ora come creare le ACTIONS.
Semplicemente, occorre definire nella nostra classe controller, dei metodi che implementano la parola chiave IBAction e che siano conformi alla
chiamata nomemetodo:(id) scender
Iniziamo con il pulsante Sfoglia, quando premuto vogliamo che esegua (chiami) il metodo browseFolder della classe FGConrolle.
Creaiamo quindi la riga di definizione del metodo in FGController.h
-(IBAction)browseFolder:(id)sender;
e la sua implementazione in FGController.m (Per ora non fa nulla, se non scrivere nella console un messaggio)
-(IBAction)browseFolder:(id)sender{
NSLog(@"browseFolder: Pulsante btnSfoglia premuto.");
}
Notare che il metodo non è collegato
quindi procediamo al collegamento.
Noto ora che anche
la tabella non è collegata , quindi provvedo ora a correggere.
Per collegare i vari oggetti nell'interfaccia possiamo anche procedere selezionando l'oggetto da collegare e premendo CTRL trascinare il mouse sull'oggetto di destinazione.
Nel caso di collegamento della azione, ad esempio, click sul pulsante sfoglia, quindi trascino su oggetto Controller presente nella elenco gerarchico delle viste. Quando rilascio
compare
e seleziono l'azione da collegare.
Questo è il risultato per quanto riguardo l'oggetto pulsante sfoglia
si vede che ha due collegamenti, uno verso il Controller per l'azione (sent => click) e uno del controller come referenza (la proprietà btnSfoglia che avevamo creato e collegato).
La situazione sino a questo punto per l'oggetto Controller è
dove si vede che è collegato ad una serie di outlets tramite le proprietà in esso definite e che riceve una Azione (ossia viene chiamato il metodo della classe) tramite il pulsante (che sappiamo essere Sfoglia, perché l'unico che
abbiamo collegato).
Bene, procediamo con la creazione ed il collegamento di tutte le altre ACTIONS.
Al termine avremo
//
//
//
//
//
//
//
FGConroller.h
FGFolderSize
Created by francesco on 8/3/13.
Copyright (c) 2013 Softech di Germinara Francesco. All rights reserved.
#import <Foundation/Foundation.h>
#import <CorePlot/CorePlot.h>
@interface FGConroller : NSObject
@property
@property
@property
@property
@property
@property
(weak)
(weak)
(weak)
(weak)
(weak)
(weak)
IBOutlet
IBOutlet
IBOutlet
IBOutlet
IBOutlet
IBOutlet
NSButton
NSButton
NSButton
NSButton
NSButton
NSButton
*btnSfoglia;
*btnAdd;
*btnRemove;
*chkFastMode;
*btnStart;
*btnStop;
//Outlet
//Outlet
//Outlet
//Outlet
//Outlet
//Outlet
per
per
per
per
per
per
collegamento
collegamento
collegamento
collegamento
collegamento
collegamento
@property
@property
@property
@property
(weak)
(weak)
(weak)
(weak)
IBOutlet
IBOutlet
IBOutlet
IBOutlet
NSTextField *txtFolder;
//Outlet per collegamento con campo immissione
NSTableView *tblFoldes;
//Outlet per collegamento con tabella cartelle da elaborare
NSProgressIndicator *prgBar;
//Outlet per collegamento con barra di progresso
CPTGraphHostingView *graphResult;
//Outlet per collegamento con grafico risultato
-(IBAction)browseFolder:(id)sender; //Pulsante Sfoglia premuto
-(IBAction)addItem:(id)sender; //Pulsante + premuto
-(IBAction)removeItem:(id)sender; //Pulsante - premuto
-(IBAction)start:(id)sender; //Pulsante start premuto
-(IBAction)stop:(id)sender; //Pulsante stop premuto
@end
//
//
//
//
//
//
//
FGConroller.m
FGFolderSize
Created by francesco on 8/3/13.
Copyright (c) 2013 Softech di Germinara Francesco. All rights reserved.
#import "FGConroller.h"
con
con
con
con
con
con
pulsante sfoglia
pulsante +
pulsante check box fast mode
pulsante start
pulsante stop
@implementation FGConroller
-(IBAction)browseFolder:(id)sender{
NSLog(@"browseFolder: Pulsante btnSfoglia premuto.");
}
-(IBAction)addItem:(id)sender{
NSLog(@"addItem:");
}
-(IBAction)removeItem:(id)sender{
NSLog(@"removeItem: ");
}
-(IBAction)start:(id)sender{
NSLog(@"start: ");
}
-(IBAction)stop:(id)sender{
NSLog(@"stop: ");
}
@end
Proviamo a vedere se funziona il tutto.
Compilo (cmd+b) e poi eseguo.
Quando il programma è in esecuzione premo i vari pulsanti è nell'area di DEBUG di XCODE vedrò i messagi di log che abbiamo impostato precedentemente.
Implementiamo i vari metodi, iniziamo con il pulsante sfoglia.
Quando premiamo il pulsante sfoglia, voglia che si apra la finestra standard di OS X per consentirci di selezionare la cartella che vogliamo aggiungere nell'elenco delle cartelle da elaborare.
-(IBAction)browseFolder:(id)sender{
NSLog(@"browseFolder: Pulsante btnSfoglia premuto.");
NSOpenPanel
[aOpenPanel
[aOpenPanel
[aOpenPanel
* aOpenPanel = [NSOpenPanel openPanel]; //Oggetto per gestire pannello OPEN standard OS X
setCanChooseDirectories:YES]; //Voglio poter scegliere le cartelle
setCanChooseFiles:NO]; //Non voglio scegliere i files
setAllowsMultipleSelection:NO]; //Solo una cartella per volta
[aOpenPanel beginWithCompletionHandler:^(NSInteger result){ //Compare la finest e restituisce il valore quando chiusa
if (result == NSFileHandlingPanelOKButton) { //Ok, l'utente ha scelto la cartella e permuto OK
NSURL* theDoc = [[aOpenPanel URLs] objectAtIndex:0]; //Ricavo l'elemento scelto dall'utente (come NSURL)
self.txtFolder.stringValue=[theDoc path]; //Lo transformo in NSString e lo assegno al mio campo di immissione
}
}];
}
Ecco come si presenta dopo esecuzione del programma se premo Sfoglia,
e se premo OPEN dopo aver selezionato la cartella Films
Gestione della Tabella
=================
Occorre ora provvedere a gestire la tabella per consentire di aggiungere il percorso selezionato nell'elenco.
Per fare questo, occorre far diventare la nostra classe FGController anche il datasource ed il delegate dalla NSTableView.
Il compito del datasource è quello di fornire i dati che la NSTableView richiede di volta in volta, mentre il fatto di essere la delegate della NSTableView implica che i messaggi che la NSTableView genera (es. riga selezionata)
siano inviati alla classe delegata.
Per poter mantenere l'elenco delle cartelle selezionate mi occorre un oggetto che gestisca un elenco di altri oggetti, tale comportamento è proprio quello della classe NSMutableArray.
La classe NSMutableArray, è un array (vettore ad una dimensione) che conterrà l'elenco delle nostre cartelle selezionate.
Definiamo quindi per prima cosa una variabile di questo tipo, che chiamato dsFolders nella classe FGController e inizializziamola.
Modifico il file FGController.h aggiungendo il blocco delle { } dentro cui mettere le variabili della classe.
@interface FGConroller : NSObject{
NSMutableArray *dsFolders; //ivar (variable membro della classe) per gestire l'elenco delle cartelle selezionate
}
Per inizializzarla, mi serve un metodo che sia eseguito quando la classe viene istanziata. Ho due possibilità di scelta,
implemento il metodo init (per attivare i suggerimenti, premere ALT+ESC nell'editor)
oppure utilizzo il metodo awakeFromNib
Init è chiamato quando la classe viene creata (viene creata un istanza)
awakeFromNib è chiamata quando il file di interfaccia (.xib o .nib) viene caricato dall'applicazione
A scopo didattico riporto entrambi i metodi
- (id)init
{
self = [super init];
if (self) {
NSLog(@"init Chiamata...");
}
return self;
}
-(void) awakeFromNib{
NSLog(@"awakeFromNib Chiamata...");
}
decido di inizializzare la nostra variabile dsFolders nella Init, quindi nel file FGController.m modifico il metodo init, in modo da creare l'oggetto di NSMutableArray che andremo a riempire.
- (id)init
{
self = [super init];
if (self) {
NSLog(@"init Chiamata...");
dsFolders = [[NSMutableArray alloc] init]; //Inizializzo la variabile, non contiene nulla al momento
}
return self;
}
A questo punto, posso implementare i metodi
-(IBAction)addItem:(id)sender
e
-(IBAction)removeItem:(id)sender
che agiscono su questa variabile.
-(IBAction)addItem:(id)sender{
NSLog(@"addItem:");
//Aggiungo l'elemento indicato nel campo di immissione nell'array
[dsFolders addObject:self.txtFolder.stringValue];
}
Per la cancellazione, devo prima cercare la posizione nell' array della cartella che voglio togliere dall'array e successivamente, rimuoverla.
-(IBAction)removeItem:(id)sender{
NSLog(@"removeItem: ");
int nIndex = [self searchItem:self.txtFolder.stringValue];
if(nIndex != -1){
[dsFolders removeObjectAtIndex:nIndex];
}
}
Ovviamente ora devo implementare il metodo searchItem, nella classe.
Notare che xcode segnala l'errore del metodo non dichiarato.
Per creare il metodo per la ricerca, dobbiamo chiederci che parametri passare e che valore ci deve restituire, nel nostro caso, passiamo una stringa (NSString *) e riceviamo un numero (int) che è la posizione nell'array (a partire
da 0 per la prima posizione). Se non trovo la stringa restituisco -1
-(int) searchItem:(NSString*) folderToSearch{
int nItems = [dsFolders count]; //Numero di elementi nell'array
int nIndex = 0;
for(nIndex=0; nIndex < nItems; nIndex++){ //Loop su tutti gli elementi dell'array
NSString *aFolder = [dsFolders objectAtIndex: nIndex]; //Estraggo il valore contenuto nella posizione specificata
if([aFolder isEqualToString: folderToSearch]) //Se il valore contenuto nell'array alla posizione indicata è uguale a quello cercato
return nIndex; //Ok, trovato restituisco l'indice
}
return -1; //Non trovato
}
Oltre a definire il nuovo metodo nel file FGController.m occorre specifica l'esistenza di tale metodo nel file FGController.h per la definizione (in modo che xcode ed altre classi sappiano che esiste).
-(int) searchItem:(NSString*) folderToSearch; //Cerca la cartella specificata nell'array delle cartelle. -1 se non la trova.
dato che ora ho questo nuovo metodo, lo uso per migliorare il funzionamento anche del metodo addItem, inserisco solo se non è già presente nell'elenco.
-(IBAction)addItem:(id)sender{
NSLog(@"addItem:");
int nIndex = [self searchItem:self.txtFolder.stringValue]; //Controllo di non aver già inserito la cartella
if(nIndex==-1){
//Aggiungo l'elemento indicato nel campo di immissione nell'array
[dsFolders addObject:self.txtFolder.stringValue];
}
}
Compiliamo e proviamo. Ok, io premo + e -, nel lob vedo i messaggi
2013-08-04
2013-08-04
2013-08-04
2013-08-04
2013-08-04
2013-08-04
2013-08-04
2013-08-04
00:15:41.495
00:15:41.499
00:15:45.381
00:15:48.581
00:15:49.301
00:15:49.837
00:15:51.093
00:15:51.420
FGFolderSize[37765:303]
FGFolderSize[37765:303]
FGFolderSize[37765:303]
FGFolderSize[37765:303]
FGFolderSize[37765:303]
FGFolderSize[37765:303]
FGFolderSize[37765:303]
FGFolderSize[37765:303]
init Chiamata...
awakeFromNib Chiamata...
addItem:
addItem:
addItem:
addItem:
removeItem:
removeItem:
ma come faccio a vedere se realmente nell'array tutto sta funzionando regolarmente ?
UTILIZZO DEI BREAKPOINT
=======================
per controllare cosa succede durante l'esecuzione del programma, posiziono due breakpoint (punti di interruzione) nei metodi che mi interessa controllare e quando il programma si
fermerà (break) potrò
ispezionare le variabile e farmi stampare nella console del log il contenuto dell'array.
per mettere un breakpoint, click con il mouse all'altezza della riga dove voglio interrompere (la zona da cliccare è quella dove ora compare la freccia BLU).
ecco predisposto i miei breakpoint che mi interessano
ora eseguiamo il programma e dopo aver digitato qualcosa nel campo di immissione della cartella, premiamo il tasto + per aggiungerlo nell'elenco e vediamo che succede.
non appena premo +, il programma prosegue ma si ferma in corrispondenza del breakpoint che abbiamo inserito
nell'AREA di DEBUG posso già vedere il valore di alcune variabili
premo
per continuare l'esecuzione
ed il programma proseue ma si ferma all'altro breakpoint che avevo messo nella funzione searchItem
vedo già subito che la funzione è prossima ad uscire col il valore -1, perché non ho trovato. Trovato cosa ?
vedo che è stato passato correttamente la stringa (NSString*) miacartella (che era il valore che ho immesso nel campo)
vedo anche che non è presente in quanto l'array è al momento VUOTO (0 objects) e nItems = 0
premo
per continuare l'esecuzione
mi ritorna la finestra dell'applicazione pronta per ricevere nuovi comandi, ripremo il pulsante + lasciando il campo di immissione con il valore precedente
ovviamente si ferma al primo breakpoint
premo
per continuare l'esecuzione
si ferma nel metodo searchItem, ma questa volta in un altro breakpoint che avevo posizionato, all'interno del loop
quindi significa che c'e' qualcosa nell'array
vedo già che c'è un elemento (nItems = 1)
ora voglio eseguire solo l'istruzione successiva a quella dove il programma si è fermato quindi premo
l'esecuzione della riga è stata completata e posso vedere il contenuto della variabile aFolder (che contiene l'oggetto del primo elemento dell'array, ossia la NSString "miacartella"
dato che aFolder e folderToSearch contengono lo stesso valore, mi aspetto che si esca dal metodo con il valore dell'indice = 0
quindi premo
per andare avanti con la singola istruzione e vediamo, che il test ha dato esito positivo e quindi si sta per eseguire return nIndex, con nIndex che vale 0
Per togliere i breakpoint, cliccare sulla freccia blu e trascinarla sulla parte dell'editor, scompare con il classico effetto nuvoletta.
IMPLEMENTAZIONE DEL DATASOURCE
==============================
Ora che sappiamo che i nostri metodi per aggiungere e rimuovere le cartella dall'array dell'elenco cartelle funzionano, poesia tranquillamente implementare il protocollo DataSource
per la nostra classe in modo da fornire i dati che saranno visualizzati nella tabella.
Per prima cosa, indichiamo nel file FGController.h che la classe ora implementa il protocollo NSTableViewDataSource, i protocolli si indicano tra i simboli < >
@interface FGConroller : NSObject <NSTableViewDataSource> {
Ora dobbiamo implementare i metodi OBBLIGATORI per tale protocollo, vediamo cosa ci dice mamma Apple,
il primo metodo che la nostra FGController deve implementare per essere un valido datasource per la nostra tabella è
numberOfRowsInTableView:
Returns the number of records managed for aTableView by the data source object.
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
ci dice quanti elementi ci sono nella tabella, nel nostro caso è semplice, sono gli stessi che abbiamo nel nostro array dsFolders
quindi modifico il file FGController.m aggiungendo il metodo richiesto che calcola il numero di elementi nella tabella semplicemente con [dsFolders count]
#pragma mark DATASOURCE methods
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView{
return [dsFolders count];
}
il secondo metodo obbligatorio è
tableView:objectValueForTableColumn:row:
Invoked by the table view to return the data object associated with the specified row and column.
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
che serve per fornire alla tabella, il valore da rappresentare nella cella della colonna aTableColumn alla riga rowIndex, in pratica dobbiamo ricavare il valore dal nostro array alla riga
specificata e restituirlo.
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex{
return [dsFolders objectAtIndex:rowIndex];
}
Nota: dato che la nostra tabella ha solo una colonna, ignoriamo il valore aTableColumn passato alla funzione. In altri casi occorre invece controllare di quale colonna si tratta e
restituire l'opportuno valore.
Per concluder dobbiamo solo effettuare ancora un paio di operazioni:
1. "dire" alla tabella che il datasource è la classe FGController
2. segnalare alla tabella che qualcosa è cambiato quando si aggiunge o si rimuove un elemento.
Per "dire" alla tabella che il datasource è la classe FGController, il posto migliore è nella awakeFromNib (non nella Init perché la tabella non esiste ancora, viene creata in
automatico quando l'interfaccia è caricata).
-(void) awakeFromNib{
NSLog(@"awakeFromNib Chiamata...");
self.tblFoldes.dataSource=self; //Imposto questa classe (FGController) come datasource della tabella (NSTableView)
}
per segnalare alla tabella i cambiamenti del contenuto dell'array, si usa il metodo reloadData, quindi occorre aggiungere ai metodi addItem e removeItem la seguente riga
[self.tblFoldes reloadData]; //Segnala alla tabella che qualcosa è cambiato e riaggiorna il contenuto
-(IBAction)addItem:(id)sender{
NSLog(@"addItem:");
int nIndex = [self searchItem:self.txtFolder.stringValue]; //Controllo di non aver già inserito la cartella
if(nIndex==-1){
//Aggiungo l'elemento indicato nel campo di immissione nell'array
[dsFolders addObject:self.txtFolder.stringValue];
[self.tblFoldes reloadData]; //Segnala alla tabella che qualcosa è cambiato e riaggiorna il contenuto
}
}
-(IBAction)removeItem:(id)sender{
NSLog(@"removeItem: ");
int nIndex = [self searchItem:self.txtFolder.stringValue];
if(nIndex != -1){
[dsFolders removeObjectAtIndex:nIndex];
[self.tblFoldes reloadData]; //Segnala alla tabella che qualcosa è cambiato e riaggiorna il contenuto
}
}
Se tutto è stato fatto correttamente, eseguiamo e controlliamo.
proviamo a cancellare. Ok.
Per cancellare, devo indicare manualmente il nome della cartella nel campo di immissione e premere -, sarebbe più comodo poter fare un click sulla riga della tabella e far comparire
il contenuto in automatico nel campo di immissione.
Per farlo, è sufficiente dire che la classe FGController implementa anche il protocollo NSTableViewDelegate.
Aggiungiamo tale indicazione nel file FGController.h
e definiamo i metodi che ci interessa gestire, nel caso specifico, sapere quando viene cambiata la selezione dell'elemento della tabella
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
modifico la classe FGController.m implementando tale metodo
#pragma mark TABLEVIEW Delegate methods
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification{
int nSelectedRow = self.tblFoldes.selectedRow; //Controllo quale elemento è stato selezionato
if(nSelectedRow != -1){ //-1 nessun elemento
self.txtFolder.stringValue=[dsFolders objectAtIndex:nSelectedRow]; //Assegno al campo di immissione il valore della riga della tabella selezionata
}
}
devo infine dire alla tabella che la classe FGController è delegata per la tabella, lo faccio nella awakeFromNib.
-(void) awakeFromNib{
NSLog(@"awakeFromNib Chiamata...");
self.tblFoldes.dataSource=self; //Imposto questa classe (FGController) come datasource della tabella (NSTableView)
self.txtFolder.delegate=self; //Imposto questa classe (FGController) come delegate della tabella (NSTableView)
}
Ci vediamo alla prossima puntata
Francesco Germinara