MokaByte 50 - Marzo 2001
Foto dell'autore non disponibile
di
Andrea Gini
Corso di Swing 
VII parte: i controlli JFileChooser e JTextArea
 
Un file chooser e' un oggetto grafico che permette di navigare il file system e di selezionare uno o piu' file su cui eseguire una determinata operazione. Qualunque applicazione grafica ne utilizza uno per facilitare le operazioni su disco. JFileChooser offre questa funzionalita' attraverso una accessoriata finestra modale.
 
 


Figura 1 - Un esempio di JFileChooser 

Possiamo creare un'istanza di JFileChooser utilizzando questi costruttori:

  • JFileChooser() :crea un JFileChooser che punta alla home directory dell'utente. 
  • JFileChooser(File currentDirectory): crea un JFileChooser che punta alla directory specificata dal parametro.


Per visualizzare un JFileChooser possiamo ricorrere alla seguente coppia di metodi, che restituiscono un intero:

  • int showOpenDialog(Component parent): visualizza un JFileChooser per apertura file.
  • int showSaveDialog(Component parent): visualizza un JFileChooser per salvataggio file. 
l'intero che viene restituito puo' assumere uno di questi tre valori: 
  • JFileChooser.CANCEL_OPTION 
  • JFileChooser.APPROVE_OPTION 
  • JFileCHooser.ERROR_OPTION
il programmatore puo' decidere cosa fare dei files selezionati basandosi su queste risposte.
Entrambi i metodi richiedono inoltre che venga passato come parametro un componente: di norma si passa un reference al JFrame principale, che verra' bloccato per tutta la durata dell'operazione. Passando null come parametro, il JFrame verra' visualizzato al centro dello schermo e risultera' indipendente dalle altre finestre.Per conoscere il risultato dell'interrogazione possiamo usare i seguenti metodi:
  • File getCurrentDirectory(): restituisce la directory corrente
  • File getSelectedFile(): restituisce il file selezionato. 
  • void setCurrentDirectory(File dir): imposta la directory di lavoro. 
  • void setSelectedFile(File file): imposta il file selezionato. 


Alcuni metodi permettono un uso piu' avanzato di JFileChooser:

  • void setDialogTitle(String dialogTitle): imposta il titolo del JFileChooser.
  • void setFileSelectionMode(int mode): permette di abilitare il JFileChooser a selezionare solo files, solo directory o entrambe, utilizzando come parametro uno dei seguenti valori:
  • JFileChooser.FILES_ONLY 
  • JFileChooser.DIRECTORIES_ONLY 
  • JFileChooser.FILES_AND_DIRECTORIES 
  • void setMultiSelectionEnabled(boolean b): abilita o disabilita la possibilita' di selezionare piu' di un file per volta. In questo caso, per interrogare lo stato, si ricorrera' ai seguenti metodi:
    • void setSelectedFiles(File[] selectedFiles): imposta come "selezionati" il gruppo di files passati come parametro.
    • File[] getSelectedFiles(): restituisce un vettore contenente i files selezionati dall'utente.


Nelle seguenti righe vediamo una tipica procedura che fa uso di JFileChooser; nel prossimo paragrafo illustreremo un uso pratico di questo componente all'interno di un'applicazione.

class MyFrame extends JFrame {
....
  fileChooser = new JFileChooser();
  int response = fileChooser.showOpenDialog(this);
  if(response==JFileChooser.APPROVE_OPTION) {
      File f = fileChooser.getSelectedFile();
      // qui viene eseguita l'operazione sul file
  }
....
}
 
 
 

