Tutorial
Cocoa, Odbc and MySql - Ideato e scritto da Francesco Germinara
Pinerolo,
Italy
www.germinara.it
info@germinara.it
Si
ringrazia per la collaborazione la ditta Actual Technologies che si è fidata di
me e mi ha concesso la possibilità di distribuire, insieme a questo tutorial,
il file contenente la licenza per utilizzare il loro driver ODBC per un periodo
trial di 15 Giorni www.actualtechnologies.com
--------------------------------------------------------------------------------
Premessa
========
Il
presente tutorial è stato realizzato con lo scopo di aiutare tutti coloro
che
vogliono provare ad utilizzare l'ambiente free XCODE di Apple per la
programmazione in ambiente Macintosh.
Il
tutorial, spiega passo, passo le operazioni da compiere per creare una semplice
applicazione che utilizzi le connessioni ODBC per accedere ai dati memorizzati
su un database MySQL.
Per
informazioni, commenti e suggerimenti
info@germinara.it
Buon
divertimento.
F.Germinara
Strumenti
=========
Per
poter realizzare l'applicazione dovete procurarvi:
- UN
MAC dotato di Mac OS X 10.3.9 o superiore
-
Scaricare ed installare MySQL dal sito
http://www.mysql.com
-
Scaricare ed installare i driver ODBC per MYSQL della
http://www.actualtechnologies.com
-
Scaricare ed installare XCODE 2.2 dal sito
http://developer.apple.com/transition/index.html
Descrizione
dell'applicazione
=============================
Dato il
periodo natalizio, non potevo che pensare ad un’applicazione adeguata a questo
particolare periodo dell’anno.
Si
tratta di una Gestione dei Regali
L'applicazione
consente di gestire un’anagrafica di persone, di regali e
di tipo
di ricorrenza (Es. Natale, Compleanno, Matrimonio ecc.).
Le
operazioni che l'applicazione consente di effettuare sono:
-
Abbinare il regalo ad una persona, valutando diversi criteri di scelta
-
Ricercare tutti i regali fatti ad una persona
-
Ricercare tutte le persone a cui è stato fatto un certo tipo di regalo
-
Ricercare i regali fatti alle varie persone in base ad un determinato tipo di
ricorrenza
- farsi
aiutare dal programma per la scelta dei regali da fare per una determinata
persona utilizzando diversi criteri di analisi, esempio lo sport praticato, un
hobby, l’età della persona, se è single e se rientra nel budget di spesa che
abbiamo previsto per la persona.
DataBase
========
Il nome
del database e' DBREGALI
Tabelle del database
====================
Nome
della tabella: PERSONE
E' l'elenco di tutte le persone a cui abbiamo
fatto o
faremo dei regali
Definizione tabella:
Nome campo
Tipo Dimensione Chiave Null Descrizione
ID_PERSONA
Char 25 Yes
No
DESCR
char 60 No
Yes
BUDGET
float 8 No
Yes
ETA
int 4 NO
Yes
HOBBY
char 30 No
Yes
SPORT
char 30 No
Yes
SINGLE
char 1 No
Yes
NATOIL
char 8 No
Yes (aaaammgg)
Nome
della tabella: REGALI
E' l'elenco dei regali che possiamo fare.
Contiene anche le indicazioni relative a dei
criteri per aiutarci a scegliere
il regalo per un certa persona (es. l'eta',
se Ë single o sposato, se ha un hobby
o uno
pratica uno sport).
Definizione tabella:
Nome campo
Tipo Dimensione Chiave Null Descrizione
ID_REGALO
Char 25 Yes
No
DESCR
char 60 No
Yes
COSTO
float 8 No
Yes
ADATTO_SINGLE char 1 No
Yes
ETA_D
int 4 NO
Yes
ETA_A
int 4 NO
Yes
IDEALE_PER
char 30 NO
Yes (un hobby,un tipo
di sport...)
Nome
della tabella: RICORRENZE
E' l'elenco delle possibili ricorrenze per le
quali abbiamo fatto un regalo
Definizione tabella:
Nome campo
Tipo Dimensione Chiave Null Descrizione
ID_TIPO_RICOR
Char 4 Yes
No
DESCR
char 60 No
Yes
Nome
della tabella: STORICOREGALI
E' lo storico di tutti i regali che abbiamo
fatto per le varie persone nei vari
anni e per le diverse ricorrenze.
Definizione tabella:
Nome campo
Tipo Dimensione Chiave Null Descrizione
ID_PERSONA
Char 25 Yes
No Identificativo della persona
ID_REGALO
Char 25 Yes
No Identificativo del regalo che
e' stato fatto
ANNO
char 4 Yes
No Anno in cui Ë stato fatto
ID_TIPO_RICOR char 4 YES
No Tipo di ricorrenza
FUNZIONI
DELL'APPLICAZIONI DA SVILUPPARE
========================================
DEFINIZIONE
DEI MENU
1) Menu
Tabelle di Base
Gestione Anagrafica PERSONE,REGALI e
RICORRENZE. Con il termine Gestione
indichiamo la possibilità di
Inserire/Modifica/Stampa e Cancellare dati
2) Menu
Gestione Regali
Immissione/variazione/stampa e cancellazione
dati relativi allo storico dei regali
3) Menu
Statistiche
Creazione/Salvataggio/Esecuzione di query
per aiutarci a valutare i regali da abbinare alle persone
INIZIAMO
========
1) Creazione del DataBase e delle Tabelle
Mandiamo
in esecuzione MySQL ADMINISTRATOR

premiamo
Connect e se tutto è OK ci troviamo nella videata di MySql Administrator.

Scegliamo
CATALOGS
E
creiamo il nostro DATABASE (Create SCHEMA)
Clic
nella tree view dei databases
E
premiamo
per creare un nuovo Schema/database DBREGALI

Nella
tree view compare il nuovo database

Passiamo
ora alla creazione delle Tabelle
Selezioniamo
il nostro database DBREGALI e poi scegliamo
table action, Create Table

La
prima tabella che creiamo ha nome PERSONE
Dopo
aver scelto Create Table, compare la seguente videata

Indichiamo
il nome della tabella ed eventualmente un commento.
A
questo punto è necessario indicare le varie informazioni che intendiamo gestire
(CAMPI), Per creare un nuovo campo
Premiamo
e compare
![]()
Bene,
ora possiamo compilare i vari campi (colonne) con i dati che ci siamo
prefissati precedentemente per la tabella delle Persone.
Il
risultato che otteniamo è il seguente

