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 == 0){ //REGISTRA was pressed Insert/Modify the record

   [self updateRecord];

 

   [self startUseDataSource];    //refresh datasource

  }

 

 

Procediamo con la cancellazione

 

Creiamo un nuovo metodo nel file .h

-(void)deleteRecord; //Delete record

 

e lo implementiamo nel file .m

 

//Delete Record

-(void)deleteRecord{

NSMutableString *strQuery;

NSString *aString=[[idPersona stringValue] TrimRight]; //Eliminate right blanks

 

strQuery=[NSMutableString stringWithFormat:@"WHERE ID_PERSONA='%@' ",aString]; //Build the query

[theApp->pTabPersone Delete:strQuery];

}

 

Ovviamente dobbiamo aggiungere il codice per intercettare il tasto Cancella

 

if(nOperationToDo == 1){ //CANCELLA was pressed Delete the record

   [self deleteRecord];

 

   [self startUseDataSource];    //refresh datasource

  }

 

chiamiamo il metodo per cancellare il dato e faccio il refresh dell’elenco.

 

Per provare se funziona occorre indicare ID PERSONA da cancellare e premere Cancella, scompare dall’elenco.

 

Cancellazione Totale di tutti i record presenti

 

Creiamo il metodo nel file .h

-(void)deleteAllRecords; //Delete all records

e lo implementiamo nel seguente modo

 

//Delete all records

-(void)deleteAllRecords{

 [theApp->pTabPersone Delete:@""];

}

 

Infine modifichiamo il codice per intercettare il tasto Elimina tutto

 

if(nOperationToDo == 2){ //ELIMINA TUTTI was pressed Delete all records

   [self deleteAllRecords];

 

   [self startUseDataSource];    //refresh datasource

  }

 

STAMPA ELENCO

 

Semplicemente chiamiamo il metodo print dell’oggetto tableview, questo quando intercettiamo il tasto Stampa

 

if(nOperationToDo == 3){ //STAMPA was pressed Print all records

   [elencoPersone print:self];

  }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Giunti a questo punto, abbiamo fatto il lavoro piu’ grosso e praticamente abbiamo toccato tutti i punti per poter interfacciare MySql server.

 

Ora faremo solo delle operazioni per migliorare la gestione da parte dell’utente, esempio delle conferme sulla cancellazione dati, abilitare i campi sono dopo aver premuto modifca e sistemare la visualizzazione della data.

 

Infine faremo in modo che facendo un doppio click sulla riga della tablebview venga automaticamente selezionato il record pronto per la variazione dati.

 

 

Mettiamoci al lavoro, attiviamo la conferma sulla cancellazione dati

if(nOperationToDo == 1){ //CANCELLA was pressed Delete the record

    NSString *strInfo;

    strInfo=[NSString stringWithFormat:@"E' stato scelto di cancellare %@. Confermi ?",[[idPersona stringValue]TrimRight]];

    int rc=NSRunAlertPanel(@"Attenzione!",strInfo,@"SI",@"NO",nil);

    if(rc==NSOKButton){

     [self deleteRecord];

 

    [self startUseDataSource];    //refresh datasource

   }

  }

 

per la cancellazione singola

 

 

 

 

 

Mentre per la cancellazione totale,

if(nOperationToDo == 2){ //ELIMINA TUTTI was pressed Delete all records

  NSString *strInfo;

  strInfo=[NSString stringWithString:@"E' stato scelto di eliminare tutti i records. Confermi ?"];

  int rc=NSRunAlertPanel(@"Attenzione!",strInfo,@"SI",@"NO",nil);

  if(rc==NSOKButton){  

   [self deleteAllRecords];

 

   [self startUseDataSource];    //refresh datasource

   }

  }

 

 

 

ABILITIAMO I CAMPI SOLO DOPO AVER PREMUTO MODIFICA

 

Qui c’e’ un po’ di lavoro da fare, creo un metodo che abilita/disabilita tutti i campi di immissione utente tranne il campo chiave (o meglio, lavora nel modo opposto, inizialmente il campo ID PERSONA è attivo ed il pulsante Modifica anche) mentre tutti gli altri campi sono disabilitati, dopo aver premuto modifica, inverto la situazione).

 