JTextArea
Il package Swing dispone di un insieme completo di componenti grafici per il trattamento di testi: JTextComponent, JTextField, JPasswordField, JTextArea, JEditorPane, JTextPane. 
Il primo componente dell'elenco e' la superclasse astratta da cui discendono tutti gli altri Text Component: esso definisce l'interfaccia di programmazione e una prima implementazione di  tutte le funzionalita' normalmente presenti su editor di testo, come ad esempio la possibilita' inserire caratteri da tastiera; quella di spostare il cursore in qualunque punto del documento utilizzando il mouse o i tasti cursore; la possibilita' di operare selezioni su gruppi contigui di caratteri al fine di eseguire su di essi una qualunque operazione di editing nonche' i metodi per operare sulla clipboard di sistema (che permette di copiare ed incollare testi anche tra programmi java e programmi nativi)  e quelli per leggere il documento da uno stream di input o per inviarlo ad uno di output.
Nei paragrafi precedenti abbiamo analizzato il funzionamento di JTextField, un componente che permette di editare una singola riga di testo; ora ci occuperemo di JTextArea, un oggetto grafico da utilizzare quando si intende lavorare su testi di lunghezza media, con l'unica limitazione di permettere l'utilizzo di un unico carattere, un unico stile ed un unico colore per tutto il documento.
Nei casi in cui si desideri lavorare su documenti complessi, senza subire limiti nella scelta di font, stile o dimensioni, e' possibile utilizzare JEditorPane e JTextPane, oggetti grafici che permettono di lavorare su formati testo come RTF o HTML e con la possibilita' aggiuntiva di arricchire i testi con immagini o componenti attivi. La complessita' di questa coppia di componenti impedisce una trattazione in questa sede (essi richiederebbero un libro a se stante); uno sguardo approfondito a JTextArea sara' comunque piu' che sufficiente per rompere il ghiaccio con questa famiglia di componenti.
 
 

JTextArea API
La via piu' breve per creare una JTextArea e' attraverso il costruttore privo di parametri; altri costruttori permettono di specificare il numero di righe e di colonne e la composizione iniziale del testo. E' importante ricordare che JTextArea, al contrario del suo equivalente AWT, non dispone di barre laterali di scorrimento; per questa ragione e' indispensabile, all'atto della sua creazione, inserirlo dentro un JScrollPane, come si puo' vedere nelle righe successive

  ...
  JTextArea ta = new JTextArea();
  JScrollPane scroll = new JScrollPane(ta);
  getContentPane().add(BorderLayout.CENTER,scroll);
  ...
 

  • JTextArea(): Crea una JTextArea
  • JTextArea(String text, int rows, int columns): crea una JTextArea con il testo specificato dalla stringa text, e le dimensioni specificate dai parametri rows e columns.


Possiamo editare il testo nel componente direttamente con la tastiera e il mouse, o da programma ricorrendo ad alcuni metodi. Questi metodi richiedono come parametro un valore intero, che specifica la posizione del cursore rispetto all'inizio del documento: se la nostra text area contenesse nella prima riga la frase "La vispa Teresa" e nella seconda "avea tra l'erbetta", potremmo dire che la parola "Teresa" e' compresa tra gli offset 9 e 15, mentre "erbetta" si trova tra gli indici 27 e 34 (contando anche il ritorno carrello).

  • void setText(String t): cancella il precedente contenuto del componente e lo rimpiazza con la stringa specificata.
  • String getText(): restituisce il testo contenuto all'interno del componente.
  • String getText(int offs, int len): restituisce il testo che parte dalla posizione  specificata dal primo parametro, della lunghezza specificata dal secondo. 
  • void insert(String str, int pos): inserisce il testo contenuto nella stringa nella posizione specificata dal parametro.
  • void append(String str): inserisce il contenuto della stringa in coda al documento.
  • void replaceRange(String str, int start, int end): rimpiazza la sezione di testo compresa tra start ed end con la stringa specificata.