Procediamo
ora e definire la chiave UNIVOCA della tabella, ossia la chiave per la quale
NON POTRANNO MAI esistere due records uguali. Tale chiave è basata sul campo
ID_PERSONA.
Clicchiamo
sul nella zona cambiamo il Name e Kind (deve essere una
Primari Key = chiave UNIVOCA)
Ora
premiamo nella zona in modo da specificare quali sono le colonne
della nostra tabella che sono utilizzate per formare la Primari key (nel nostro
caso, per questa tabella, solo un campo e precisamente ID_PERSONA).

Per
confermare la creazione della tabella, premiamo APPLY, ci compare una finestra
che contiene l'istruzione SQL per la creazione di una Tabella
premiamo
EXECUTE.
Ecco
come deve presentarsi alla fine la videata relativa alla tabella PERSONE

Premiamo
CLOSE e proseguiamo con la creazione delle altre tabelle
TABELLA
REGALI

TABELLA
RICORRENZE

TABELLA
STORICOREGALI
Questa
tabella ha una chiave primaria costituita da piu' campi della tabella

A
questo punto il nostro DATABASE DBREGALI si
presenta in questo modo

A
questo punto possiamo abbandonare MySQL Administrator.
2) CREAZIONE DELLA CONNESSIONE ODBC
Dopo
aver installato il driver ODBC della Actual Technologies, LLC che mi ha
gentilmente concesso una licenza trial di 15 giorni da allegare al mio tutorial
(la versione demo normale è limitata alla gestione di TRE soli record) dalla
cartella applicazioni scegliamo

e mandiamo in esecuzione iODBC Administrator.
Compare

