INTERFACCE GRAFICHE IN JAVA CON SWING - DISPENSE
←
→
Trascrizione del contenuto della pagina
Se il tuo browser non visualizza correttamente la pagina, ti preghiamo di leggere il contenuto della pagina quaggiù
INTERFACCE GRAFICHE IN JAVA CON SWING DISPENSE
INTRODUZIONE L’interfaccia grafica del programma è composta dai cosiddetti componenti GUI (Graphics User Interface); essi sono dei componenti che servono per l’input o per l’output, ed hanno un aspetto grafico (esempio: menù, i bottoni, le label, ecc). Tutti questi componenti saranno inserite in un contenitore principale che mi rappresenta la finestra; questo è chiamato Frame. Per questo le applicazioni con un'interfaccia grafica le chiameremo applicazioni “a finestre”. Ogni GUI è quindi un pezzettino di interfaccia grafica; essi ricevono degli eventi e in base a questi danno dei risultati. Esempio: un bottone, esso può essere cliccato; il click è un evento sulla componente bottone; saremo noi poi che dovremo gestire questo evento, ovvero si dovrà dire cosa succede quando il bottone viene cliccato. Ogni GUI avrà i suoi eventi associati che vanno gestiti. Per capire quando si verifica un evento su un GUI (ese: click su un pulsante) si deve dichiarare un ascoltatore (listener) dell’evento sul GUI: il listener è un oggetto che attende il verificarsi dell’evento sul componente (GUI), e quando questo si verifica lo gestisce (indica che azioni fare). Il package SWING Per disegnare le interfacce grafiche utilizzeremo una libreria che Java mette a disposizione che è chiamata Swing. Questo significa che nella libreria Swing ci saranno le classi relative ai vari componenti GUI di cui posso creare oggetti ed usarli. Nulla mi vieta (anzi spesso è necessario in quanto le classi della libreria sono astratte) di estendere queste classi con mie sottoclassi e personalizzarle. In particolare la libreria SWING aggiunge funzionalità alla già preesistente e più vecchia libreria AWT.
Sottintendiamo quindi che importeremo sempre il pacchetto delle librerie Swing: javax.swing.* e AWT: java.awt.*. La caratteristica dell'interfaccia Swing è quella di avere contenitori e contenuti. Un contenitore è un componente Swing in grado di ospitare altri componenti. Come si vede dall'immagine precedente in realtà tutti gli elementi sono potenzialmente sia contenitori che componenti, nella pratica però utilizzeremo alcuni esclusivamente come componenti altri come contenitori. Con gli oggetti che utilizzeremo come contenitori utilizzeremo metodi ereditati dalla classe Component e per quelli utilizzati come componenti quelli della classe Content. Abbiamo in particolare che tutto il programma sarà incluso in un JFrame, ovvero una Finestra. All'interno della finestra utilizzo dei pannelli JPanel in cui andrò poi a mettere i vari componenti (pulsanti, scritte, etc). Per ogni classe contenitore e contenuto posso istanziare oggetti e settarne poi le proprietà con i relativi metodi. Mi conviene però in genere creare una mia classe che estende una di queste classi e dentro di essa settarne le proprietà. Esempio: potrei creare un oggetto della classe JFrame per creare una finestra, e poi settarne le proprietà con i metodi che tale classe mi mette a disposizione (esempio: setta il titolo, le dimensioni, la posizione). Mi conviene però definire una mia classe che fa l'extends di JFrame e dentro di se setta le suddette proprietà.
JFrame La prima cosa che bisogna fare è creare un Frame (la finestra) vuoto che poi conterrà le varie componenti. La classe della libreria Swing che bisogna utilizzare è JFrame. In particolare bisogna definire una propria classe che estende la suddetta JFrame. ESEMPIO O1 import javax.swing.*; public class Finestra extends JFrame { public Finestra( ) { //indichiamo le dimensioni della finestra setSize(300, 200); } //creamo direttamente qui un main public static void main(String [] args){ Finestra f = new Finestra(); //indica che quando si chiude la finestra deve terminare l'applicaz f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //rende visibile la finestra che di partenza è invisibile f.setVisible(true); } } Creamo quindi una classe Finestra che estende la classe JFrame. Nel costruttore Finestra( ) settiamo le dimensioni della finestra utilizzando il metodo ereditato setSize(...) che prende in input la larghezza e l'altezza. Potremmo creare ora una classe esterna Main che ci crea un oggetto del tipo Finestra appena definito. Per velocizzare definiamo però il metodo main direttamente nella classe Finestra e stesso in esso creiamo un oggetto di tipo Finestra. Creato l'oggetto, vengono utilizzati poi i metodi ereditati: – setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) – setVisible(true); Il primo indica che quando si chiude la finestra deve terminare anche l'applicazione; il secondo rende visibile la finestra (perché all'inizio è creata invisibile). Le caratteristiche di un frame La classe Frame ovviamente mette a disposizione una serie di metodi per settarne le caratteristiche. Costruttore Già a partire dal costruttore abbiamo un overload del costruttore base da parte di un costruttore che prende in input una stringa: JFrame(String titoloFinestra); Imposta tale stringa come titolo della finestra.
Altre prorietà del Frame dispose( ) chiude la finestra e rilascia le risorse del sistema utilizzate per la sua creazione. setIconImage(Image img) riceve un oggetto Image e lo utilizza come icona della finestra. setTitle(String title) modifica il titolo della finesta setResizable(boolean resizable) se riceve true come parametro rende la finestra ridimensionabile dall'utente. setSize(int width, int height) già l'abbiamo visto: setta le dimensioni della finestra. Se non viene chiamato all'inizio la finestra sarà 0x0. setLocation(int x, int y) posiziona la finestra a x pixel orizzontalmente e y pixel verticalmente dall'angolo superiore sinistro dello schermo setVisible(boolean visible) già l'abbiamo visto: se visible è true, rende visibile la finestra (che alla sua creazione è invisibile). pack( ) ridimensiona la finestra tenendo conto delle dimensioni ottimali di ciascuno dei componenti presenti all’interno. setDefaultCloseOperation(int operation) già l'abbiamo visto: imposta l’azione da eseguire alla pressione del bottone close. Operation disponibili: JFrame.DO NOTHING ON CLOSE (nessun effetto), JFrame.HIDE ON CLOSE (nasconde la finestra), JFrame.DISPOSE ON CLOSE (chiude la finestra e libera le risorse di sistema) e JFrame.EXIT ON CLOSE (chiude la finestra e conclude l’esecuzione del programma). Frame con qualche proprietà settata in più import javax.swing.*; public class Finestra extends JFrame { public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; public Finestra( ) { //chiamo il costruttore della superclasse JFrame super("La Mia Finestra"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); } public static void main(String [] args){ Finestra f = new Finestra(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } }
L'anatomia di un JFrame Per poter lavorare con i Frame Swing è opportuno conoscere in linea e generale la struttura della superficie. La superficie di un frame Swing è coperta da quattro lastre: Glass Pane: La lastra di vetro è nascosta di default ed ha il compito di catturare gli eventi di input sulla finestra. Normalmente è completamente trasparente a meno che venga implementato il metodo paintComponent del GlassPane. Poichè è davanti a tutte le altre, qualsiasi oggetto è disegnato su questa lastra nasconde qualsiasi altro è disegnato sulle altre . Content Pane: La lastra dei contenuti è la più importante perché è quella che ospita i componenti che volete visualizzare nella finestra e la maggior parte dei programmatori Java lavora solo su questa . Layered Pane: Contiene la lastra dei contenuti ed eventualmente i menu. I menu, infatti, non vengono mai aggiunti al Content Pane ma a questa lastra. Root Pane: La lastra radice ospita la lastra di vetro insieme con la lastra dei contenuti e i bordi della finestra. Quello che interessa a noi è quindi principalmente il Content Pane. Il Content Pane, come anche il JFrame stesso, estende la più generica classe Content in quanto appunto è un contenitore. Quindi la procedura da seguire è: 1) Creo un JFrame; 2) Prendo il suo Content Pane tramite l'apposito metodo getContentPane() della classe JFrame; 3) Aggiungere i vari componenti al Content Pane.
Aggiungere componeti al JFrame Come detto in precedenza non si inseriscono direttamente le componenti nel JFrame ma bisogna prendere il suo Content Pane tramite il metodo getContentPane () ed utilizzare quello. import javax.swing.*; import java.awt.*; public class Finestra extends JFrame { public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; //creo un label (un'etichetta) JLabel jl = new Jlabel("Hello!!"); public Finestra( ) { //chiamo il costruttore della superclasse JFrame super("La Mia Finestra"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); //ottengo il content pane Container c = this.getContentPane(); //aggiungo il label al content pane c.add(j1); } public static void main(String [] args){ Finestra f = new Finestra(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } } Abbiamo anticipato l'utilizzo di uno dei possibili componenti: Jlabel. Lo rivedremo in seguito, per il momento anticipiamo che non è nient'altro che un'etichetta, una stringa che è possibile visualizzare. Per aggiungere una componente abbiamo visto che è possibile utilizzare il metodo: add(Component comp) Questo metodo viene ereditato dalla classe Container e prende in input come parametro un oggetto della classe Component.
I Pannelli: JPanel Come detto in precedenza non si inseriscono direttamente le componenti nel JFrame ma bisogna prendere il suo Content Pane tramite il metodo getContentPane () ed utilizzare quello. In realtà in genere tali componenti non vengono inseriti direttamente sul Content Pane ma si creano vari contenitori, i Pannelli (identificati dalla classe JPanel) e si inseriscono in essi. Quindi in genere: 1) Creo un JFrame; 2) Prendo il suo Content Pane tramite l'apposito metodo getContentPane() della classe JFrame; 3) Creo un JPanel; 4) Inserisco gli elementi nel JPanel; 5) Aggiungo il JPanel al Content Pane del JFrame. Per i Pannelli, come per JFrame, posso creare una classe che estende la classe JPanel e faccio l'override dei suoi metodi per estenderne o personalizzare le sue funzionalità oppure creare ed utlizziare direttamente un oggetto di tipo JPanel. import javax.swing.*; import java.awt.*; public class Finestra extends JFrame { public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; //creo un label (un'etichetta) JLabel jl = new JLabel("Hello!!"); //creo un pannello Jpanel p1 = new JPanel(); public Finestra( ) { //chiamo il costruttore della superclasse JFrame super("La Mia Finestra"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); //ottengo il content pane Container c = this.getContentPane(); //aggiungo il label al pannello p1.add(jl); //aggiungo il pannello al content pane c.add(p1); } public static void main(String [] args){ Finestra f = new Finestra(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } }
LayoutManager: posizionamento dei componenti I Layout Manager sono oggetti che si occupano di gestire la strategia di posizionamento dei componenti all’interno di un contenitore. Layout Manager è in realtà un'interfaccia che va implementata. La libreria SWING fornisce un certo numero di classi che implementano tale interfaccia e che quindi possiamo utilizzare. Ogni container nasce con un certo Layout Manager ma è possibile assegnarne a piacimento con il metodo: public void setLayout(LayoutManager m) Vediamo le suddette classi che implementano LayoutManager che Swing mette a disposizione: FlowLayout Riempie il contenitore con le componenti disponendole su righe da sinistra verso destra; quando si riempie la prima riga si passa alla successiva. Tra i vari costruttori, i più importanti sono: – public FlowLayout(); – public FlowLayout(int allin); Il parametro intero allin indica l'allineamento; possiamo utilizzare valori prestabiliti utilizzando le costanti: • FlowLayout.LEFT (allineamento a sinistra) • FlowLayout.CENTER (allineamento al centro) • FlowLayout.RIGHT (allineamento a destra) GridLayout Suddivide il contenitore in una griglia in celle di uguali dimensioni. Le dimensioni della griglia vengono definite mediante il costruttore: – public GridLayout(int rows, int columns) I componenti all’interno della griglia assumono automaticamente la stessa dimensione, dividendo equamente lo spazio disponibile. Man mano che inserisco gli oggetti mi riempiono in ordine la griglia. BorderLayout Suddivide il contenitore esattamente in cinque aree, disposte a croce, come in figura: Ogni zona può contenere uno ed un solo componente (che di fatto però può essere un contenitore a sua volta). Se una o più zone non vengono riempite, allora i componenti nelle altre zone sono estesi a riempire le zone vuote. Il programmatore può decidere in quale posizione aggiungere un controllo utilizzando la variante del metodo add sempre presente nella classe Containe r: public void add(Component c, String s); dove come secondo parametro vado a passargi l'indicazione di dove inserire il componente utilizzabili le costanti: BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.CENTER, BorderLayout.EAST e BorderLayout.WEST .
Esempio con LayoutManager di tipo FlowLayout import javax.swing.*; import java.awt.*; public class Finestra2 extends JFrame { public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; //creo dei label (un'etichetta) JLabel l1 = new JLabel("uno"); JLabel l2 = new JLabel("due"); JLabel l3 = new JLabel("tre"); JLabel l4 = new JLabel("quattro"); JLabel l5 = new JLabel("cinque"); //creo un pannello JPanel p1 = new JPanel(); public Finestra2( ) { //chiamo il costruttore della superclasse JFrame super("La Mia Finestra 2"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); //ottengo il content pane Container c = this.getContentPane(); //setto il layout del pannello p1.setLayout(new FlowLayout()); //aggiungo i label al pannello p1.add(l1); p1.add(l2); p1.add(l3); p1.add(l4); p1.add(l5); //aggiungo il pannello al content pane c.add(p1); } public static void main(String [] args){ Finestra2 f = new Finestra2(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } }
Paranoramica di alcune componenti I nomi delle classi per la maggior parte dei componenti dell’interfaccia utente Swing iniziano con la lettera J. JTextField E' un campo per insierire del testo. Bisogna fornire al costruttore, come parametro, l’ampiezza; cioè il numero approssimato di caratteri che vi aspettate verranno inseriti dall’utente (gli utenti possono comunque inserire più caratteri, però verranno visualizzati il numero di caratteri indicato). JTextField xField=new JTextField(5); JLabel Semplici etichette di testo. Al costruttore posso passare il testo da visualizzare. JLabel xField=new Jlabel("testo"); JButton Sono dei bottoni. Al costruttore può essere fornita una stringa che fungerà da etichetta, un’immagine come icona o entrambe .
Progettazione di un'interfaccia grafica In genere è utile, in fase progettuale, ricorrere descrivere l’insieme dei componenti a partire dal componente più esterno per poi procedere a mano a mano verso quelli più interni: 1) Si definisce il top level container, il JFrame, su cui si vuole lavorare ; 2) Si assegna un layout manager al content pane del JFrame, in modo da suddividerne la superficie in aree più piccole. 3) Per ogni area messa a disposizione dal layout manager è possibile definire un JPanel. Ogni sotto pannello pò utilizzare un layout manager differente. 4) Ogni pannello identificato nel terzo passaggio può essere sviluppato ulteriormente, creando al suo interno ulteriori pannelli o disponendo dei controlli. Una volta conclusa la fase progettuale, si può passare a scrivere il codice relativo all’interfaccia: in questo secondo momento è utile realizzare dapprima il codice relativo ai componenti atomici, quindi quello dei contenitori e infine quello del JFrame.
Puoi anche leggere