EnneBi – Programmazione

IndietroIndiceAvanti

Progetto 3: dipendenti di un reparto

Il programma ora proposto permette di inserire i dati dei dipendenti di una ditta e di selezionare i dipendenti che lavorano in un reparto scelto fra quelli in cui sono registrati dipendenti.

la GUI è composta da due schede: nella prima si può inserire un dipendente. Se non si specifica il reparto, essendo questo un dato importante per la selezione, viene mostrata una finestra di dialogo con un messaggio di avviso. Si può passare da un campo all'altro premendo il pulsante Tab e dopo l'inserimento dell'ultimo campo (Nome) si può premere Invio (o premere il tasto Aggiungi) per accodare il dipendente alla lista. Nella seconda scheda è presente un menù a discesa dal quale si può selezionare uno dei reparti e, premendo il pulsante Cerca, si possono vedere tutti i dipendenti inseriti che lavorano nel reparto selezionato.

  1. Avviato FLUID si comincia selezionando Function. Il Name sarà, al solito, lasciato vuoto per costruire la main.

  2. Si aggiunge alla funzione una Window inserendo nella Label della finestra delle proprietà Selezione Dipendenti per Reparto.

  3. Inserire un elemento Tabs (secondo gruppo da sinistra, icona riga centrale a sinistra, nella Widget Bin o New, Group, Tabs). Non è necessario specificare alcuna proprietà.

  4. Inserire Group (accanto alla Window nella Widget Bin) e immettere nella finestra delle proprietà nel tab GUI la Label Dipendenti (sarà visualizzata nell'etichetta della scheda). L'elemento raggrupperà tutti i controlli che verranno visualizzati nella scheda. Nel tab Style della finestra delle proprietà, si può selezionare (scegliendo da Label Color) un colore più chiaro in modo che, quando la scheda non risulterà selezionata, il colore dell'etichetta sia più chiaro e sarà ancora più evidente la scheda attiva.

  5. Selezionare il gruppo e inserire dentro tre elementi di tipo Input (primo pulsante in alto, quinto gruppo della Widget Bin). Nelle proprietà Name del tab C++ inserire, rispettivamente rep, cognome, nome.

  6. Inserire, sempre all'interno del gruppo (basta accertarsi che sia selezionato il gruppo) tre elementi Box in modo da sistemare le etichette sopra le caselle di input. Le Label del tab GUI delle proprietà dei box saranno, rispettivamente, Reparto, Cognome, Nome.

  7. Sempre all'interno del gruppo, inserire un elemento di tipo Browser (pulsante in alto penultimo gruppo da sinistra nella Widget Bin). Nel Name del tab C++ della finestra delle proprietà, inserire elDip.

  8. Per completare il gruppo inserire un Return Button. Specificare nella Label del tab GUI della finestra delle proprietà, Aggiungi. Nel tab C++ bisogna inserire nel Name aggiungi e in Callback, cbAggiungi.

  9. Selezionare Tabs e inserire un nuovo Group. Nelle proprietà inserire Reparto nella Label. Anche qui si può scegliere, nel tab Style della finestra delle proprietà, lo stesso colore più chiaro scelto nel gruppo precedente.

  10. Selezionare il nuovo gruppo e inserire un Box con Label Reparto.

  11. All'interno del gruppo inserire un elemento Choice per il menù a discesa (sesto gruppo da sinistra della Widget Bin, icona a sinistra in basso). Il Name sarà impostato a listaRep.

  12. Inserire nel gruppo un elemento Browser. La proprietà Name potrà essere elDipCerca.

  13. Completare il gruppo con un Button con Label Cerca, Name cerca e Callback cbCerca.

  14. Per completare la GUI è necessario inserire un Code per specificare le caratteristiche dei Browser utilizzati. Selezionare Code e inserire le linee:

    int colonne[]={80,105,105};	/*1*/
    
    elDip->column_widths(colonne);	/*2*/
    elDip->column_char('\t');	/*3*/
    elDip->type(FL_MULTI_BROWSER);	/*4*/
    elDip->add("Reparto\tCognome\tNome");	/*5*/
    
    elDipCerca->column_widths(colonne);	/*2*/
    elDipCerca->column_char('\t');	/*3*/
    elDipCerca->type(FL_MULTI_BROWSER);	/*4*/
    

    Nella 1 si dichiara un array di tipo int contenente la larghezza delle colonne. Negli elementi dell'array sono inseriti numeri ricopiati dalle larghezze delle tre caselle di input dei dati del dipendente (Width della riga Position del tab GUI della finestra delle proprietà).

    Nelle 2 si passa al browser la larghezza delle colonne e nelle 3 il carattere che separerà una colonna dall'altra: il carattere di tabulazione. Nelle 4 si specifica che si tratta di browser multicolonna. La 5 aggiunge la riga delle intestazioni delle colonne nel browser presente nella prima scheda dell'applicazione.

La GUI è completata. Resta da inserire, alla fine, l'include del file contenente il codice delle funzioni. Inserire una Declaration:

#include “selDipF.cxx”

A conclusione di tutti i passaggi specificati la GUI dovrebbe essere:

Esame delle funzioni da definire in selDipF.cxx:

#include <FL/fl_ask.H>	/*1*/
#include <string>
using namespace std;

// Prototipi

string estraiRep(string);
void modListaRep(const char *);

// Callback associata al pulsante Aggiungi
// Aggiunge un dipendente alla lista

void cbAggiungi(Fl_Return_Button* o, void*)
{
  string r,cog, nom;
  string linea;
  char lin[100];

  // verifica se inserito reparto

  if(!strcmp(rep->value(),"")){	/*2*/
    fl_alert("E\' necessario inserire il reparto");	/*3*/
    rep->take_focus();
    return;
  }
  
  // verifica se aggiungere reparto alla lista di scelta

  modListaRep(rep->value());	/*4*/

  // aggiunge dati del dipendente all'elenco

  r.assign(rep->value());	/*5*/
  cog.assign(cognome->value());	/*5*/
  nom.assign(nome->value());	/*5*/
  
  linea = r + "\t" + cog + "\t" + nom;	/*6*/
  strcpy(lin,linea.c_str());	/*7*/
  
  elDip->add(lin);	/*8*/
  rep->value("");	/*9*/
  cognome->value("");	/*9*/
  nome->value("");	/*9*/

  rep->take_focus();	/*10*/
}

L'inclusione della 1 definisce un insieme di funzioni della FLTK per l'utilizzo delle comuni finestre di dialogo degli ambienti grafici.

Poiché il codice del reparto è importante per l'elaborazione, visto che seleziona i dipendenti per reparto, è necessario che l'utente inserisca tale codice. La funzione controlla (2) se è stata lasciata vuota la casella di input del codice e, in tal caso, visualizza (3) una finestra di dialogo con un messaggio di avviso. Si tratta delle classiche finestre degli ambienti grafici, che non permettono di andare avanti se prima non vengono chiuse, che mostrano un avviso accompagnato da un icona con un simbolo di attenzione e che presentano un pulsante Ok che permette di chiuderle e riprendere il controllo del programma. L'inclusione della 1 serve per disporre, fra l'altro, di fl_alert().

Se non è stato inserito alcun valore nel campo del reparto la funzione termina altrimenti si passa il reparto (4) ad una funzione che provvede ad aggiungerlo, se non già esistente, alla lista dei reparti da cui scegliere per la selezione.

I valori inseriti nelle caselle di input vengono convertiti (5) in stringhe C++ type in modo da creare facilmente la riga da inserire nel browser (6). Nella riga fra un campo e l'altro è stato inserito un carattere di tabulazione in modo da incolonnare i dati, così come previsto dalle impostazioni effettuate sui componenti Browser della GUI. Infine la riga è riconvertita in formato C type (7). Era possibile generare la stringa da inserire anche senza effettuare la doppia conversione utilizzando più volte la funzione strcat(), ma qui si è fatta questa scelta per motivi di maggiore leggibilità in riferimento soprattutto alla 6.

la riga viene aggiunta al browser (8), si reinizializzano i valori delle caselle di input (9) e si porta il focus sulla casella dell'inserimento del reparto (10).

// Verifica se aggiornare lista reparti

void modListaRep(const char *r)
{
  int i;
  bool trovato=false;

  if(!listaRep->size())	/*1*/
    listaRep->add(r);	/*2*/
  else{	
    for(i=0;i<listaRep->size()-1;i++){	/*3*/
      if(!(strcmp(r,listaRep->text(i))))	/*4*/
        trovato = true;
    }
    if(!trovato)	
      listaRep->add(r);	/*5*/
  }
}

Se la lista dei reparti è vuota (1) si inserisce il reparto (2) nelle voci del menù a discesa. In questo caso il metodo size() restituisce un valore nullo.

Il ciclo 3 effettua la scansione delle righe contenute nel menù a discesa. Il metodo size() restituisce la quantità di righe +1 (la riga con il terminatore), ma il metodo text() richiede come parametro il numero di riga (4) e le righe sono contate a cominciare dal valore 0. Quindi se, per esempio, ci sono 5 righe, size() restituisce 6 e il ciclo deve esaminare le righe dalla 0 alla 4.

Se il reparto passato come parametro alla funzione non coincide con alcuna delle righe esistenti nella Choise (4) si aggiunge in coda alle righe esistenti già (5).

// Callback associata al pulsante Cerca
// Seleziona i dipendenti del reparto cercato

void cbCerca(Fl_Button* o, void*)
{
  string rInp, rDip, linOld;
  int i;

  if(listaRep->value()<0){	/*1*/
    fl_alert("E\' necessario scegliere un reparto");
    return;
  }

  rInp.assign(listaRep->text());	/*2*/

  // inizializza browser

  elDipCerca->clear();	/*3*/
  elDipCerca->add("Reparto\tCognome\tNome");	/*4*/

  // le righe cominciano da 1 ma
  // nella 1 ci sono le intestazioni

  for(i=2;i<=elDip->size();i++){	/*5*/

    // estrae e verifica reparto

    linOld.assign(elDip->text(i));
    rDip = estraiRep(linOld);	/*6*/
     
    if(rDip==rInp)
      elDipCerca->add(elDip->text(i));	/*7*/
  }
}

Se non è stato selezionato alcun reparto (1), o perché l'utente non ha effettuato una scelta o perché non è stato possibile fare una scelta poiché non sono stati inseriti dipendenti, viene visualizzata una finestra di dialogo di avvertimento e si abbandona la funzione. La non selezione infatti fa ritornare al metodo il valore -1. Se invece una qualche selezione è stata effettuata, il metodo ritorna il numero di selezione effettuata contata dal valore 0 (la prima selezione).

Se c'è una selezione si trasforma in stringa C++ type il reparto selezionato (2), si pulisce l'area che conterrà i dati (3) e si scrive la riga delle intestazioni (4).

Si esaminano tutte le righe che rappresentano tutti i dipendenti inseriti (5). Si estrae dalla riga il codice del reparto (6) e se coincide con quello scelto su cui si vuole effettuare la selezione si aggiunge la riga del dipendente al contenitore della selezione (7).

L'inizializzazione del ciclo 5 al valore 2 dipende dal fatto che la prima riga del browser elDip contiene l'intestazione che non è utile nell'elaborazione e che deve essere scartata.

// Estrae reparto dalla linea

string estraiRep(string ri)
{
  string ro;
  int pos;

  pos = ri.find("\t");	/*1*/
  ro = ri.substr(0,pos);	/*2*/

  return ro;
}

L'ultima funzione da commentare è abbastanza intuitiva: si cerca la posizione del carattere (il tabulatore) che separa la prima colonna, contenete il codice del reparto, dalla successiva (1) e si estrae la sottostringa (2) del codice.



IndietroIndiceAvanti