premiamo
il pulsante Add (Il tab selezionato e' User DNS) la differenza tra User DNS e
System DNS è che nel primo caso la connessione ODBC che stiamo creando
esistera' solo per l'utente loggiato, nel secondo sara' sempre visibile
indipendentemente dall'utente che ha effettuato il Login in Mac OS X.
Selezioniamo
il nostro driver ODBC per MYSQL server e premiamo FINISH.

Compare
il wizard per la configurazione della connessione ODBC

Premiamo LICENSES e
indicamo il codice di licenza valido per 15 giorni, gentilmente concesso dal
Sig. Jonathan Monroe della Actual Technologies, LLC
Il Sig. Monroe si è
raccomandato di NON PUBBLICARE su WEB tramite HTML il license key per il trial
di 15 giorni, mi raccomando, mi fido di voi e non facciamoci brutte figure, in
fondo è solo una licenza trial e la versione full del driver ODBC costa molto
poco.
Il sito è
www.actualtechnologies.com da cui reperire ulteriori informazioni o inviare
commenti sui loro prodotti e magari su questo tutorial.
Una
volta inserito il numero di Licenza, premiamo CONTINUE

a
questo punto dobbiamo decidere un nome alla nostra connessione ODBC.
Nel
nostro esempio, decidiamo di chiamarla DBREGALI2005

e
premiamo CONTINUE
Selezioniamo
MySQL e la porta di comunicazione con il server MySQL di default e' la 3306
quindi premiamo CONTINUE

Indicamo
il nome del DATABASE che abbiamo precedentemente creato
(DBREGALI)
e premiamo CONTINUE

Appare
una finestra di riepilogo della connessione ODBC appena creata

PREMIAMO
TEST per verificare se tutto è OK

Premiamo
OK
Ed se
tutto è stato fatto correttamente

A
questo punto possiamo chiudere l'odbc manager e iniziare la parte di
programmazione in Cocoa con XCODE.
Questa
è la videata relativa alla connessione ODBC appena creata.

Per
eventuali modifiche o nuove connessioni ODBC utilizzare iODBC Administrator.
INIZIAMO LA PROGRAMMAZIONE IN COCOA

Impostiamo,
tramite le preferenze, i percorsi dove dovranno risiedere i files generati
durante la compilazione ed il link del programma.
Creiamo
quindi una cartella TUTORIAL (MAC HD) e dentro TUTORIAL creaiamo la cartella
APPL (dove risiederà l'applicazione) e TEMP (files e cartelle temporanee) come
sotto indicato

Impostiamo
i percorsi corretti in Xcode

Creiamo
ora il nuovo progetto, da Xcode, Menu File e New Project ...

compare
l'elenco dei possibili "modelli" di progetto e selezioniamo Cocoa
Applcation
quindi
indichiamo il nome dell'applicazione GestioneRegali e selezioniamo la directory
nella quale creare i files del progetto (TUTORIAL\APPL)

premiamo
FINISH

Compaiono
i files e i frameworks (le librerie) che il progetto ha creato in automatico.
Premere
per cambiare il modo di visualizzazione, in
modo da poter vedere il contenuto del file che si seleziona sulla tree view di
sinistra.

IMPOSTIAMO
l'ambiente di sviluppo per produrre il codice relativo alla versione di MAC OS
X su cui stiamo lavorando, selezioniamo GestioneRegali nel tree view e click di
destro per visualizzare menu contestuale

Quindi
da Get Info,
IMPOSTARE
CURRENT MAC OS (VERIFICATE ANCHE I PERCORSI DI
DESTINAZIONE DEI FILES PRODOTTI DA XCODE)
Chiudiamo
la finestra di dialogo e proviamo a compilare ed eseguire il programma.

Effettuiamo
la compilazione e vediamo se tutto funziona
Deve
comparie la finestra dell’applicazione come di seguito riportato.

Ok,
funziona.
Dato
che la nostra applicazione deve comunicare con un database, tramite ODBC, ci
servono dei frameworks per gestire la connessione odbc
Tali
frameworks sono situati nella cartella Library/Frameworks

Quindi
la prima cosa da fare è includere nel notro progetto di cocoa il framework
iODBC
Per
fare questa operazione

quindi
selezionare il percorso dove si trova il framework in questione
(iODBC.framework)
e
premere ADD.
Ora la
tree view appare cosi'

IMPORTANTE
Per
poter usare agevolmente la connessione odbc e le funzioni fornite dal framework
ho realizzato alcune classi che incapsulano le chiamate API (Application
Program Inteface in C) con degli oggetti Cocoa e di conseguenza utilizzano
Objective-C.
Tali
classi le ho incluse nel progetto e possono essere usare ed implementate
liberamente.
I files
relativi alle mie classi sono stati copiati in un folder che ho nominato FGODBC e che contiene i seguenti files

Quindi ora dobbiamo includere questi files
nel nostro progetto

selezionare
la cartella TUTORIAL/FGODBC e selezionare tutti i files
quindi
premere ADD.
La tree
view adesso risulta essere cosi' composta

Proviamo
nuovamente a compilare ed eseguire il codice, tutto dovrebbe funzionare
correttamente. (compare la solita finestra vuota...)
CREAZIONE DELLA CLASSE DELEGATO PER L'APPLICAZIONE
La
connessione ODBC verso il database, sara' aperta una sola volta dopo aver
lanciato il programma e sara' chiusa quando l'applicazione sara' chiusa.
Quindi
la posizione migliore dove aprire e chiudere la connessione ODBC e' nella
classe applicazione, intercettando i messaggi
PER
L'APERTURA DELLA CONNESSIONE ODBC
-
(void)applicationDidFinishLaunching:(NSNotification *)aNotification
PER LA
CHIUSURA DELLA CONNESSIONE ODBC
-
(void)applicationWillTerminate:(NSNotification *)aNotification
Per
poter intercettare tali messaggi, dobbiamo creare una nostra classe che
dichiareremo essere una classe delegata della nostra applicazione.
1) -
Apriamo il file MainMenu.NIB (file delle risorse)
![]()
e con
doppio clic lanciamo Inteface Bulder (IB)
individuiamo
la finestra

e
selezionamo sul Tab CLASSES, quindi NSObject e con un clic di destro selezionamo
Subclass NSObject

compare
![]()
e
cambiamo il nome in gstregaliapp

a
questo punto dobbiamo creare un istanza della classe appena definita
quindi,
la evidenziamo e dal menu contestuale (clic di destro) selezioniamo
instantiate
gstregaliapp.

Rifacciamo
la selezione e questa volta scegliamo Creare Files for gstregaliapp.
![]()
Compare

e
scegliamo il pulsante CHOOSE
A
questo punto, selezioniamo il TAB INSTANCES e troviamo questa nuova situazione

In
pratica adesso esiste un oggetto gstregaliapp, creato dinamicamente dal NIB in
base alle informazioni della nostra classe gstregaliapp.h / gstregaliapp.m che
abbiamo creato e che ci troveremo nel nostro progetto, nella tree view insieme
agli files.
Non
rimane che impostare il nostro nuovo oggetto gstregaliapp come DELEGATO della
nostra applicazione, in questo modo, da codice potremo intercettare e gestire i
messaggi di inizio e fine applicazione, per poter aprire e chiudere la
connessione ODBC.
Per
fare questa operazione, premiamo CTRL e mantenendolo premuto selezioniamo il
nostro oggetto gstregaliapp

Compare
una finestra, e selezioniamo DELEGATE e premiamo il pulsante CONNECT.
Alla
fine otterremo la seguente situazione

Notare
il "pallino" vicino alla voce "outlets" delegate, che
indica che è presente una connessione tra oggetti.
Ciccandoci
sopra, viene evidenziata tale connessione

a
questo punto possiamo chiudere Interface Builder, salvando le modifiche.
Ritornando
sul progetto in XCODE, ora troveremo due nuovi files
![]()
che
rappresentano la definizione del nostro nuovo oggetto appena creato.
Non ci
resta che andare ad intercettare i metodi di cui abbiamo parlato prima per
aprire e chiudere la connessione ODBC.
La
prima cosa da fare è aggiungere nel file gstregaliapp.h un oggetto che gestira'
la connessione odbc, tale oggetto è FGODBCConnection.

e

Dopo di
che' passiamo alla intercettazione dei messaggi nel file gstregaliapp.m

//Applicazione
è stata lanciata
-
(void)applicationDidFinishLaunching:(NSNotification *)aNotification{
//Open
ODBC Connection
m_DB=[[FGODBCConnection alloc]init];
[m_DB
Open:@"DSN=DBREGALI2005;UID=root;PWD="]; //DBREGALI2005 is the
ODBC connection name previous create
with iODBC
}
![]()

//Prima
di chiudere l'applicazione
- (void)applicationWillTerminate:(NSNotification
*)aNotification{
[m_DB Close];
//Close the ODBC connection
[m_DB release]; //Release memory of
}
Salviamo,
compiliamo e mandiamo in esecuzione, se diamo uno sguardo al Run Log, questa
volta vediamo dei nuovi messaggi

Quando
l'applicazione parte, apre la connessione ODBC, e la connessione viene
correttamente aperta infatti vediamo comparire la versione del Driver ODBC, e
la scritta Ok, connected ... quando si effettua mela-q per chiudere
l'applicazione compare il messaggio di chiusura della connessione ODBC.
Se per
esempio, cambiamo il nome della connessione es (DBREG) e mandiamo in esecuzione
otterremo invece un errore

il log
segnalera’

bene,
rimettiamo a posto il nome della connessione ODBC e proseguiamo.

Ora
dobbiamo agganciare gli oggetti che rappresentano le nostre tabelle del
database, tali oggetti sono nuovamente delle classi mie in cocoa e
specificatamente si tratta di FGODBCRecord
Che
incapsula le funzionalita' dei singoli record.
Anche
in questo caso, esiste un oggetto legato ad ogni tabella e valido per tutta
l'applicazione, di conseguenza li creo e li distruggo negli stessi metodi
appena visti della nostra classe gstregaliapp.
Quindi
avremo
/*
gstregaliapp */
#import
<Cocoa/Cocoa.h>
#import
"FGODBCConnection.h"
#import
"FGODBCRecord.h"
@interface
gstregaliapp : NSObject
{
FGODBCConnection *m_DB; //ODBC Connection to the DataBase
FGODBCRecord *pTabPersone; //DB Table PERSONE
FGODBCRecord *pTabRegali; //DB Table REGALI
FGODBCRecord *pTabRicorrenze; //DB Table RICORRENZE
FGODBCRecord *pTabStoricoRegali; //DB Table STORICOREGALI
}
@end

Nell'implementazione
della classe gstregaliapp.m
La
creazione degli oggetti con i rispettivi nomi delle tabelle del database nella
fase di lancio dell'applicazione e chiusura/distruzione degli oggetti nella
fase di chiusura applicazione
Il
codice diventa quindi
#import
"gstregaliapp.h"
@implementation
gstregaliapp
//Applicazione
è stata lanciata
-
(void)applicationDidFinishLaunching:(NSNotification *)aNotification{
NSLog(@"Try to open ODBC
connection");
//Open
ODBC Connection
m_DB=[[FGODBCConnection alloc]init];
//[m_DB
Open:@"DSN=DBREG;UID=root;PWD="]; ERROR!!! //DBREGALI2005 is the ODBC
connection name previous create with iODBC
[m_DB
Open:@"DSN=DBREGALI2005;UID=root;PWD="]; //DBREGALI2005 is the ODBC
connection name previous create with iODBC
//Create record Object for manage table
data
pTabPersone=[[FGODBCRecord alloc] initWithDataBase:m_DB
forSQLTable:@"PERSONE"];
pTabRegali=[[FGODBCRecord alloc]
initWithDataBase:m_DB forSQLTable:@"REGALI"];
pTabRicorrenze=[[FGODBCRecord alloc]
initWithDataBase:m_DB forSQLTable:@"RICORRENZE"];
pTabStoricoRegali=[[FGODBCRecord alloc]
initWithDataBase:m_DB forSQLTable:@"STORICOREGALI"];
}
//Prima
di chiudere l'applicazione
-
(void)applicationWillTerminate:(NSNotification *)aNotification{
//Close recordset and release memory object
[pTabPersone CloseCursor];
[pTabPersone release];
[pTabRegali CloseCursor];
[pTabRegali release];
[pTabRicorrenze CloseCursor];
[pTabRicorrenze release];
[pTabStoricoRegali CloseCursor];
[pTabStoricoRegali release];
NSLog(@"Try to close ODBC
connection");
[m_DB Close];
//Close the ODBC connection
[m_DB release]; //Release memory of
}
@end

CREAZIONE
DELL'INTERFACCIA UTENTE
Per
prima cosa andiamo a personalizzare un po’ la nostra applicazione, quindi
cambiamo indichiamo l’autore, inseriamo un icona e modifichiamo il menu.
a)
Informazioni
su autore e versione
![]()

![]()
Nota:
Il bundle signature va richiesto alla Apple tramite web/registrazione.


2)
Inseriamo l’icona Nella cartella