In alternativa possiamo inizializzare il componente a partire da uno stream.
  • void read(Reader in, Object desc): legge il testo da uno stream (il secondo parametro puo' essere messo a null)
  • void write(Writer out): salva il testo su uno stream.


Un gruppo di metodi permette di conoscere la posizione attuale del cursore ed eventualmente modificarla: tra questi metodi ci sono anche quelli che permettono di operare selezioni, ovvero di mettere in evidenza una porzione di testo contigua, indicandone l'inizio e la fine. 
 

  • int getCaretPosition(): restituisce la posizione del cursore a partire dall'inizio del documento.
  • void setCaretPosition(int position): sposta il cursore alla posizione specificata.
  • void moveCaretPosition(int pos) : muove il cursore fino alla posizione specificata, evidenziando il testo tra la nuova posizione e quella precedente.
  • void select(int selectionStart, int selectionEnd) : seleziona il testo situato tra la posizione iniziale e quella finale specificate dai parametri.
  • String getSelectedText(): restituisce il testo contenuto nella selezione.
  • void replaceSelection(String content): rimpiazza l'attuale selezione con il testo contenuto nella stringa.
  • int getSelectionStart(): restituisce il punto di inizio della selezione
  • int getSelectionEnd() : restituisce il punto finale della selezione


Possiamo operare sulla clipboard di sistema attraverso i metodi 

  • void copy()
  • void cut()
  • void paste()
  • void selectAll()


Infine possiamo impostare con i seguenti metodi alcune importanti proprieta'

  • void setFont(Font font) : imposta il font 
  • void setForeground(Color fg) : imposta il colore del testo
  • void setBackground(Color bg) : imposta il colore dello sfondo
  • void setEditable(boolean b) : imposta il componente come editabile o non editabile.
Sviluppare un'applicazione grafica complessa
Le nozioni apprese fino ad ora permettono di affrontare lo studio di un'applicazione grafica di una discreta complessita'. Le seguenti righe permettono di realizzare un piccolo editor di testo perfettamente funzionante, utilizzando JTextArea, una JToolBar, una JMenuBar, un JFileChooser e mostrando un utilizzo pratico delle Action. Viene inoltre illustrato, all'interno dei metodi loadText() e  saveText(), come sia possibile inizializzare un Text Component a partire da un file su disco. 


Figura 2 - Con appena un centinaio di righe e' possibile 
realizzare un utile text editor

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

public class TextEditor extends JFrame {
  private JTextComponent editor;
  private JFileChooser fileChooser;
  protected Action loadAction;
  protected Action saveAction;
  protected Action cutAction;
  protected Action copyAction;
  protected Action pasteAction;
  public TextEditor() {
    super("TextEditor");
    setSize(300,300);
    createActions(); 
    JMenuBar menuBar = createMenuBar();
    JToolBar toolbar = createToolBar();
    editor = createEditor();
    JComponent centerPanel = createCenterComponent();
    getContentPane().add(BorderLayout.NORTH,toolbar);
    getContentPane().add(BorderLayout.CENTER,centerPanel);
    setJMenuBar(menuBar);
    fileChooser = new JFileChooser();
    setVisible(true); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 }
  protected void createActions() {
    loadAction = new AbstractAction("Open", new ImageIcon("Open24.gif")) {
      public void actionPerformed(ActionEvent e) {
        loadText();
      }
    };
    saveAction = new AbstractAction("Save", new ImageIcon("Save24.gif")) {
      public void actionPerformed(ActionEvent e) {
        saveText();
      }
    }; 
    cutAction = new AbstractAction("Cut", new ImageIcon("Cut24.gif")) {
      public void actionPerformed(ActionEvent e) {
        editor.cut();
      }
    }; 
    copyAction = new AbstractAction("Copy", new ImageIcon("Copy24.gif")) {
      public void actionPerformed(ActionEvent e) {
        editor.copy();
      }
    }; 
    pasteAction = new AbstractAction("Paste", new ImageIcon("Paste24.gif")) {
      public void actionPerformed(ActionEvent e) {
        editor.paste();
      }
    }; 
  }
  protected JToolBar createToolBar() {
    JToolBar tb = new JToolBar();
    tb.add(loadAction);
    tb.add(saveAction);
    tb.addSeparator();
    tb.add(cutAction);
    tb.add(copyAction);
    tb.add(pasteAction);
    return tb;
  }
  protected JMenuBar createMenuBar() {
    JMenu menu = new JMenu("Menu");
      menu.add(loadAction);
      menu.add(saveAction);
      menu.addSeparator();
      menu.add(cutAction);
      menu.add(copyAction);
      menu.add(pasteAction);
    JMenuBar menuBar = new JMenuBar();
    menuBar.add(menu);
    return menuBar;
  }
  protected JComponent createCenterComponent() {
    if(editor == null)
      editor = createEditor();
    return new JScrollPane(editor);
  }
  protected JTextComponent createEditor() {
    return new JTextArea();
  }
  public void loadText() {
    int response = fileChooser.showOpenDialog(this);
    if(response==JFileChooser.APPROVE_OPTION) {
      try {
        File f = fileChooser.getSelectedFile();
        Reader in = new FileReader(f);
        editor.read(in,null);
        setTitle(f.getName());
      }
      catch(Exception e) {}
    }
  }
  public void saveText() {
    int response = fileChooser.showSaveDialog(this);
    if(response==JFileChooser.APPROVE_OPTION) {
      try {
        File f = fileChooser.getSelectedFile();
        Writer out = new FileWriter(f);
        editor.write(out);
        setTitle(f.getName());
      }
      catch(Exception e) {}
    }
  }
  public static void main(String argv[]) {
    TextEditor t = new TextEditor();
  }
}

Il metodo createActions() riesce a definire cinque classi in appena trenta righe di codice facendo uso delle classi anonime. L'uso di classi anonime in questo contesto e' giustificato dal desiderio di rendere il programma molto compatto; su progetti di dimensioni maggiori, si consiglia comunque di ricorrere al piu' chiaro costrutto delle classi interne.
Questo programma vuole anche dare una dimostrazione di costruzione modulare di interfacce grafiche: come si puo' notare, il costruttore genera gli elementi dell'interfaccia grafica ricorrendo ad un gruppo di "metodi fabbrica" (Factory Method), ovvero metodi protected caratterizzati dal prefisso "create" (creeateToolBar(), createMenuBar(), createCenterComponent() e createEditor()). Questa scelta offre la possibilita' di creare sottoclassi del programma che implementino una differente composizione della GUI semplicemente sovrascrivendo questi metodi, e lasciando inalterato il costruttore. Se ad esempio disponessimo di un'ipotetica HTMLTextArea e volessimo creare un editor HTML, ci basterebbero appena cinque righe per adattare il nostro editor ad una nuova funzione.

public class HTMLTextEditor extends TextEditor {
  protected JTextComponent createEditor() {
    return new HTMLTextArea();
  }
}

In uno dei prossimi paragrafi verra' presentato un esempio concreto che permettera' di apprezzare i vantaggi di questa scelta di progettazione.
 
 
 

Conclusioni
Con questo articolo si conclude la panoramica sui componenti grafici presenti in Swing. Le conoscenze maturate dall'inizio del corso ci hanno finalmente permesso di illustrare la costruzione di un'applicazione grafica semplice, compatta e funzionale. Vi invito a sperimentare delle soluzioni personali, utilizzando quanto appreso fino ad ora o modificando gli esempi presentati: quest'ultima attivita' e' sicuramente la via migliore per impratichirsi nella stesura del codice.
Nel prossimo articolo affronteremo lo studio di alcuni contenitori specializzati: JSplitPane, JTabbedPane e JDesktopPane.

Gli esempi descritti nell'articolo possono essere scaricati qui

Vai alla Home Page di MokaByte
Vai alla prima pagina di questo mese


MokaByte®  è un marchio registrato da MokaByte s.r.l.
Java®, Jini®  e tutti i nomi derivati sono marchi registrati da Sun Microsystems; tutti i diritti riservati
E' vietata la riproduzione anche parziale
Per comunicazioni inviare una mail a
mokainfo@mokabyte.it