Corso di Java

(senza pretese)

Lezione dodici: il Look And Feel.


Premessa
In questa lezione faremo ben due cose: la prima è vedere un po' come funziona il Look And Feel degli oggetti grafici e poi, come avevo preannunciato nella scorsa lezione andremo ad implementare i box di apertura e salvataggio dei files.
Per maggiore chiarezza procederò in questo modo: prima vedremo cosa è e come implementare il Look And Feel nelle vostre applicazioni e successivamente analizzeremo il sorgente di una applicazione fatta per l'occasione e commentata a dovere per capire effettivamente come "agire" per modificare stile e files.

Il Look And Feel
A tradurlo in italiano suonerebbe come "Aspetto e Sensazioni" (con un plurale messo perché sennò suonava male) e si riferisce all'aspetto grafico e al modo in cui l'utente delle vostre applicazioni interagisce con le stesse.
In poche parole, con Java è possibile specificare (e anche modificare durante l'esecuzione) lo stile grafico di una applicazione.
I diversi Look And Feel sono (a quanto sembra) abbastanza, ma noi ci concentreremo su quelli che vengono standard con il JDK 1.2 (e con l'1.3.1), ovvero "Windows", "Motif" e "Metal".
I primi due riprendono i rispettivi stili grafici dei sistemi Windows e Unix, mentre il terzo è il Look And Feel caratteristico di Java.

Il metodo più semplice per attribuire ad una applicazione un determinato L&F (per brevità da ora in poi userò questa sigla al posto di "Look And Feel") è quello di specificarlo durante la creazione del frame principale della finestra, all'interno della funzione main(). Attenzione però perché l'impostazione del L&F genera una eccezione che deve essere o lanciata oppure intercettata (è meglio) tramite un blocco try...catch. Guardiamo come fare:

Esempio tratto dal codice di HTML (J)Editor 4.1
 public static void main (String[] args)
  {
   JFrame edtr = new Editor("HTML (J)Editor Pro Ver 4.1 - Build 362");
   WindowListener wl = new WindowAdapter()
   {public void windowClosing(WindowEvent e){System.exit(0);}};
   edtr.addWindowListener(wl);
   edtr.setSize(800,550);
   edtr.setVisible(true);
     
   try {
        UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
        
        //Questo sotto valida (ricrea) l'intera area
        edtr.validate();
       }
   catch (Exception e)
   {
    JOptionPane.showMessageDialog(null,"Impossibile impostare lo stile: " + e);
   
   //Se non va con il metal si fa prendere il L&F di sistema.
   //Occorre un blocco try...catch interno!!!
   try{
   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
   }
   catch (Exception e_int)
   {
    JOptionPane.showMessageDialog(null,"Impossibile impostare lo stile: " + e_int);
   }
   //Fine blocco try...catch interno
   }
  }


Come potete vedere è molto semplice impostare all'inizio lo stile del frame. Per impostare un L&F si può agire in due modi come ho fatto nel codice sopra: il primo viene richiamato tramite la notazione puntata alla classe che lo gestice (in questo caso il Metal), mentre nel secondo caso per impostare il L&F si usa un metodo che imposta lo stile di sistema: questo fa in modo che se state lavorando su macchine Win, lo stile sarà "Windows", mentre se state lavorando su macchine Unix sarà il "Motif".
Nel caso ci sia qualche problema vengono presentati dei JOptionPane che avvisano dell'eccezione sollevata. Per fare una prova, nel primo L&F richiesto, cambiate la stringa che punta al "Metal" con una volutamente sbagliata e vedrete che:
  1. Apparirà il JOptionPane che riporta l'eccezione;
  2. Verrà applicato lo stile di sistema;
Ma questo non è tutto. Anzi... È infatti possibile cambiare il L&F anche durante l'esecuzione dell'applicazione, specificando il nuovo stile e aggiornando tutto il frame. Ognuno può decidere un suo modo per far cambiare il L&F all'applicazione. Io personalmente ho usato nei miei programmi un menu della barra menu principale che contenesse radiobuttons per scegliere tra i vari L&F. Naturalmente questo significa che tali voci di menu avranno un actionListener che si preoccuperà di svolgere il lavoro di passaggio da uno stile all'altro.

Passerei quindi ad esaminare il codice sorgente di questa piccola applicazione che ho creato per spiegarvi il funzionamento delle procedure di salvataggio/apertura files e modifica di L&F.
Si tratta di un rudimentalissimo editor di testi in grado di salvare e caricare files .txt.
Attenzione, il codice è un po' lungo!

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;


public class Esempio extends JFrame  implements ActionListener
{
 /*Qui si dichiarano tutti gli elementi che compongono
   la nostra applicazione*/

  JMenuItem ItemApri = new JMenuItem("Apri");
  JMenuItem ItemSalva = new JMenuItem("Salva");
  JMenuItem ItemEsci = new JMenuItem("Esci");
  JRadioButtonMenuItem rbmMotif = new JRadioButtonMenuItem("CDE/Motif");
  JRadioButtonMenuItem rbmWin = new JRadioButtonMenuItem("Windows");
  JRadioButtonMenuItem rbmMetal = new JRadioButtonMenuItem("Metal");

  //L'area di editing
   JTextArea AreaEditing = new JTextArea();


  public Esempio(String titolo)
  {
   /*Questo serve per impostare la stringa nella barra del titolo*/
   super(titolo);

   /*Aggiungo gli actionListener. Il this all'interno significa
     che il metodo actionPerformed che si occupera' della
     gestione degli eventi si trova all'interno di questa classe*/
   ItemApri.addActionListener(this);
   ItemSalva.addActionListener(this);
   ItemEsci.addActionListener(this);
   rbmMotif.addActionListener(this);
   rbmWin.addActionListener(this);
   rbmMetal.addActionListener(this);

   /*Qui si creano i pannelli e i layout*/
   JPanel PannelloPrincipale = new JPanel(new BorderLayout());

   /*Creo un pannello che abbia barre di scorrimento e che contenga
     l'oggetto AreaEditing. Si poteva anche non specificare AreaEditing
     e usare il metodo add() successivamente per aggiungerla.
     La barra di scorrimento non sara' visualizzata fino a che non
     se ne avra' bisogno. Comunque e' possibile far apparire sempre
     le barre di scorrimento tramite i metodi
     setHorizontalScrollbarPolicy() e setVerticalScrollbarPolicy()
     con argomenti appropriati.
     */
   JScrollPane EditingScrollPane = new JScrollPane(AreaEditing);

   //Barra dei menu
   JMenuBar BarraMenu = new JMenuBar();
   //Menu
   JMenu MenuFile = new JMenu("File");
   JMenu MenuLAF = new JMenu("Look&Feel");
   //Aggiunta componenti al menu File
   MenuFile.add(ItemApri);
   MenuFile.add(ItemSalva);
   MenuFile.add(ItemEsci);
   //Aggiunta componenti al menu L&F
   MenuLAF.add(rbmMotif);
   MenuLAF.add(rbmWin);
   MenuLAF.add(rbmMetal);
   //Aggiunta menu alla barra
   BarraMenu.add(MenuFile);
   BarraMenu.add(MenuLAF);

   //Aggiunta componenti al panello principale
   PannelloPrincipale.add("North", BarraMenu);
   PannelloPrincipale.add("Center", EditingScrollPane);

   setContentPane(PannelloPrincipale);
   PannelloPrincipale.setVisible(true);
  }

  /*Funzione che fa partire il tutto*/
  public static void main (String[] args)
  {
   /*Creo una finestra dalla classe Esempio. L'argomento della
     chiamata di funzione e' il testo della barra del titolo.
   */
   JFrame applicazione = new Esempio("Applicazione di prova by AlexMfM");

   /*Il seguente codice serve per gestire il pulsante di chiusura
     della finestra. Non fateci troppo caso, copiatelo pari pari
   */
   WindowListener wl = new WindowAdapter()
   {public void windowClosing(WindowEvent e){System.exit(0);}};

   /*Si aggiunge il WindowListener creato sopra*/
   applicazione.addWindowListener(wl);
   /*Si impostano le dimensioni della finestra e
     si rende visibile*/

   applicazione.setSize(500,500);
   applicazione.setVisible(true);

   /*Blocco try...catch per impostare lo stile grafico della
     finestra. Qui si usa lo stile del sistema operativo su
     cui si usa l'applicazione. Dato che questa parte di codice
     potrebbe generare un errore (non si riesce a impostare lo stile),
     si intercetta nel blocco catch e se tale errore si verifica
     viene fatto apparire un messageDialog che ci avverte.*/
   try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
       }
   catch (Exception e)
   {
    JOptionPane.showMessageDialog(null,"Impossibile impostare lo stile: " + e);
   }



  } //Fine di main()

  /*Metodo che gestisce gli eventi catturati da ActionListener
    L'argomento e' l'evento che viene generato*/
  public void actionPerformed(ActionEvent evento)
 {
  /*Questo serve per identificare l'oggetto che e' stato
    la sorgente dell'evento intercettato*/
  Object sorgente = evento.getSource();

  //Menu File->Esci
  if(sorgente==ItemEsci)
  {
   /*Implementiamo il classico dialog box che chiede se si
     vuole salvare il file prima di uscire. Per prima cosa
     questo intero conterra' il risultato della decisione che
     prenderemo cliccando nel dialog box*/
   int decisione;

   /*Associando l'intero al JOptionPane, facciamo in modo di
     "catturare" la scelta fatta sotto forma di intero*/
   decisione = JOptionPane.showConfirmDialog(null,
   "Salvare il documento corrente prima di uscire dall'applicazione?",
   "Salvo il documento?", JOptionPane.YES_NO_CANCEL_OPTION);

   //Se si sceglie di salvare...
   if (decisione==JOptionPane.YES_OPTION)
   { funzione_salva();
     System.exit(0);
   }
   //Se non si vuole salvare si esce
   else if (decisione==JOptionPane.NO_OPTION)
   {
   System.exit(0);
   }
   //Se annulliamo si ritorna al programma
   else if (decisione==JOptionPane.CANCEL_OPTION)
   {
   return;
   }
  }

  //Menu File->Apri
  if (sorgente==ItemApri)
  {
   leggi();
  }

  //Menu File->Salva
  if (sorgente==ItemSalva)
  {
   funzione_salva();
  }

  //Menu L&F->CDE/Motif
  if (sorgente==rbmMotif)
   {
    rbmWin.setSelected(false);
    rbmMetal.setSelected(false);
    //Codice x impostare lo stile Motif
    try
    {
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
    }
    catch (Exception e)
    {JOptionPane.showMessageDialog(null, "Impossibile impostare lo stile: "+e);
    }
    //Aggiorniamo la finestra con il nuovo stile
    SwingUtilities.updateComponentTreeUI(super);
   }

  //Menu L&F->Windows
  if (sorgente==rbmWin)
   {
    rbmMotif.setSelected(false);
    rbmMetal.setSelected(false);

    //Codice x impostare lo stile Windows
     try
     {
      UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
     }
     catch (Exception e)
     {
      JOptionPane.showMessageDialog(null, "Impossibile impostare lo stile: "+e);
     }
     //Aggiorniamo la finestra con il nuovo stile
     SwingUtilities.updateComponentTreeUI(super);
    }

  //Menu L&F->Metal
  if (sorgente==rbmMetal)
   {
    rbmMotif.setSelected(false);
    rbmWin.setSelected(false);
    //Codice x impostare lo stile Metal
    try
    {
     UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
    }
    catch (Exception e)
    {
    JOptionPane.showMessageDialog(null, "Impossibile impostare lo stile: "+e);
    }
     //Aggiorniamo la finestra con il nuovo stile
     SwingUtilities.updateComponentTreeUI(super);
   }


  } //Fine actionPerformed()


  //Funzione per salvare files di testo
   public void funzione_salva()
  {
   /*Creo uno di quegli "aggeggi" per scegliere i files
     e lo mostro*/
   JFileChooser apri_box = new JFileChooser();
   apri_box.showSaveDialog(this);

   /*Stringa che conterra' il percorso del file da salvare*/
   String file_in_cui_salvare = apri_box.getSelectedFile().getPath();
   /*Stringa che conterra' il testo dell'area di editing*/
   String da_salvare = AreaEditing.getText();

   /*Blocco try...catch che effettivamente scrive il file su disco*/
   try
   {
     /*Istanziamo un FileWriter e gli diciamo DOVE salvare.
     Successivamente gli diciamo COSA salvare con il metodo
     write() i cui argomenti sono: la stringa da salvare, il punto da
     cui iniziare a salvare e quello dove smettere. Nel nostro caso
     Vogliamo salvare tutto quindi andiamo da zero fino alla fine
     della stringa (ovvero all'intero che indica la sua lunghezza)*/
     FileWriter salvataggio = new FileWriter(file_in_cui_salvare);
     salvataggio.write(da_salvare, 0, AreaEditing.getText().length());

     /*Chiudo il FileWriter*/
     salvataggio.close();
    }
   catch(IOException e)
  {
   //Semplicemente mostra l'eccezione
   JOptionPane.showMessageDialog(null, e);}
  }
  //Fine funzione_salva()



  public void leggi()
  {
   /*Creiamo il solito FileChooser, lo mostriamo e assegnamo
     alla stringa il percorso del file da aprire che abbiamo scelto*/

  JFileChooser apri_box = new JFileChooser();
  apri_box.showOpenDialog(this);
  String file_da_aprire = apri_box.getSelectedFile().getPath();

  /*Leggiamo il contenuto del file aperto e lo mandiamo all'area
    di editing*/
  try
  {
   FileReader lettore = new FileReader(file_da_aprire);
   int inByte = 0;

   /*Stringa che conterra' il contenuto parziale del file
     via via che viene letto*/
   String appoggio = "";

   /*Il do...while legge un byte alla volta dal file (quindi un
     carattere alla volta) e lo appende alla stringa di
     appoggio finche' il valore di inByte non e' -1, che
     indica la fine del file. Se siamo arrivati in fondo,
     si chiude il lettore e si invia il contenuto della
     stringa di appoggio all'area di editing*/
   do
    {
     try{
     inByte = lettore.read();
        }
     catch(IOException e)
     { JOptionPane.showMessageDialog(null, e);
     }

     if (inByte != -1)
     appoggio+=(char)inByte;
    }
    while (inByte != -1);

    AreaEditing.setText(appoggio);

    try {
    lettore.close();
       }
     catch(IOException e)
     { JOptionPane.showMessageDialog(null, e);
     }
   }

  catch (FileNotFoundException e)
  {
   JOptionPane.showMessageDialog(null, e);
   }
   //Fine blocco principale try...catch

   }  //Fine leggi()


}



Per questa volta la lezione è finita e per la prossima vi anticipo che, usando come base il programma qui sopra, daremo uno sguardo ai MouseListener per creare una statusbar al nostro programma! Alla prossima...

Prossima pagina

Indice Webdesign