si trova il file tutorial.icns (per creare
le icone, usare il tool icon composer)

Per
inserire l’icona alla nostra applicazione


selezionare
il file dell’icona, quindi premere Add.
Nella
tree view ora compare

Selezioniamo
nuovamente info.plist e modifichiamo CFBundleIconFile

Compiliamo
ed eseguiamo… NOTA: Fare prima un

per
forzare Xcode a riconsiderare tutto il progetto…
Otteniamo
la nostra icona e credit …


3)
Modifichiamo il menu

Doppio
click su MainMenu.nib, viene attivato IB

doppio
click è appare il nostro menu dell’applicazione

Bene, ora
non ci rimane che sostituire a NewApplication, il nome della nostra
applicazione, doppio click sul nome …
![]()

ecco il
menu alla fine

Poi
tolgo le voci che non interessano negli altri sottomenu e tolgo il menu Help.

Visto
che siamo nei menu, facciamo anche che aggiungere i notri menu
Menu
Tabelle di Base
Menu
Gestione
Per
aggiungere dei menu dalla Palette dei componenti selezioniamo Cocoa-Menus

Quindi,
cliccliamo su SubMenu e lo trasciniamo sul menu dell’applicazione

Ora
cambiamo il nome agli elementi del menu e aggiungeremo i sottomenu

Per
aggiungere delle voci al menu, selezionare ITEM e trascinare sul menu

Cambiamo
nome, e ripetiamo l’operazione per le varie voci.
Alla
fine decido di denominare le voci del menu Tabelle di Base cosi

Aggiungiamo
ora il menu Gestione ed i relativi sottomenu

Bene,
salviamo da IB e chiudiamo.
Compiliamo
in XCode e controlliamo se tutto è come piace a noi…
CREAZIONE DELLA FINESTRA PER LA GESTIONE DELL’ANAGRAFICA DELLE PERSONE
Apriamo
MainMenu.nib e siamo in Interface Builder.
Scelgo
di usare del Panel per gestire le anagrafiche.

Scelgo
Panel e lo trascino dentro questa finestra, compare Panel …

Cambio
il nome, in modo da rendere piu’ leggibile il tutto in PersonePanel

Ed ora,
disegnamo la nostra videata per l’anagrafica delle Persone
Mi
predispongo l’ambiente di lavoro

Cambio
qualche impostazione …

E
inizio a mettere gli oggetti per gestire la nostra anagrafica.
Ricordiamoci
che i dati da gestire sono
Definizione
tabella: PERSONE
Nome campo
Tipo Dimensione Chiave Null Descrizione
ID_PERSONA
Char 25 Yes
No
DESCR
char 60 No
Yes
BUDGET
float 8 No
Yes
ETA
int 4 NO
Yes
HOBBY
char 30 No
Yes
SPORT
char 30 No
Yes
SINGLE
char 1 No
Yes
NATOIL
char 8 No
Yes (aaaammgg)
Quindi
Creo i
vari oggetti, ed ecco la nostra videata per la gestione della tabella Persone