//enable/disable control in user interface

-(void)setCtrlStat:(BOOL) bSts{

 

 [idPersona setEnabled:bSts];

 [budget setEnabled:!bSts];

 [descrizione setEnabled:!bSts];

 [dataNascita setEnabled:!bSts];

 [eta setEnabled:!bSts];

 [flgSingle setEnabled:!bSts];

 [sport setEnabled:!bSts];

 [hobby setEnabled:!bSts];

 [flgSingle setEnabled:!bSts];

}

 

Chiamo questo metodo in diverse parti del codice, impostando bSts a TRUE o FALSE a seconda delle esigenze.

 

-(void) awakeFromNib{

  dsPersone=[[FGODBCResultSet alloc] init:theApp SetIdentifier:@"PERSONE" tableView:elencoPersone];

 

  [self setCtrlStat:TRUE]; //enable/disable control in user interface

}

 

if(nOperationToDo == 0){ //REGISTRA was pressed Insert/Modify the record

   [self updateRecord];

 

   [self startUseDataSource];    //refresh datasource

  

   [self setCtrlStat:TRUE];

  }

 

- (IBAction)btnModificaPremuto:(id)sender

{

 

//1: Check if key field is valid

NSString *aString=[[idPersona stringValue] TrimRight]; //Eliminate right blanks

 

if([aString isEqualToString:@""]){

 NSRunAlertPanel(@"ERRORE",@"E' Indispensabile indicare un identificativo della persona!",@"OK",nil,nil);

}

 

if([aString length] >25){

 NSRunAlertPanel(@"ERRORE",@"L'identificativo non puo' essere superiore a 25 caratteri!",@"OK",nil,nil);

}

 

//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);

}

 

[self setCtrlStat:FALSE];

 

}

 

ecc.

 

Una particolare attenzione va posta per la barra dei pulsanti azione, in quanto sono se ho un valore valido nel campo Id Persona ed è stato premuto modifica, devo rendere disponibili i pulsanti Registra e Cancella. Quindi modifico setCtrlStat …

 

 [pulsantiAzione setEnabled:!bSts forSegment:0]; //Enable/Disable REGISTRA

 [pulsantiAzione setEnabled:!bSts forSegment:1]; //Enable/Disable CANCELLA

 

Per completare questa parte, mi serve un OutLet per il pulsante Modifica in modo da poterlo abilitare/disabilitare nella funzione setCtrlStat.

 

Ok, lo creo nella classe .h

IBOutlet NSButton *btnModifica;

modifico setCtrlStat, e poi creo l’outlet in IB e lo collego.

 

 

Modifico il codice in setCtrlStat

 

[btnModifica setEnabled:bSts];

 

Compilo e provo.

Ora occupiamoci di visualizzare i dati nei campi, nel caso di una variazione dati. Prima di tutto aggiungo al progetto i files FGBseData.h e .m

E’ una classe che utilizzo per trasformare comodamente una stringa nel formato “AAAAMMGG” in una NSDate e per fare altre varie operazioni sulle date in un modo a me piu’ famigliare.

Dato che nel nostro record c’e’ una data (NATOIL), uso questa mia classe.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I files sono nella cartella

 

Ora modifichiamo il codice relativo al pulsante Modifica premuto, in modo da leggere i dati presenti nel record e di presentarli nei rispettivi campi a video nel caso di variazione dati oppure di ripulire i campi nel caso di nuovo inserimento.

 

- (IBAction)btnModificaPremuto:(id)sender

