venerdì 26 febbraio 2016

Turbo Vision, la visione dell'era delle interfacce grafiche secondo la Borland

Era il 1990, e la Borland, con un po' di ritardo (diciamo, un ritardo spaventoso) lancia il framework Turbo Vision, quando già la Apple e la Microsoft rivaleggiavano con le interfacce grafiche in VGA e la modalità testuale del DOS era un vecchio ricordo. 

Si tratta di un framework object-oriented (lanciato in concomitanza con l'aggiornamento del linguaggio Turbo Pascal 7.0, con l'implementazione dell'object orienting) che fornisce una interfaccia grafica (o meglio, una imitazione di una interfaccia grafica) in modalità testuale, con l'uso di diversi widget (finestre, tasti, menu, barra di scelta veloce ecc.). Purtroppo non ebbe molto seguito per ovvi motivi, giusto un anno dopo veniva rilasciato Windows 3.1, il primo Microsoft OS completamente grafico. 

Però. Però.
Non nego che ha un fascino innegabile. Quello schermo pieno di pixel e quei movimenti scattosi, gli stratagemmi per le ombreggiature e le animazioni per rendere tridimensionale l'ambiente sono molto belli da vedere, e mi piacciono ancora oggi. E devo dire che non sono l'unico.

L'angolo della nostalgia

Ho iniziato a programmare in Pascal, e tengo sempre un posto particolare nel mio cuore di programmatore per questo linguaggio. Era il 2001 circa, la prima versione che scaricai era quella che il libro su cui studiavo i principi della programmazione consigliava. 
Oggi ho scaricato il simulatore DOS DOSBox e rivisto alcuni dei miei vecchi programmi scritti usando il Turbo Pascal 4.0. Questo è un esempio:

e qui mi viene da sorridere facendo il critico dopo 13 anni. A parte la pixel art che è vergognosa, l'area di calcolo è così piccola che viene a decadere tutta l'utilità del programma. E poi non c'era motivo di mettere una pixel art (Alby III G, la mia classe d'Istituto) che prendesse tutto lo schermo. 
Questa versione è rimasta 1.1. Flash Utility lasciò il posto a un esperimento del 2009 usando appunto Turbo Vision. 