Ovviamente
se non vi piace, potete cambiare quello che vi pare…
Prima
di procedere con l’integrazione della videata con la relativa tabella, dobbiamo
sbrigare un po’ di altro lavoro per rendere visibile la videata dal menu
applicazione.
Per
fare questo, io creo un nuovo oggetto, che chiamo windowController che si
occupera’ di gestire la finestra principale (che al momento è semplicemente
vuota, e di altre attività, tra cui quella di gestire i comani del menu per
aprire i pannelli di interfaccia che man mano creeremo.
Per
creare questo oggetto, da IB scelgo



![]()
a
questo punto ci troviamo questi oggetti

Questo
oggetto windowController, lo faccio diventare DELEGATO per l’oggetto Window,
ciccando premendo CTRL e selezionando Window

e poi
Delegate, Connect

Ora
dobbiamo creare dei collegamenti (ACTION) per collegare l’azione del menu
Tabelle di base, Persone con questo oggetto, in modo che, successivamente, da CODICE
possiamo far aprire il panello relativo ai dati anagrafici delle Persone.
Quindi
l’oggetto windowController
È il
delegato dell’oggetto Window (finestra principale dell’applicazione
Avrà il
collegamento (ACTION) da collegare all’azione del menu
Dovrà
conoscere l’oggetto PersonePanel per poterci interagire, per far conoscere
questo oggetto occorre creare un OUTLET.
Creaimo
il collegamento per L’action del menu Tabelle di base, persone
DOPPIO
CLICK SU

Compare

Come
visibile, al momento il nostro oggetto non ha nessun collegamento con altri
oggetti (ACTION) e non conosce nessun altro oggetto (OUTLET).
Creiamo
un azione, (=METODO) che dovrò essere successivamente collegata al menu, in
modo che quando si sceglierà il menu, sarà eseguita questa azione.
Premo
ADD

e
cambio il nome, lo chiamo gstTabellaPersone

Ora
seleziono outlets, e premo ADD

e lo
chiamo personaPanel, inoltre cambio il tipo e lo metto di tipo NSPanel, in
quanto è il tipo di oggetto che ho usato quando l’ho creato.

quindi
alla fine ho

Bene
ora non rimane che collegali agli altri oggetti
Colleghiamo
il Menu Tabelle di base, Persone
Mi
precaro l’ambiente

quindi
CTRL e click sulla voce Persone del menu e clicco sull’oggetto
windowController, seleziono l’unica Action disponibile (gstTabellaPersone) e
premo Connect

Comparirà
il solito “pallino” della connessione…

Ora
presentiamo l’oggetto personePanel all’oggetto windowController
CTRL
click sull’oggetto windowController e click su oggetto personePanel

Compare

Seleziono
l’unica outlets presente (quella che abbiamo creato in precedenza) e premo
Connect.
Otteniamo

Ora non
ci rimane che far creare a IB i files .h e .m che rappresentano il nostro nuovo
oggetto windowController, in modo da poter andare ad implementare il codice per
visualizzare il pannello della gestione tabella persone.

premo
CHOOSE, ora salviamo tutto da IB e usciamo.
In
XCODE, ora troviamo due nuovi amici …

windowContoller.h
e windowController.m


Per
visualizzare il nostro pannello, decido di usare beginSheet,
quindi
inserisco nella chiamata del metodo gstTabellaPersone il codice per
visualizzare una sheet.
[NSApp beginSheet:personaPanel modalForWindow:[NSApp mainWindow]
modalDelegate:self didEndSelector:@selector(sheetDidEnd: returnCode: contextInfo:) contextInfo:NULL];
Compiliamo
ed eseguiamo …

Ora
tabella di base,persone è ATTIVO, clicchiamo ed ecco il nostro Panel che
fuoriesce dall’alto della finestra principale della applicazione.

Ora
abbiamo un piccolo problemino da affrontare, COME LA CHIUDIAMO ?
In
effetti io ho messo il pulsante ESCI, ma ovviamente non fa nulla, non lo
abbiamo collegato a nessuna azione.
Terminiamo
l’applicazione con 
E
andiamo a risolvere questo problema.
Per
prima cosa creiamo manualmente (ormai non possiamo piu’ farlo da IB, una nuova
azione per il nostro oggetto winodwController)
-
(IBAction)chiudeSheet:(id)sender; //Action for close the panel
ed
implementiamo il codice relativo
- (IBAction)chiudeSheet:(id)sender{
//Chiudo la finestra
[personaPanel orderOut:nil];
[NSApp endSheet:personaPanel];
}
bene,
ora devo andare in IB e collegare il pulsante ESCI con questa azione creata in
windowController.
Lancio
IB, quindi vado ad aggiungere l’ACTION all’oggetto windowController

Ora
faccio il collegamento, mi predispongo l’ambiente

CTRL
click sul pulsante ESCI (sul controllo SEGMENTED…) e trascino sino a
windowController compare

Scelgo
chiudiSheet (questa volta ho gia’ due azioni implementate nella oggetto windowController)
![]()
e
Connect, ottengo

Ora
salviamo e chiudiamo IB.
NOTA:
Il pulsante ESCI ha TAG 4 come visibile da Attibutes

Questa
informazione ci servira’ tra un po’…
Da
XCODE, compiliamo ed eseguiamo il programma, proviamo ad aprire e chiudere, ora
funziona, ma la finestra viene chiusa indipendentemente se premo Esci, Registra
ecc
Quindi
devo solo controllare che sia il pulsante ESCI a chiamare il metodo per poter
procedere alla chiusura dello sheet
int
nOperationToDo=0;
nOperationToDo=[sender selectedSegment];
if(nOperationToDo
== 4){
[personaPanel orderOut:nil];
[NSApp endSheet:personaPanel];
}
Dato
che abbiamo creato l’oggetto panelPersone per gestire i dati della tabella
persone, ora conviene creare un oggetto che sia in grado di interagire con il
database e con la tabella persone e l’oggetto di interfaccia grafica per
presentare i dati all’utente e per consentirne la modifica.
Chiameremo
tale nuovo oggetto panelPersoneController.
Per
crearlo, attiviamo IB con un doppio click su MainMenu.nib
Quindi
Tab CLASSES, e subclass della classe NSObject

quindi
creaimo l’istanza (creazione dell’oggetto in memoria)
![]()
Quindi
ora la situazione relativa agli oggetti presenti nel NIB è questa

Ora creiamo
tanti OUTLETS quanti sono i controlli con cui vogliamo interagire tramite
codice nella classe, (ossia dobbiamo creare i collegamenti per poter presentare
all’oggetto panelPersoneController i vari controlli (che sono a loro volta
degli oggetti…) dell’oggetto PersonePanel.
Doppio
click sull’oggetto panelPersoneController e creaiamo i vari OUTLETS come di
seguito riportato.
Notare
che è stato selezionato il Tipo corretto, per ciascun OutLets creato.
Infatti
corrisponde un outlet ad ogni controllo della finestra PersonePanel,
successivamente
provvederemo a collegare ciascuno di questi controlli con l’equivalente OutLet
che abbiamo creato.

Per
terminare l’implementazione della nostra nuova classe, aggiungiamo anche delle
ACTIONS (metodi) a cui la classe dovrà rispondere.
Un
metodo dovrà rispondere alla pressione del tasto Modifica, un altro dovrà
rispondere e, internamente, gestire il diverso tasto premuto dalla barra dei
pulsanti (segmented control) Registra,Cancella,Elimina Tutto,Stampa ed Esci.
Procediamo
quindi con la creazione di queste due ACTIONS che chiameremo rispettivamente

Non ci
rimane che effettuare i vari collegamenti tra i vari oggetti
Pulsante
Modifica lo colleghiamo con btnModificaPremuto


e premo
CONNECT (ATTENZIONE: Verificare di aver selezionato Outlets dalla combobox,
quindi target)
barra
delle azioni lo colleghiamo con btnBarraAzionePremuto

Ora si
presenta un problemino, noi abbiamo già una connessione attiva per la nostra
barra (ci era servita per collegare la barra azione con la classe
windowController chiudeSheet) quindi dobbiamo cambiare il collegament, ossia
prima lo SCOLLEGHIAMO (DISCONNECT) e po lo ricolleghiamo alla nostra nuova
azione.
Questo
significa anche, che il codice presente in windowController per la gestione del
metodo chiudeSheet dovra’ essere eliminato, e la gestione della chiusura dello
sheet sarà fatta nella classe panelPersoneController.
1)
Disconnessione

2)
Connessione

Colleghiamo ora tutti gli altri elementi (questa volta sono degli
OUTLETS, ossia dei collegamenti per far conoscere all’oggetto
panelPersoneController i vari controlli utente presenti nell’oggetto
PersonePanel).
Per collegare gli outels, CTRL Click sull’oggetto
panelPersoneController e poi click sull’elemento da collegare, selezionare il
corretto Outlet da abbinare e ripetere il procedimento sino a quando non
abbiamo abbinato tutti gli oggetti al loro relativo outlet.

Ecco come si presenta la situazione dopo
aver fatto tutti i collegamenti.

Uhm… mi sono dimenticato di presentare all’oggetto
panelPersoneController l’oggetto delegato dell’applicazione, ci serve fare cio’
in quanto l’oggetto delegato dell’applicazione gstregaliapp ha al suo interno
l’oggetto della connessione ODBC e i vari oggetti che rappresentano le tabelle
del database.
Quindi provvediamo subito a creare un nuovo OutLet, che chiamiamo
theApp di tipo gstregaliapp.

ed ora colleghiamolo

A questo punto, possiamo far generare i files .h e .m ad IB
relativi al nostro nuovo oggetto

e premiamo CHOOSE.
Salviamo e chiudiamo IB, ora in XCODE ci troviamo anche i nuovi
files

per prima cosa sistemiamo la chiusura dello sheet, quindi
prendiamo il codice che e nella classe windowController e lo spostiamo in
panelPersoneController.
Elimino
-
(IBAction)chiudeSheet:(id)sender; //Action for close the panel
e sposto implementazione nella nuova classe,
nel metodo
- (IBAction)btnBarraAzionePremuto:(id)sender
{
//Chiudo la finestra
int
nOperationToDo=0;
nOperationToDo=[sender selectedSegment]; //Get
the Button That is selected on the segment
if(nOperationToDo
== kBtnEsci){ //If
ESCI close sheet
[personaPanel
orderOut:nil]; //Close the panel
[NSApp endSheet:personaPanel ]; //End the sheet loop
}
}
Salviamo, compiliamo e mandiamo in esecuzione…
Ma c’e’ un errore di compilazione

Doppio click sul primo messaggio e vediamo di capire il problema,
uhm il compilatore non conosce la definizione della classe
gstregaliapp che noi abbiamo usato in IB per creare l’outlet theApp.
Semplice, mettiamo #import <gstregaliapp.h>
Il secondo messaggio di errore è invece dovuto alla variabile
personaPanel che non è riconosciuta come variabile della classe, per forza, non
esiste, e’ colpa del copia/incolla della metodo per la chiusura dello sheet.
La variabile che identifica lo sheet si chiama … non abbiamo
creato l’outlet per far conoscere alla classe panelPersoneController l’oggetto Panel che rappresenta
il nostro sheet.
Possiamo pero’ ricavare tale oggetto in quanto nel metodo - (IBAction)btnBarraAzionePremuto:(id)sender
viene passato l’ID del sender ossia dell’oggetto che ha chiamato il
metodo, in questo caso la barra azioni, ma la barra azioni è FIGLIA della
FINESTRA PANEL, quindi se invochiamo il metodo window sull’oggetto sender,
ricaviamo l’oggetto Panel.
id aPanel=[sender window];
if(nOperationToDo
== 4){
//If ESCI close sheet
[aPanel
orderOut:nil]; //Close the panel
[NSApp
endSheet:aPanel ]; //End
the sheet loop
}
Compiliamo ed eseguiamo.
Ecco come si presentano i files dell’oggetto
panelPersoneController


INTERFACCIAMO LA TABELLA PERSONE
Ora ci occupiamo di intercettare la pressione del Pulsante modifica,
e di conseguenza
-
controlliamo
che il campo IDPersona non sia vuoto
-
che
la lunghezza non superi 25 caratteri
-
controlliamo
se esiste gia’ il record con la chiave indicata, ricordo che la chiave per la
tabella Persona è ID_PERSONA di 25 caratteri.
Se esiste visualizziamo I dati presenti nel record nei vari campi
della videata, se non esiste I campi saranno inizializzati a blank.
Questo è il messaggio di errore che compare se premo Modifica
senza aver indicato nulla nel campo ID PERSONA

e questo è il codice che ho implementato per effettuare il
controllo e visualizzare le finestra di errore
- (IBAction)btnModificaPremuto:(id)sender
{
//1: Check if key field is valid
NSString *aString=[[idPersona stringValue]
TrimRight]; //Eliminate right blanks
if([aString isEqualToString:@""]){
NSRunAlertPanelRelativeToWindow(@"ERRORE",@"E'
Indispensabile indicare un identificativo della persona!",@"OK",nil,nil,[sender
window]);
}
}
Controlliamo ora la lunghezza (max 25)…
if([aString
length] >25){
NSRunAlertPanelRelativeToWindow(@"ERRORE",@"L'identificativo
non puo' essere superiore a 25 caratteri!",@"OK",nil,nil,[sender
window]);
}
E proviamo se funziona, inseriamo piu’ di 25 caratteri e premiamo
Modifica