{

 

//1: Check if key field is valid

NSString *aString=[[idPersona stringValue] TrimRight]; //Eliminate right blanks

 

if([aString isEqualToString:@""]){

 NSRunAlertPanel(@"ERRORE",@"E' Indispensabile indicare un identificativo della persona!",@"OK",nil,nil);

 return;

}

 

if([aString length] >25){

 NSRunAlertPanel(@"ERRORE",@"L'identificativo non puo' essere superiore a 25 caratteri!",@"OK",nil,nil);

 return;

}

 

//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);

 //Update info in user interface

 [descrizione setStringValue:[[theApp->pTabPersone FieldInfo:@"DESCR"] GetValue]];

 [eta setStringValue:[[theApp->pTabPersone FieldInfo:@"ETA"] GetValue]];

 [hobby setStringValue:[[theApp->pTabPersone FieldInfo:@"HOBBY"] GetValue]];

 [sport setStringValue:[[theApp->pTabPersone FieldInfo:@"SPORT"] GetValue]];

 [budget setStringValue:[[theApp->pTabPersone FieldInfo:@"BUDGET"] GetValue]];

 [flgSingle setState:[[[theApp->pTabPersone FieldInfo:@"SINGLE"] GetValue] intValue]];

 FGBseData *aDate=[[FGBseData alloc] init];

 [aDate SetDataR:[[theApp->pTabPersone FieldInfo:@"NATOIL"] GetValue]];

 [dataNascita setDateValue:[aDate GetCalendarDate]];

 [aDate release];

}else{

 NSLog(@"Not Found: %@ in table PERSONE",aString);

 //New record, clear fields

 [descrizione setStringValue:@""];

 [eta setStringValue::@""];

 [hobby setStringValue::@""];

 [sport setStringValue::@""];

 [budget setStringValue::@""];

 [flgSingle setState:FALSE];

}

 

[self setCtrlStat:FALSE];

 

}

 

Esaminiamo una parte del codice,

[descrizione setStringValue:[[theApp->pTabPersone FieldInfo:@"DESCR"] GetValue]];

il questo caso imposto il valore del controllo descrizione con il valore che ho nel record attualmente selezionato (abbiamo fatto in precedenza una LoadDati…) ed estraggo il valore (GetValue) relativo al campo del record che ha nome “DESCR” (E’ quindi il nome della colonna della tabella Persone del nostro database).

 

La stessa cosa si ripete per gli altri campi; diverso è invece il modo di impostare il flag Singolo (e’ un check box) e la data del compleanno (e’ un NsdatePicker)

 

Per il check box

[flgSingle setState:[[[theApp->pTabPersone FieldInfo:@"SINGLE"] GetValue] intValue]];

ricavo il valore del campo SINGLE (che vale “0” o “1”), lo trasformo in INT e lo passo al metodo setState del controllo check box button.

 

 

 

Per la data, uso la classe FGBseData

 

 FGBseData *aDate=[[FGBseData alloc] init]; //Creo l’oggetto dinamicamente

 

 //Chiamo il metodo che mi consente di impostare la data usando una stringa nel

 //formato “AAAAMMGG”, che è quello che uso per la registrazione dati sulle mie tabelle di

 //database

 [aDate SetDataR:[[theApp->pTabPersone FieldInfo:@"NATOIL"] GetValue]];

 

 //Imposto il controllo NSDatePicker con il nuovo valore di data, ricavato usando il metodo GetCalendarDate del mio oggetto FGBseData

 

 [dataNascita setDateValue:[aDate GetCalendarDate]];

 

 [aDate release]; //Libero la memoria allocata dalla “alloc”

 

SISTEMIAMO LA VISUALIZZAZIONE DELLA DATA NELLA TABLEVIEW

 

Modifico il codice nella FGODBCResultSet

 