Questa versione (chiamata FXMath o FixMath) è un'applicazione più matura ma comunque, piena zeppa di bug, anche perché non l'ho curata più di tanto. Consiste in un calcolatore di espressioni dove il risultato viene dato analizzando (parsing) la stringa inserita carattere per carattere, con la casella di testo "personalizzata" ad hoc per l'editing. E' un progetto più complesso, che presenta le caratteristiche di ereditarietà e polimorfismo tipiche della programmazione ad oggetti. Questo progetto verrà sviluppato più avanti in ambiente linux usando le gtk+. Più avanti dedicherò il post. 
Riporto solamente la dichiarazione degli oggetti usati nel programma:
TYPE
    TipodiOggetto = (Numero,Operatore);

    PCasellaTesto = ^TCasellaTesto;
    TCasellaTesto = OBJECT (TInputLine)
                      PUBLIC
                      Expression: ARRAY[0..1024] OF PMathObject;{L'espressione.}
                      IndiceOggetto:word;                     {Il numero     }
                                                              {ordinale.     }
                      Counter:Word;                           {Numero oggetti}
                      ame:PCasellaTesto;
                      CONSTRUCTOR Init(TR:TRect;TMaxLen:Word);
                      PROCEDURE Draw;Virtual;                 {Override      }
                      PROCEDURE SetExpression(Oggetto:PMathObject);{Memorizza}
                      PROCEDURE Riordina(Indice:Word;Direzione:boolean;lung:byte);
                      PUBLIC                                     {nell'arra}
                      FUNCTION  IsCursorShown:boolean;
                      FUNCTION  FormattaNumero(n:real):string;
                      FUNCTION  CatturaNumero(dir:boolean;Indice:word;VAR P:word):real;
                      PROCEDURE ToArray(Indice:word;num:real);
                      FUNCTION  CancellaOggetto(Indice:Word):byte;
                      PROCEDURE CalcolaEspressione;           {in una MsgBox }
                      PROCEDURE HandleEvent(var Event:TEvent);VIRTUAL;
                    END;
    PEspresBox = ^TEspresBox;
    TEspresBox = OBJECT (TDialog)                     {La finestra di dialogo}
                     PUBLIC
                     Field:PCasellaTesto;
                     CONSTRUCTOR Init;
                     PROCEDURE HandleEvent(var Event: TEvent); VIRTUAL;
                  END;
    TMyApp = OBJECT (TApplication)
                 EspresBox :PEspresBox;
                 PROCEDURE NuovaFinestra;
                 PROCEDURE HandleEvent(var Event:TEvent); VIRTUAL;
                 PROCEDURE InitMenuBar; VIRTUAL;
                 PROCEDURE ApriFinestraEspressione;
                 FUNCTION GetFileMenuItems(mah: PmenuItem) : PMenuItem;
                 FUNCTION GetEditMenuItems(mah: PMenuitem) : PMenuItem;
                 FUNCTION GetInsertMenuItems(mah: PMenuItem) : PMenuItem;
                 FUNCTION GetHelpMenuItems(mah: PMenuItem) : PMenuItem;
              END;

giovedì 25 febbraio 2016

L'applicativo scritto per la mia tesi di laurea

Per la mia tesi di laurea ho scritto un software in java per automatizzare un calcolo che, anche fatto con un foglio di calcolo, richiedeva della manualità e quindi più tempo. 
Il programma sviluppato non è certo chissà cosa di complicato, ma essendo un programmatore, ho voluto inserire qualcosa che riguardasse la programmazione nella mia tesi di laurea. 

Schermata del software
Piccolo incipit.
La mia tesi di laurea "Produzione, gestione e smaltimento dei rifiuti citotossici e citostatici
nell’AOUP “Paolo Giaccone” di Palermo", redatta con uno stage dove ho raccolto dati, riguarda lo smaltimento dei rifiuti citotossici e citostatici. I dati che avevo raccolto riguardavano le quantità di rifiuti relativi a certi farmaci prodotti ogni giorno, e ogni farmaco è caratteristico di un reparto. Il mio programma non fa altro che calcolare le percentuali del numero di farmaci effettivamente utilizzati per ogni reparto, su scala settimanale. Posso decidere se utilizzare i dati di 1, 2 o 3 settimane, come si nota sullo screenshot. Inseriti i file .csv, formati in questo modo:


poi basta premere sul tasto Elabora, che nel log del programma vengono mostrati i dati in output, che verranno comunque esportati in altrettanti file .csv. 

Dando un'occhiata al codice, ho utilizzato la libreria esterna opencsv versione 3.4 per gestire i file csv in maniera veloce. 

public class Farmaci {

    public static double oncologia=0;
    public static double ematologia=0;
    public static double neurologia=0;
    public static double urologia=0;
    public static double reumatologia=0;
    public static double onco=0;
    public static double ema=0;
    public static double neuro=0;
    public static double uro=0;
    public static double reuma=0;
    public static Integer[] ID;
    public static int primo=0, secondo=0, terzo=0;
    /*numero di farmaci*/
    public static int count;
    public static Frame frame = new Frame();
    
    
    public static void main(String[] args) {
        ID = new Integer[67];
        for (int i=0;i<67;i++)
            ID[i] = new Integer(0);
        frame.setVisible(true);
    }
}

Questa è la classe principale dove dichiaro le variabili principali. Nel metodo main inizializzo l'array di Integer di 67 elementi, tanti quanto il numero di farmaci. 
Riporto dalla mia tesi:

Il seguente codice scritto in linguaggio Java è la funzione principale del software che ho scritto. Essa riceve in input un intero da 1 a 3 che denota la casella contenente il percorso del file .csv da elaborare, quindi apre il file, legge iteratamente ogni record ed effettua le opportune operazioni, per poi infine scrivere le percentuali nelle 5 label relative a ogni reparto, e riportare altre informazioni nella casella di testo “sum”.
private voidelaboraFile(intindiceCasellaDiTesto){
try{
CSVReadercsvReader;
/*  Controllo quale casella del file esaminare */
if (indiceCasellaDiTesto==1)
csvReader = new CSVReader(new java.io.FileReader(new File(this.file1textfield.getText())),';');
else if (indiceCasellaDiTesto==2)
csvReader = new CSVReader(new java.io.FileReader(new File(this.file2textfield.getText())),';');
else if (indiceCasellaDiTesto==3)
csvReader = new CSVReader(new java.io.FileReader(new File(this.file3textfield.getText())),';');
else //DevoinizializzareobbligatoriamentecsvReader
csvReader = new CSVReader(new java.io.FileReader(new File(this.file1textfield.getText())),';');
String[] row=null;
/* Leggo dal file .csv */
while ((row = csvReader.readNext())!=null){
if (!row[0].equals("0")){ //controllo se è la riga terminale
Farmaci.ID[Integer.parseInt(row[0])-1]=Farmaci.ID[Integer.parseInt(row[0])-1]+Integer.parseInt(row[2]);      //memorizzo il farmaco con il numero delle volte che è stato utilizzato
/* Da qui in poi verifico a quale reparto “appartiene” ed eseguo le dovute operazioni
if (row[1].equals("oncologia"))
Farmaci.onco=Farmaci.onco+Integer.parseInt(row[2]);
else if (row[1].equals("oncoema")){
Farmaci.onco=Farmaci.onco+0.5*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.5*Integer.parseInt(row[2]);
}
else if (row[1].equals("oncoemaneuo")){
Farmaci.onco=Farmaci.onco+0.3333*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.3333*Integer.parseInt(row[2]);
Farmaci.neuro=Farmaci.neuro+0.3333*Integer.parseInt(row[2]);
}
else if (row[1].equals("ema")){
Farmaci.ema = Farmaci.ema+Integer.parseInt(row[2]);
}
else if (row[1].equals("oncoemaurol ")){
Farmaci.onco=Farmaci.onco+0.3333*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.3333*Integer.parseInt(row[2]);
Farmaci.uro=Farmaci.uro+0.3333*Integer.parseInt(row[2]);
}
else if (row[1].equals("oncoemaurol")){
Farmaci.onco=Farmaci.onco+0.3333*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.3333*Integer.parseInt(row[2]);
Farmaci.uro=Farmaci.uro+0.3333*Integer.parseInt(row[2]);
}
else if (row[1].equals("reumatologia")){
Farmaci.reuma=Farmaci.reuma+Integer.parseInt(row[2]);
}
/* Aumento il contatore del numero di flaconi utilizzati */
Farmaci.count = Farmaci.count+Integer.parseInt(row[2]);
}
else{
/* Operazioni da effettuare quando si arriva a fine giornata.
   ovvero il calcolo delle percentuali */
Farmaci.oncologia = (Farmaci.onco/Farmaci.count)*100;
Farmaci.ematologia = (Farmaci.ema/Farmaci.count)*100;
Farmaci.urologia = (Farmaci.uro/Farmaci.count)*100;
Farmaci.neurologia = (Farmaci.neuro/Farmaci.count)*100;
Farmaci.reumatologia = (Farmaci.reuma/Farmaci.count)*100;
oncologia.setText(String.format("%.2f",Farmaci.oncologia)+"%");
ematologia.setText(String.format("%.2f",Farmaci.ematologia)+"%");
urologia.setText(String.format("%.2f",Farmaci.urologia)+"%");
neurologia.setText(String.format("%.2f",Farmaci.neurologia)+"%");
reumatologia.setText(String.format("%.2f",Farmaci.reumatologia)+"%");
}
}
/* Trovo i tre farmaci più utilizzati */
int primo=0, secondo=0, terzo=0;
for (int i=0;i<67;i++){
if (Farmaci.ID[i]>Farmaci.ID[primo])
primo = i;
}
for (inti=0;i<67;i++){
if ((Farmaci.ID[i]>Farmaci.ID[secondo])&&(Farmaci.ID[i]<Farmaci.ID[primo]))
secondo = i;
}
for (inti=0;i<67;i++){
if ((Farmaci.ID[i]>Farmaci.ID[terzo])&&(Farmaci.ID[i]<Farmaci.ID[secondo]))
terzo = i;
}
/* Scrivo il tutto nella casella di testo per mostrare i dati. */
sum.append("Numero di farmaci utilizzati: "+Farmaci.count+"\n");
sum.append("I tre farmaci più utilizzati (per ID): \n");
sum.append("#"+Integer.toString(primo)+": "+Integer.toString(Farmaci.ID[primo])+" usi\n");
sum.append("#"+Integer.toString(secondo)+": "+Integer.toString(Farmaci.ID[secondo])+" usi\n");
sum.append("#"+Integer.toString(terzo)+": "+Integer.toString(Farmaci.ID[terzo])+" usi\n");
}
/* Controllo degli errori */
catch(java.io.IOException e){
sum.append("File non trovato\n");
}
catch(Exception e){
sum.append("Si è verificato un errore: "+e.getMessage()+”\n”);
}
}