Procediamo ora con il controllare se esiste gia’ il record
indicato.
Per fare questo controllo, usando l’istruzione SQL dovremmo
scrivere
SELECT * FROM PERSONE WHERE ID_PERSONA=’FRANCO’
Nel nostro caso, usiamo un metodo della classe FGODBCRecord ed in
particolare usiamo LoadDati. Tale metodo ha un solo parametro in input che è la
parte della clausola dell’istruzione SQL (WHERE … ) e restituisce TRUE se è
stato trovato un record che soddisfa il criterio di selezione.
Il pratica, quando abbiamo creato l’oggetto pTabPersone gli abbiamo già detto come si
chiamava la tabella “PERSONE” quindi la classe FGODBCRecord, costruirà in modo
automatico l’istruzione completa SQL.
NSMutableString *strQuery;
strQuery=[NSMutableString
stringWithFormat:@"WHERE ID_PERSONA='%@' ",aString];
//Build the query
if([theApp->pTabPersone
LoadDati:strQuery] == TRUE){
NSLog(@"Found: %@ in table
PERSONE",aString);
}else{
NSLog(@"Not Found: %@ in
table PERSONE",aString);
}
Come si vede dal codice, accediamo alla tabella che è un membro
della classe gstregaliapp (variabile che abbiamo ora chiamato theApp).
Quindi per accedere ad una tabella sarà sufficiente indicare
theApp->pTabPersone
theApp->pTabRegali
theApp->pTabRicorrenze
theApp->pTabStoricoRegali
per eseguire un metodo della classe es. LoadDati
BOOL bFound=[theApp->pTabPersone
LoadDati:clausolaWhereComeStringa];
Quindi il nostro metodo della classe panelPersoneController
diventa
- (IBAction)btnModificaPremuto:(id)sender
{
//1: Check if key field
is valid
NSString
*aString=[[idPersona stringValue] TrimRight]; //Eliminate right
blanks
if([aString
isEqualToString:@""]){
NSRunAlertPanelRelativeToWindow(@"ERRORE",@"E'
Indispensabile indicare un identificativo della persona!",@"OK",nil,nil,[sender
window]);
}
if([aString
length] >25){
NSRunAlertPanelRelativeToWindow(@"ERRORE",@"L'identificativo
non puo' essere superiore a 25 caratteri!",@"OK",nil,nil,[sender
window]);
}
//2: Check if record
already present
NSMutableString *strQuery;
strQuery=[NSMutableString
stringWithFormat:@"WHERE ID_PERSONA='%@' ",aString];
//Build the query
if([theApp->pTabPersone
LoadDati:strQuery] == TRUE){
NSLog(@"Found: %@ in table
PERSONE",aString);
}else{
NSLog(@"Not Found: %@ in
table PERSONE",aString);
}
}
Compiliamo ed eseguiamo … ma otteniamo questo errore
![]()
Ok, semplicemente dobbiamo dichiarare PUBLIC (accessibili da
tutti) i membri della nostra classe gstregaliapp.
Scriviamo la correzione, (@public)
/* gstregaliapp */
#import
<Cocoa/Cocoa.h>
#import
"FGODBCConnection.h"
#import
"FGODBCRecord.h"
@interface
gstregaliapp : NSObject
{
FGODBCConnection *m_DB; //ODBC Connection to the
DataBase
@public
FGODBCRecord *pTabPersone; //DB Table PERSONE
FGODBCRecord *pTabRegali; //DB Table REGALI
FGODBCRecord *pTabRicorrenze; //DB Table RICORRENZE
FGODBCRecord *pTabStoricoRegali; //DB Table STORICOREGALI
}
@end
Compiliamo e eseguiamo il codice, proviamo a scrivere FRANCO nel
campo ID PERSONA e premiamo MODIFICA, nel file di LOG troveremo


NON ESISTE NESSUN RECORD CON IDENTIFICATIVO_PERSONA (ID_PERSONA)
uguale a FRANCO nella Tabella PERSONE.
Per controllare se realmente funziona, passiamo subito alla
realizzazione della funzione di IMMISSIONE/VARIAZIONE dati.
Per fare questo, andiamo a modificare - (IBAction)btnBarraAzionePremuto
In quanto è il metodo che viene richiamato quando si preme il
pulsante Registra dalla barra azioni.
Il pulsante Registra ha TAG = 0 quindi per capire se è stato
premuto registra controlliamo se nOperationToDo = 0
Se è stato premuto Registra, chiamiamo il metodo updateRecord che
apparterra’ alla nostra stessa classe panelPersoneController, quindi useremo
[self updateRecord]; per chiamare tale metodo all’interno della classe.
Quindi modifichiamo il file .h per specificare la definizione del
nuovo metodo
-(void)updateRecord; //Update Record
e modifichiamo il file .m per implementare il codice che consenta
di effettuare la registrazione sulla tabella del database.
//Update Record
-(void)updateRecord{
NSMutableString *strQuery;
NSString
*aString=[[idPersona stringValue] TrimRight]; //Eliminate right
blanks
strQuery=[NSMutableString
stringWithFormat:@"WHERE ID_PERSONA='%@' ",aString];
//Build the query
BOOL
sts=[theApp->pTabPersone LoadDati:strQuery]; //New Insert or
Update ?
//Assign new data value
for the record
[[theApp->pTabPersone
FieldInfo:@"ID_PERSONA"] SetValue:aString];
[[theApp->pTabPersone
FieldInfo:@"DESCR"] SetValue:[descrizione
stringValue]];
[[theApp->pTabPersone
FieldInfo:@"ETA"] SetValue:[eta stringValue]]; //Int
[[theApp->pTabPersone
FieldInfo:@"HOBBY"] SetValue:[hobby
stringValue]];
[[theApp->pTabPersone
FieldInfo:@"SPORT"] SetValue:[sport
stringValue]];
if([flgSingle
state]==TRUE)
[[theApp->pTabPersone FieldInfo:@"SINGLE"]
SetValue:@"1"];
else
[[theApp->pTabPersone FieldInfo:@"SINGLE"]
SetValue:@"0"];
[[theApp->pTabPersone
FieldInfo:@"NATOIL"] SetValue:[[dataNascita
dateValue] descriptionWithCalendarFormat:@"%Y%m%d"
timeZone:nil locale:nil]];
//data YYYYMMDD
[[theApp->pTabPersone
FieldInfo:@"BUDGET"] SetValue:[budget
stringValue]]; //real
//If not exist make a
INSERT else a UPDATE
if(sts==FALSE)
[theApp->pTabPersone Insert];
else
[theApp->pTabPersone Update:strQuery];
}
la prima parte, effettua nuovamente la query per verificare se
esiste già un record con la chiave indicata, dopo di che vengono assegnati i
valori letti dai vari campi presenti sulla videata alle rispettive COLONNE
(campi) della tabella PERSONE.
Il metodo FieldInfo della classe FGODBCRecord, mi restituisce un oggetto di tipo FGODBCFieldInfo relativo al valore della colonna
del record che sto esaminando, quindi con il metodo SetValue imposto il nuovo
valore al campo.
Dopo aver modificato tutti i valori dei singoli campi del record
procedo con un operazione di Insert o di Update sulla tabelle del database.
Chiamando rispettivamente i metodi Insert e Update della classe
FGODBCRecord.
Proviamo se tutto funziona regolarmente,compilo ed eseguo
Immetto FRANCO come ID PERSONA e premo MODIFICA, dal LOG vedo che
NON ESISTE UN RECORD FRANCO, quindi procedo compilando i dati dei altri campi e
quando ho terminato premo Registra.
Se ora ripreso MODIFICA, con il valore FRANCO ancora nel campo ID
PERSONA il LOG mi dice che esiste gia’ un record.

ed ecco il risultato del Log.

per
vedere se ho correttamente registrato i dati nel database, dato che non abbiamo
ancora implementato la visualizzazione, uso il tool MySql BROWSER


Indico
il nome del database DBREGALI (default schema) e CONNECT

Doppio
click su DBREGALi, quindi su PERSONE e premo EXECUTE (Esegue la query indicata
Select * from DBREGALI.PERSONE)
Ed ecco
il risultato

Ok, il record è stato correttamente inserito
Provo la variazione, lancio gestione regali, richiamo FRANCO e
MODIFICA, quindi cambio il BudGet e metto il mio nome e cognome in minuscolo.
Premo registra.
Ritorno su MySql browser ed premo nuovamente Execute
E questo è il risultato

Ok, anche la variazione funziona.
Chiudiamo MySql Browser e andiamo a creare la visualizzazione dei
record presenti nella tabella nella nostra applicazione.
VISUALIZZAZIONE ELENCO DEI RECORD
Per poter visualizzare dei dati all’interno della tableview che
abbiamo in precedenza posizionato nella videata PersonePanel, occorre definire
un DATASOURCE, ossia un oggetto che fornisca i dati alla tableview in modo che
la tableview possa visualizzarli.
Nel nostro caso, possiamo creare un oggetto di tipo
FGODBCResultSet e impostarlo come datasource per la tableview.
Per fare questo è necessario
Aggiungere una variabile per il nostro datasource nel file .h
FGODBCResultSet *dsPersone; //DataSource
PERSONE
E modificare il file .m aggiungendo il metodo awakeFromNib (che
viene chiamato in automatico quando l’inizializzazione del NIB si è conclusa) e
all’interno di questo metodo allochiamo l’oggetto datasource.
-(void)
awakeFromNib{
dsPersone=[[FGODBCResultSet alloc] init:theApp
SetIdentifier:@"PERSONE"
tableView:elencoPersone];
}
Al metodo init dell’oggetto FGODBCResultSet passiamo ID
dell’oggetto delegato dell’applicazione, il nome della TABELLA e ID
dell’oggetto tableview che vogliamo gestire
Ora non ci rimane che far popolare il datasource con i dati e di
dire alla tableview che dsPersone è il suo datasource. Per fare cio’ creo un
nuovo metodo startUseDataSource che dovrà essere chiamato dall’oggetto dopo che
la videata è stata presentata all’utente.
Per fare questo devo intercettare il messaggio
-
(void)windowDidBecomeKey:(NSNotification *)aNotification
e per intercettare tale messaggio devo dire tramite interface
builder che la classe panelPersoneController è anche la classe DELEGATA per il
Panel PersonePanel.
Apriamo IB con doppio click su MainMenu.NIB, quindi CTRL click
sull’oggetto PersonaPanel e tascinando click su oggetto personaPanelController,
seleziono DELEGATE e CONNECT.

Mentre siamo in IB sistemiamo
ancora una cosetta, ossia per poter funzionare il mio oggetto FGODBCResultSet
ha bisogno che l’IDENTIFIER della colonna della tableview si chiami esattamente
come si chiama il campo nella tabella del Database. Esempio La colonna Id
persona deve avere Identifier = ID_PERSONA
La colonna descrizione deve
avere Identifier DESCR ecc.
Doppio click
sull’intestazione della tabella

compare (se non compare
)

e faccio la stessa
operazione per tutte le altre colonne







Salvo le modifiche e chiudo
IB.
Creiamo i metodi per
popolare il datasource ed assegnarlo alla table view e richiamiamolo nel
messaggio windowDidBecomeKey (lo faccio solo una volta)
- (void)windowDidBecomeKey:(NSNotification
*)aNotification{
static
int bOnlyOnce=0;
if(!bOnlyOnce){
[self
startUseDataSource];
bOnlyOnce=1;
}
}
-(void)
startUseDataSource{
[elencoPersone setDataSource:nil];
//Forzo il riaggiornamento del datasource per la tableview
//Execute the query for
dataset result
[dsPersone FillArray:theApp->pTabPersone
SqlFilter:@"order by ID_PERSONA" ProgressInd:nil];
//Set datasource to
tableview
[elencoPersone setDataSource:dsPersone];
}
e nel file .h
-(void) startUseDataSource; //Start using internal datasource for
tableview
Compiliamo e mandiamo in
esecuzione, se tutto è OK quando selezioniamo tabelle di base e persone compare

Proviamo ad inseire un
nuovo record

dopo aver premuto registra,
il nuovo record non compare nell’elenco, questo è ovvio visto che abbiamo detto
di riempire il datasource solo quando la finestra viene aperta, infatti se
chiudo e riapro trovo il nuovo record.
Per riaggiornare l’elenco è
sufficiente aggiungere la chiamata al metodo startUseDataSource dopo l’update
del record
if(nOperationToDo ==