if([colID isEqualToString:@"NATOIL"]){ //Date...

 

ovviamente, se abbiamo altre tabelle con campi dati, dovremo aggiungere gli altri nomi dei campi

 

Ecco il risultato,

 

 

ATTIVIAMO IL DOPPIO CLICK SULLA TABLEVIEW per selezionare i dati indicati

 

Per prima cosa, da IB dobbiamo disattivare l’opzione Editable su ciascuna colonna della nostra TableView (dobbio click su intestazione colonna e togliamo la casella di spunta dalla voce Editable).

 

salviamo e chiudiamo Interface Builder.

 

Ora andiamo a dire alla nostra tableview che vogliamo far eseguire un determinato metodo quando si effettua il doppio click su una riga

 

-(void) awakeFromNib{

  dsPersone=[[FGODBCResultSet alloc] init:theApp SetIdentifier:@"PERSONE" tableView:elencoPersone];

 

  [self setCtrlStat:TRUE]; //enable/disable control in user interface

 

  [elencoPersone setTarget:self];

  [elencoPersone setDoubleAction:@selector(loadSelectedData)]; //Double click

 

 

}

 

In pratica si tratta di impostare il metodo setDoubleAction della tableview, indicando quale è il metodo della nostra classe che vogliamo sia richiamato quando l’utente effettua un doppio click. (loadSelectedData)

 

Dato che il metodo che ho deciso di chiamare loadSelectedData è un metodo della classe panelPersoneController imposto il setTarget su self

 

Ora implemento il metodo nella classe panelPersoneController

 

Nel file .h

//Double click action

-(void)loadSelectedData;

 

Nel file .m

//Double click action

-(void)loadSelectedData{

 int nSelectedRow=[elencoPersone clickedRow];

 FGODBCRecord *tmpRecord=[dsPersone GetSingleRow:nSelectedRow];

 

 //Update info in user interface

 [idPersona setStringValue:[[tmpRecord FieldInfo:@"ID_PERSONA"] GetValue]];

 [descrizione setStringValue:[[tmpRecord FieldInfo:@"DESCR"] GetValue]];

 [eta setStringValue:[[tmpRecord FieldInfo:@"ETA"] GetValue]];

 [hobby setStringValue:[[tmpRecord FieldInfo:@"HOBBY"] GetValue]];

 [sport setStringValue:[[tmpRecord FieldInfo:@"SPORT"] GetValue]];

 [budget setStringValue:[[tmpRecord FieldInfo:@"BUDGET"] GetValue]];

 [flgSingle setState:[[[tmpRecord FieldInfo:@"SINGLE"] GetValue] intValue]];

 FGBseData *aDate=[[FGBseData alloc] init];

 [aDate SetDataR:[[tmpRecord FieldInfo:@"NATOIL"] GetValue]];

 [dataNascita setDateValue:[aDate GetCalendarDate]];

 [aDate release];

 [self setCtrlStat:FALSE];

}

Il nuovo metodo loadSelectedData appena implementato deve

1)  ricavare il numero della riga su cui l’utente ha fatto doppio click

2)  ricavare i dati del record corrispondente

3)  visualizzare i dati nei campi dell’interfaccia utente

4)  aggiornare situazione dello stato dei controlli

 

1)  int nSelectedRow=[elencoPersone clickedRow]; //ricavo la riga selezionata

2)  FGODBCRecord *tmpRecord=[dsPersone GetSingleRow:nSelectedRow]; //il mio datasource non è altro che un array du FGODBCRecord, quindi chiedo di restituirmi il record numero nSelectedRow

3)  [idPersona setStringValue:[[tmpRecord FieldInfo:@"ID_PERSONA"] GetValue]]; //ricavo il dato relativo al campo indicato

4)  [self setCtrlStat:FALSE]; //aggiorna situazione pulsanti e campi di immissione

 

 

Il mio tutorial è quindi finito, abbiamo visto come inferfacciare MySql con una applicazione Cocoa, e gestire una tabelle (PERSONE) in modo completo, effettuando l’immissione, la variazione, la cancellazione, la stampa, la visualizzazione e la selezione dalla visualizzazione.

 

Spero di essere stato sufficientemente chiaro ed esauriente.

 

Per qualsiasi ulteriore informazione, suggerimento, correzione, implementazione, traduzione ecc. non esisate a contattarmi.

 

Grazie per l’attenzione dedicata e grazie nuovamente alla Actual Technologies

Per avermi concesso l’uso di una licenza trial di 15 giorni del loro driver ODBC.

 

Nel file zip che accompagna questo tutorial troverete tutto il materiale che ho usato io per la realizzazione di questo tutorial.

 

Saluti.

 

Franceso Germinara

www.germinara.it

info@germinara.it

 

 

 

 

 

 

 

Ecco come si presenta la videata della gestione delle Persone alla fine

 

 

 

 

 

Ideato, scritto e realizzato da Francesco Germinara

 

7/8 dicembre 2005 Pinerolo, Torino - Italy

 

In allegato c’e’ l’applicazione completa ecco le videate