Gestori di layout Un gestore di layout è una classe che stabilisce in quale modo i componenti devono essere disposti, quando vengono aggiunti ad un contenitore. Le istanze delle classi JFrame e JPanel sono create rispettivamente con i seguenti gestori di layout predefiniti: • BorderLayout; • FlowLayout. BorderLayout e FlowLayout sono sottoclassi dirette della superclasse cosmica Object e appartengono al package java.awt.
Obj ect
BorderLayout
FlowLayout
Layout dei frame: BorderLayout Ogni istanza della classe JFrame è suddivisa in cinque aree, denominate NORTH, SOUTH, EAST, WEST, CENTER.
Barra del titolo NORTH
WEST
CENTER
EAST
SOUTH
Quando si aggiunge un componente (tipicamente un pannello) al pannello del contenuto del frame, è possibile indicare in quale delle cinque aree caricarlo. A tal scopo si usa il seguente metodo della classe Container:
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
1
public Component add(Component comp, Object vincoli) Aggiunge il componente comp al contenitore secondo i vincoli rappresentati dal parametro vincoli. Il parametro vincoli può coincidere con una delle seguenti costanti simboliche della classe BorderLayout1: •
-
public public public public public
static static static static static
final final final final final
String String String String String
NORTH SOUTH EAST WEST CENTER
All'interno di ogni area è possible aggiungere un solo componente.
Esempio L'istruzione contentPane.add(panel, BorderLayout.NORTH); aggiunge il pannello panel nell'area NORTH del contenitore contentPane. Se non si specifica dove caricare il componente, l'area predefinita è CENTER.
Costruttori della classe BorderLayout public BorderLayout() Crea un gestore di layout senza spazi tra i componenti. •
public BorderLayout(int hgap, int vgap) Crea un gestore di layout con gli spazi specificati tra i componenti. Lo spazio orizzontale è denotato con hgap; quello verticale con vgap. •
Nota: Quando si crea una istanza della classe JFrame, non è necessario creare esplicitamente un'istanza di BorderLayout poichè ciò avviene automaticamente.
Esempio: frame con cinque pannelli colorati Il codice seguente crea un frame contenente 5 pannelli di diversi colori, disposti nelle 5 aree determinate dal layout manager di default. Il frame generato è mostrato in figura 1. import import import import import
java.awt.BorderLayout; java.awt.Color; java.awt.Container; javax.swing.JFrame; javax.swing.JPanel;
public class CreaFrame { 1
In realtà esistono altre costanti che sono consultabili alla pagina http://docs.oracle.com/javase/7/docs/api/java/awt/BorderLayout.html, ma quelle indicate sono sufficienti per i nostri scopi. Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
2
public static void main(String[] args) { final int LARGHEZZA= 300; final int ALTEZZA = 150; final int ASCISSA = 100; final int ORDINATA = 100; final String TITOLO = "Frame con 5 pannelli colorati"; //crea il frame JFrame aframe = new JFrame(TITOLO); aframe.setSize(LARGHEZZA, ALTEZZA); aframe.setLocation(ASCISSA, ORDINATA); aframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //crea JPanel JPanel JPanel JPanel JPanel
i pannelli nPanel = new wPanel = new ePanel = new sPanel = new cPanel = new
JPanel(); JPanel(); JPanel(); JPanel(); JPanel();
//colora i pannelli nPanel.setBackground(Color.YELLOW); wPanel.setBackground(Color.WHITE); ePanel.setBackground(Color.GREEN); sPanel.setBackground(Color.BLUE); cPanel.setBackground(Color.RED); //aggiunge i pannelli al contentPane Container contentPane = aframe.getContentPane(); contentPane.add(nPanel, BorderLayout.NORTH); contentPane.add(wPanel, BorderLayout.WEST); contentPane.add(ePanel, BorderLayout.EAST); contentPane.add(sPanel, BorderLayout.SOUTH); contentPane.add(cPanel, BorderLayout.CENTER); //visualizza il frame aframe.setVisible(true); } }
Figura 1 - Frame con 5 pannelli disposti nelle 5 aree disponibili
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
3
Layout dei pannelli: FlowLayout Il gestore di layout FlowLayout consente di inserire i componenti in un contenitore da sinistra verso destra, come avviene per le linee di un testo. Quando una linea è piena, va a capo. I componenti che si trovano su una linea vengono centrati, per default.
Costruttori della classe FlowLayout public FlowLayout() Crea un'istanza di FlowLayout con un allineamento centrale per i componenti e uno spazio orizzontale/verticale tra i componenti di 5 unità. •
public FlowLayout(int align) Crea un'istanza di FlowLayout con l'allineamento specificato da align per i componenti e uno spazio orizzontale/verticale tra i componenti di 5 unità. •
public FlowLayout(int align, int hgap, int vgap) Crea un'istanza di FlowLayout con l'allineamento specificato da align per i componenti e uno spazio orizzontale/verticale indicato rispettivamente da hgap e vgap. •
Le costanti utilizzate per indicare l'allineamento, sono così definite 2: − − −
public static final int LEFT public static final int CENTER public static final int RIGHT
Esempio: pannello con 2 pulsanti Il codice seguente mostra come vengono disposti due pulsanti all’interno di una istanza di JPanel, che ha un flow layout come layout manager di default. La ui generata è visibile in figura 2. import import import import
java.awt.Container; javax.swing.JButton; javax.swing.JFrame; javax.swing.JPanel;
public class CreaFrame { public static void main(String[] args) { final int LARGHEZZA= 300; final int ALTEZZA = 150; final int ASCISSA = 100; final int ORDINATA = 100; final String TITOLO = "Frame con pannello e 2 pulsanti"; //crea il frame JFrame aframe = new JFrame(TITOLO); aframe.setSize(LARGHEZZA, ALTEZZA); 2
In realtà esistono altre costanti che sono consultabili alla pagina http://docs.oracle.com/javase/7/docs/api/java/awt/FlowLayout.html, ma quelle indicate sono sufficienti per i nostri scopi. Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
4
aframe.setLocation(ASCISSA, ORDINATA); aframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //crea il pannello JPanel panel = new JPanel(); //crea i due pulsanti JButton button1 = new JButton("button1"); JButton button2 = new JButton("button2"); //aggiunge i pulsanti al pannello panel.add(button1); panel.add(button2); //aggiunge il pan nello al contentPane Container contentPane = aframe.getContentPane(); contentPane.add(panel); //visualizza il frame aframe.setVisible(true); } }
Figura 2 - Frame con 2 pulsanti inseriti in un pannello
Cambiare il gestore di layout predefinito E' possibile modificare il gestore di layout predefinito mediante il metodo setLayout della classe Container: public void setLayout(LayoutManager mgr) Imposta il gestore di layout a mgr. •
Esempio Per cambiare il gestore di layout di una finestra frame da BorderLayout a FlowLayout, è sufficiente scrivere: frame.setLayout(new FlowLayout()); Viceversa, per cambiare il gestore di layout di un pannello panel da FlowLayout a BorderLayout, si scriverà: panel.setLayout(new BorderLayout()); Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
5
Non utilizzare un gestore di layout Talvolta può essere utile o necessario non servirsi di un gestore di layout, per poter collocare un componente in una posizione "assoluta". In casi come questo occorre: 1. annullare ogni gestore di layout, passando come parametro al metodo setLayout il valore null; 2. specificare la posizione e la dimensione del componente, utilizzando il metodo setBounds.
Esempio Consideriamo il frame di figura 2 e posizioniamo i pulsanti in modo assoluto. import import import import
java.awt.Container; javax.swing.JButton; javax.swing.JFrame; javax.swing.JPanel;
public class CreaFrame { public static void main(String[] args) { final int LARGHEZZA= 300; final int ALTEZZA = 150; final int ASCISSA = 100; final int ORDINATA = 100; final String TITOLO = "Frame con posizionamento assoluto"; //crea il frame JFrame aframe = new JFrame(TITOLO); aframe.setSize(LARGHEZZA, ALTEZZA); aframe.setLocation(ASCISSA, ORDINATA); aframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //crea il pannello JPanel panel = new JPanel(); //crea i due pulsanti JButton button1 = new JButton("button1"); JButton button2 = new JButton("button2"); //aggiunge i pulsanti al pannello in posizione assoluta panel.setLayout(null); panel.add(button1); panel.add(button2); button1.setBounds(0,0,100,50); button2.setBounds(100,50,100,50); //aggiunge il pan nello al contentPane Container contentPane = aframe.getContentPane(); contentPane.add(panel); //visualizza il frame aframe.setVisible(true); Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
6
} } Il frame generato è visibile in figura 3.
Figura 3 - Frame con posizionamento assoluto di componenti
Occorre considerare che il posizionamento assoluto può non essere la scelta migliore poiché i componenti, in tal caso, rimangono in posizione fissa anche quando il frame viene ridimensionato dall’utente.
BoxLayout Il BoxLayout inserisce i componenti orizzontalmente o verticalmente in un’unica riga o colonna. La classe è dotata di un solo costruttore:
• public BoxLayout(Container target, int axis) − target è il contenitore a cui si vuole applicare il layout; − axis è l’asse lungo il quale organizzare i componenti e può assumere come valore
una delle seguenti costanti intere della classe BoxLayout: − X_AXIS, dispone i componenti lungo l’asse X da sinistra a destra; − Y_AXIS, dispone i componenti lungo l’asse Y dall’alto verso il basso; − LINE_AXIS, dispone i componenti nella direzione di una riga di testo, in base alle proprietà di orientamento del componente che li contiene; PAGE_AXIS, dispone i componenti nella direzione del flusso delle linee di una pagina, in base alle proprietà di orientamento del componente che li contiene.
Chiariamo meglio il significato di LINE_AXIS e PAGE_AXIS. LINE_AXIS significa che se il contenitore ha proprietà di orientamento orizzontale/verticale, i componenti sono disposti orizzontalmente/verticalmente. Nel caso di orientamento verticale, i componenti sono sempre disposti dall’alto verso il basso. Nel caso di orientamento orizzontale, se il contenitore ha un orientamento da sinistra a destra, i componenti vengono disposti da sinistra a destra, altrimenti vengono disposti da destra a sinistra. PAGE_AXIS significa che se il contenitore ha proprietà di orientamento orizzontale, i componenti sono disposti verticalmente, altrimenti sono disposti orizzontalmente. Nel caso di orientamento verticale, i componenti sono sempre disposti dall’alto verso il basso. Nel caso di orientamento orizzontale, se il contenitore ha un orientamento da
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
7
sinistra a destra, i componenti vengono disposti da sinistra a destra, altrimenti vengono disposti da destra a sinistra. In ogni caso, l’ordine di visualizzazione dei componenti coincide con l’ordine di inserimento nel contenitore.
Esempio di BoxLayout Il frame dell’esempio contiene un pannello centrale, il cui layout manager è stato impostato a BoxLayout e un pannello a sud, con layout manager di default FlowLayout. Il frame creato è mostrato in figura 4.
Figura 4 - Frame con due pannelli di cui uno avente layout manager BoxLayout
import import import import import import import
java.awt.BorderLayout; java.awt.Component; java.awt.Container; javax.swing.BoxLayout; javax.swing.JButton; javax.swing.JFrame; javax.swing.JPanel;
public class CreaFrame { public static void main(String[] args) { final String TITOLO = "Esempio di BoxLayout"; //crea il frame JFrame aframe = new JFrame(TITOLO); aframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
(1)
//crea un pannello centrale con gestore di layout BoxLayout JPanel centerPanel = new JPanel(); BoxLayout centerPanelLayout = new BoxLayout(centerPanel, BoxLayout.Y_AXIS); centerPanel.setLayout(centerPanelLayout); //crea un pannello centrale con gestore di layout predefinito FlowLayout
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
8
JPanel southPanel = new JPanel();
(2)
//crea e aggiunge tre pulsanti al pannello centrale con allineamento centrato JButton button = new JButton("button"); button.setAlignmentX(Component.CENTER_ALIGNMENT); JButton shortButton = new JButton("short"); shortButton.setAlignmentX(Component.CENTER_ALIGNMENT); JButton longButton = new JButton("long-long - long button"); longButton.setAlignmentX(Component.CENTER_ALIGNMENT); centerPanel.add(button); centerPanel.add(shortButton); centerPanel.add(longButton); //crea e aggiunge due pulsanti al pannello sud JButton okButton = new JButton("OK"); JButton cancelButton = new JButton("Cancel"); southPanel.add(okButton); southPanel.add(cancelButton); //aggiunge i pannelli al contentPane Container contentPane = aframe.getContentPane(); contentPane.add(centerPanel, BorderLayout.CENTER); contentPane.add(southPanel, BorderLayout.SOUTH);
}
//visualizza il frame aframe.pack(); aframe.setVisible(true);
} (1) - Si osservi che non per impostare il layout manager di un pannello a BoxLayout occorre prima creare una istanza di BoxLayout: BoxLayout centerPanelLayout = new BoxLayout(centerPanel, BoxLayout.Y_AXIS) e solo successivamente impostare il layout manager del pannello con il metodo setLayout: centerPanel.setLayout(centerPanelLayout). Non è possibile, invece, usare la forma abbreviata: JPanel centerPanel = new JPanel(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); perché il parametro centerPanel di BoxLayout coincid con l’istanza del pannello che si sta creando. e questo genera un errore in fase di compilazione. (2) - Il codice presente in questa sezione crea i pulsanti da inserire nel pannello con BoxLayout e ne imposta un allineamento centrato.
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
9
La classe Box La classe Box consente di creare pannelli che hanno come layout manager di default il BoxLayout, invece del FlowLayout. La classe Box ha un solo costruttore:
• public Box (int axis) Crea un Box che visualizza i suoi componenti lungo l’asse specificato. Il parametro axis può essere una delle costanti intere di BoxLayout: X-AXIS, Y_AXIS, LINE_AXIS, PAGE_AXIS. Metodi utili della classe Box Per migliorare l’allineamento dei componenti, la classe Box consente di creare alcuni tipi di componenti invisibili che fungono da riempitivo (filler) per le zone che si vogliono mantenere vuote. I componenti invisibili sono di tre tipi: rigid area, struts e glue. Esamineremo solo rigid area e glue, poiché l’uso di struts è sconsigliato.
• public static Component createRigidArea (Dimension d) Crea un componente invisibile che mantiene sempre la stessa dimensione d. Tale componente è da utilizzare quando si vuole mantenere uno spazio di dimensione fissa tra altri due componenti. Per esempio, se si vuole inserire uno spazio vuoto di 5 pixel tra due componenti di un box con orientamento orizzontale da sinistra a destra, occorre scrivere: container.add(firstComponent); container.add(Box.createRigidArea(new Dimension(5,0))); container.add(secondComponent); Un oggetto Dimension3 incapsula la larghezza e l’altezza di un componente. Larghezza e altezza sono numeri interi. La figura 5 mostra qual è l’effetto dell’utilizzo di una rigid area.
Figura 5 - Utilizzo di una rigid area per separare due componenti Immagine tratta da http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html
• public static Component createGlue () Crea un componente invisibile che si può espandere, nel modo ritenuto più opportuno, per occupare lo spazio vuoto interno a un contenitore. 3
Si veda http://docs.oracle.com/javase/7/docs/api/java/awt/Dimension.html
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
10
• public static Component createHorizontalGlue () Dispone lo spazio vuoto orizzontale, che in condizioni normali si troverebbe alla destra dei componenti, tra i due componenti stessi. La figura 6 mostra l’effetto dell’utilizzo di tale componente.
Figura 6 - Utilizzo di un componente glue per separare due componenti Immagine tratta da http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html
Il codice necessario per creare uno spazio vuoto come quello di figura 6 è: container.add(firstComponent); container.add(Box.createHorizontalGlue()); container.add(secondComponent);
• public static Component createVerticalGlue ()
Dispone lo spazio vuoto verticale, che in condizioni normali si troverebbe sotto i componenti, tra i due componenti stessi.
La classe Box.Filler Nel caso in cui nessuna delle soluzioni proposte sia utilizzabile, è possibile creare uno spazio vuoto personalizzato con la classe Box.Filler, utilizzando il seguente costruttore:
• public Box.Filler (Dimension min, Dimension pref, Dimension max) Crea un componente invisibile con le dimensioni minime (min), preferite (pref) e massime (max) specificate. Il codice seguente crea uno spazio vuoto tra due componenti di larghezza minima e preferita pari a 5 pixel e di larghezza massima pari al massimo valore Short (2 15-1). L’altezza è invece impostata a 100. container.add(firstComponent); Dimension minSize = new Dimension(5, 100); Dimension prefSize = new Dimension(5, 100); Dimension maxSize = new Dimension(Short.MAX_VALUE, 100); container.add(new Box.Filler(minSize, prefSize, maxSize)); container.add(secondComponent); La figura 7 mostra l’effetto prodotto dal codice.
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
11
Figura 7 - Utilizzo di un componente Box.Filler per separare due componenti Immagine tratta da http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html
Esempio di Box e Box.filler Il frame dell’esempio contiene tre pannelli: un pannello a nord con due pulsanti separati da una rigid area, un pannello centrale con due pulsanti separati da un glue orizzontale e un pannello a sud con due pulsanti separati da un box filler. Il frame creato è mostrato in figura 8. import import import import import import import
java.awt.BorderLayout; java.awt.Container; java.awt.Dimension; javax.swing.Box; javax.swing.JButton; javax.swing.JFrame; javax.swing.JPanel;
public class CreaFrame { public static void main(String[] args) { final String TITOLO = "Esempio di Box e Box.Filler"; //crea il frame JFrame aframe = new JFrame(TITOLO); aframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
0)));
//esempio di rigid area JPanel northPanel = new JPanel(); JButton button1 = new JButton("button 1"); JButton button2 = new JButton("button 2"); northPanel.add(button1); northPanel.add(Box.createRigidArea(new Dimension(50, northPanel.add(button2); //esempio di glue JPanel centerPanel = new JPanel(); JButton button3 = new JButton("button 3");
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
12
JButton button4 = new JButton("button 4"); centerPanel.add(button3); centerPanel.add(Box.createHorizontalGlue()); centerPanel.add(button4); //esempio di box filler JPanel southPanel = new JPanel(); JButton button5 = new JButton("button 5"); JButton button6 = new JButton("button 6"); southPanel.add(button5); Dimension minSize = new Dimension(20, 100); Dimension prefSize = new Dimension(20, 100); Dimension maxSize = new Dimension(Short.MAX_VALUE, 100); southPanel.add(new Box.Filler(minSize, prefSize, maxSize));
southPanel.add(button6); //aggiunge i pannelli al contentPane Container contentPane = aframe.getContentPane(); contentPane.add(northPanel, BorderLayout.NORTH); contentPane.add(centerPanel, BorderLayout.CENTER); contentPane.add(southPanel, BorderLayout.SOUTH); //visualizza il frame aframe.pack(); aframe.setVisible(true);
}
}
Figura 8 - Frame con componenti separati da componenti invisibili
La classe GridLayout Il GridLayout inserisce i componenti in una griglia le cui celle hanno tutte la stessa dimensione. Ogni componente occupa tutto il contenuto della cella in cui si trova. I costruttori sono tre:
Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
13
• public GridLayout()
Crea una griglia con una sola colonna e una sola riga.
• public GridLayout(int rows, int cols)
Crea una griglia con il numero di righe (rows) e colonne (cols) specificato.
• public GridLayout(int rows, int cols, int hgap, int vgap)
Crea una griglia con il numero di righe e colonne specificato e definisce lo spazio orizzontale (hgap) e verticale (vgap) tra le celle.
Le celle della griglia sono indicizzate con una numerazione progressiva che parte da 1 e prosegue da sinistra a destra a partire dall’alto. Per esempio, una griglia di 3 righe e 2 colonne avrà le celle così indicizzate:
1
2
3
4
5
6
I componenti vengono inseriti seguendo l’ordinamento degli indici delle celle.
Esempio di GridLayout L’esempio crea in layout a griglia con due colonne e due righe, come mostrato in figura 9. import java.awt.Container; import java.awt.GridLayout; import javax.swing.JButton; import javax.swing.JFrame; public class CreaFrame { public static void main(String[] args) { final String TITOLO = "Esempio di GridLayout"; //crea il frame JFrame aframe = new JFrame(TITOLO); Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
14
aframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //imposta il layout del contentPane a GridLayout Container contentPane = aframe.getContentPane(); contentPane.setLayout(new GridLayout(2,2)); //crea i pulsanti e li inserisce nella griglia 2x2 contentPane.add(new JButton("1")); contentPane.add(new JButton("2")); contentPane.add(new JButton("3")); contentPane.add(new JButton("4")); //visualizza il frame aframe.pack(); aframe.setVisible(true); }
}
Figura 9 - Frame con GridLayout
Altri layout manager Altri gestori di layout più complessi sono: • GridBagLayout, • CardLayout, • GroupLayout, • SpringLayout. Maggiori dettagli si possono trovare all’url http://download.oracle.com/javase/tutorial/uiswing/layout/visual.html#card. Inoltre, è sempre possibile creare un layout personalizzato, anche se il compito non è banale. Un esempio di layout personalizzato dal nome FormLayout è visibile all’url http://www.pdfcoke.com/doc/29332215/Esercizio7-Gui-Prenotazioni-Soluzione
_______________________________________________________________ Quest'opera è stata rilasciata con licenza Creative Commons Attribution-ShareAlike 3.0 Unported. Per leggere una copia della licenza visita il sito web http://creativecommons.org/licenses/by-sa/3.0/ o spedisci una lettera a Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. Bocchi Cinzia Ultimo aggiornamento: 01/02/2013
15