Java Interfaccia Grafica
• Testi di consultazione:
a) core Java 1.1 (Volume I – Fundamentals)
Cay S. Horstmann, Gary Cornell, Prentice Hall, 1997.
b) Java 1.2 Unleashed, Jamie Jaworski, Sams Publishing, 1998.
c) Programmazione di applicazioni grafiche in Java, S. Mazzanti e V. Milanese, 2006.
• Un programma interattivo classico controlla l'interazione con l'utente quando il flusso di controllo lo esige.
• Con una interfaccia grafica (GUI) normalmente l'applicazione attende che l'utente generi eventi agendo sull'interfaccia (azioni e movimenti del mouse, bottoni, ecc...)
• Si può parlare di interazione guidata dagli eventi, a cui corrispondono delle opportune procedure/funzioni/metodi per gestirli.
• Un sistema operativo che supporti un'interfaccia grafica deve
controllare continuamente l'ambiente per verificare se sono avvenute azioni (ad esempio 'la pressione di un tasto sulla tastiera' o un
'click' sul mouse), che generano eventi corrispondenti.
Tali eventi vengono quindi comunicati all'applicazione che li gestisce.
Vi sono vari approcci.
Approcci classici di alto e basso livello
Approccio stile Visual Basic
• Corrispondenza diretta eventi-procedure (event procedures)
• Si scrive codice per manipolare ciascun evento e si mette tale codice nella corrispondente procedura.
Ad esempio: per HelpButton si scrive la procedura HelpButton_Click per gestire l'evento 'click' del mouse.
Approccio stile C:
• Un unico ciclo che controlla continuamente la coda degli eventi, con un enorme 'case' per testare tutte le possibilità.
Per ogni evento può essere invocata la routine opportuna.
Java e gli altri
• L'approccio del Visual Basic consente di trattare una classe limitata di Eventi, quelli previsti dal linguaggio, però il codice corrispondente è molto più conciso, semplice ed elegante.
• L'approccio del C permette una maggiore flessibilità e di trattare più eventi.
• Il codice Java deve essere indipendente dalla piattaforma,
quindi definisce un modello astratto che contiene i concetti comuni ai vari ambienti grafici.
Di conseguenza si pone in una posizione intermedia come flessibilità e semplicità tra l'esempio del Visual Basic e del C.
• Package per la gestione dell'ambiente grafico: AWT (Abstract Window Toolkit).
java.awt (4 sotto-package: java.awt.datatransfer, java.awt.event, java.awt.image, java.awt.peer). 105 classi, 22 interfacce
Java 1.2
• Extended JFC (Java Foundation Classes)
JFC 1.1 ---- AWT, SWING, JAVA 2D, Drag and Drop, Accessibility
SWING:
• usa AWT per interfacciarsi col sistema di finestre sottostanti nativo
• offre nuove componenti (rispetto all'AWT)
• ri-implementa componenti AWT in codice Java 100% puro peggiore performance per la stessa componente
aspetto migliore (look and feel) maggiore flessibilità
AWT incluse in SWING inclusi in JFC
• JDK 1.2 include compiler JIT
Package AWT
• La classe principale del package è component, che rappresenta un oggetto grafico che ha una posizione ed una dimensione sullo schermo, su cui è possibile disegnare e che può ricevere 'azioni' dall'utente
Component è una classe astratta (circa 120 metodi). Rappresenta gli elementi di base dell'interfaccia grafica.
Una istanza di component può essere visualizzata solo se contenuta in un oggetto visibile.
Esempi di componenti:
List, Scrollbar, TextArea, TextField, Choice, Button, Label...
Tutti i Container
• Container è una classe che deriva da Component.
Può contenere componenti. Notiamo che un container è anche un componente.
In genere un container prevede le funzionalità per la gestione degli eventi e dello scambio di informazioni tra i componenti.
Esempi di Container: Applet, Frame, Window, Dialog, Panel
Il modello astratto (Java 1.1)
• Definiamo come sorgente di un evento (Event source) una
qualunque componente grafica su cui l'utente possa svolgere delle azioni (ad esempio un bottone o una lista di scelte in un menu) Il programmatore decide come gli eventi generati da azioni utente sulle componenti grafiche dell'interfaccia vengono gestiti da opportuni oggetti delegati a gestire (o ascoltare) il verificarsi di un determinato evento.
Qualsiasi oggetto (anche più di uno) può essere delegato ad ascoltare (e quindi gestire) il verificarsi di un determinato evento.
Per questo motivo si parla di event delegation model.
Notiamo che è più flessibile di Visual Basic, in cui l'ascoltatore è fissato a priori, però richiede di scrivere più codice.
I vantaggi rispetto a C sono ovvi, ad esempio il fatto che l'utente non vede la coda di sistema degli eventi.
Ovviamente un programma C potrebbe gestire più eventi di quelli trattabili in Java.
Modello con delega della gestione eventi
• Un oggetto ascoltatore è una istanza di una classe che implementa la interfaccia detta listener interface
Un oggetto ascoltatore deve comunque essere delegato per poter gestire un evento generato da una componente grafica.
Un oggetto delegato riceverà un messaggio (notifica) quando si verifica un evento.
Il messaggio attiva il corrispondente metodo della listener interface.
• L'oggetto ascoltatore viene delegato mediante una linea di codice del tipo seguente:
eventSourceObject.addEventListener(eventListenerObject)
• Esempio:
Button b = new Button(“clear”);
b.addActionListener(OggDeleg);
In questo modo viene inviato un messaggio a 'OggDeleg' ogni volta che si verifica un evento (cioè un'azione) su Button.
Un evento su un bottone può essere un 'click' sul bottone.
L'oggetto delegato ('OggDeleg') come ascoltatore deve implementare l'interfaccia opportuna, quindi in questo caso ActionListener
Il metodo actionPerformed di tale interfaccia riceve come parametro un oggetto di tipo ActionEvent, che permette all'ascoltatore di avere informazioni ulteriori sull'evento verificatosi.
Alcuni esempi di programmazione
• esempi di applicazioni standalone (console grafica) esempi di applets
Gestione Finestre
Finestra vuota, no gestione eventi (no interazione con utente)
import java.awt.*;
public class FinestraVuota extends Frame {
public static void main (String argv[]) { FinestraVuota ist = new FinestraVuota();
System.out.println ("Esco da main");
}
FinestraVuota () {
setBounds(30, 10, 300, 200);
setTitle (getClass().getName());
setVisible(true);
} }
• Sostanzialmente disegna un rettangolo di 300x200 pixel
sulla console grafica con il vertice in alto a sinistra di coordinate 30 e 10.
Il punto di coordinate (0,0) è quello più in alto a sinistra sulle coordinate (x,y), dove x è per l’asse verticale, a scendere, ed y per l’asse orizzontale.
Infine scrive sulla console grafica la scritta “Esco da main”.
• Questo è un esempio di creazione di una finestra, senza gestione degli eventi, e quindi senza interazione con l'utente.
Stesso programma utilizzando le classi Swing
//import java.awt.*;
import javax.swing.*; // si importano le swing
public class FinestraVuota extends JFrame { // sottoclasse di JFrame public static void main (String argv[]) {
FinestraVuota ist = new FinestraVuota();
System.out.println ("Esco da main");
}
FinestraVuota () {
setBounds(30, 10, 300, 200);
setTitle (getClass().getName());
//setTitle ("Finestra di prova senza interazione");
setVisible(true);}}
Finestra vuota, con gestione eventi (interazione con utente)
import java.awt.*;
import java.awt.event.*;
public class Eventi extends Frame {
Ascoltatore asc = new Ascoltatore();
public static void main (String argv[]) { Eventi ist = new Eventi();
}
Eventi () {
setBounds(30, 10, 300, 200);
setTitle (getClass().getName());
setVisible(true);
addWindowListener(asc);
} }
class Ascoltatore implements WindowListener {
public void windowClosed (WindowEvent evt) { System.out.println (evt);
System.exit(0);
}
public void windowClosing (WindowEvent evt) { evt.getWindow().dispose();
System.out.println (evt);
}
public void windowDeiconified (WindowEvent evt) { System.out.println (evt);
}
public void windowIconified (WindowEvent evt) { System.out.println (evt);
}
public void windowOpened (WindowEvent evt) { System.out.println (evt);
}
public void windowActivated (WindowEvent evt) { System.out.println (evt);
}
public void windowDeactivated (WindowEvent evt) { System.out.println (evt); }
}
java.awt.event.WindowEvent[WINDOW_OPENED] on frame0 java.awt.event.WindowEvent[WINDOW_ACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_DEACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_ICONIFIED] on frame0 java.awt.event.WindowEvent[WINDOW_DEICONIFIED] on frame0 java.awt.event.WindowEvent[WINDOW_CLOSING] on frame0 java.awt.event.WindowEvent[WINDOW_DEACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_CLOSED] on frame0
Listener interfaces e gerarchia degli eventi
• ActionListener AdjustementListener ComponentListener FocusListener ItemListener KeyListener MouseListener
MouseMotionListener TextListener
WindowListener
• Non tutti gli eventi nella gerarchia di sistema sono utili per l'utente. Quelli che sono inviati agli ascoltatori sono:
ActionEvent AdjustmentEvent ComponentEvent FocusEvent ItemEvent KeyEvent MouseEvent TextEvent WindowEvent
Eventi ed Oggetti Eventi
• Gli eventi possono essere di diverso tipo, ma comunque condividono alcune caratteristiche. Pertanto le classi degli eventi sono rappresentate in modo gerarchico e seguono le usuali regole dell'inheritance.
• La classe radice si chiama java.util.EventObject.
La sola caratteristica comune condivisa da tutti gli eventi è un oggetto sorgente. Pertanto nella classe radice EventObject troviamo il seguente metodo:
public Object getSource()
Restituisce l’oggetto su cui si è verificato l’Evento.
Controlli grafici
• un contenitore permette di organizzare (contenere in modo ordinato) un insieme di componenti grafiche e di presentarle visualmente in modo controllato.
• È possibile aggiungere componenti ad un contenitore mediante il metodo
Component add(Component)
e specificare un gestore della organizzazione all'interno del contenitore mediante il metodo
public void setLayout(LayoutManager mgr)
Programmi standalone piuttosto che Applet
Il plugin Java per browser verrà rimosso da Oracle JDK (Java Development Kit) e JRE (Java Runtime Environment) nelle prossime release di Java SE (in JDK 9 sono ‘deprecated’).
Questo perché i produttori di browser stanno rimuovendo tutti i plugin dai browser (compresa la versione desktop per PC), per renderli uniformemente compatibili con le versioni
smartphone che non li prevedono, e per questioni di sicurezza.
Di conseguenza le pagine seguenti, che descrivono gli Applet di
Java stanno diventando obsolete, dato che è una tecnologia destinata a scomparire.
APPLET
• Un applet si crea come sottoclasse di java.applet.Applet
• È necessario definire un tag APPLET per poter inserire una
“chiamata” al codice compilato in un documento html
• si può inoltre eseguire un applet mediante l' “appletviewer”
del JDK (Java Development Kit) della Oracle.
In BLUEJ basta scegliere 'run Applet', prima opzione del menu
di scelte per eseguire l'applet, poi Bluej fa scegliere tra 'appletviewer' o browser (meglio usare appletviewer, per il browser sono
necessari settaggi sui controlli di sicurezza)
Esempio di tag:
<APPLET
CODE = ProvaApplet.class WIDTH = 50
HEIGHT = 100>
</APPLET>
• WIDTH ed HEIGHT definiscono le dimensioni della regione assegnata sulla finestra gestita dal browser per visualizzare l'applet.
• CODE indica il bytecode dell'applet da caricare
Ciclo di vita di un Applet
• public void init()
eseguito la prima volta che viene caricato l'applet
• public void start()
eseguito ogni volta che il browser ri-visualizza la parte di pagina dove è contenuta l'applet (ad esempio caricando o ricaricando la pagina html dov'è definita)
• public void stop()
eseguito quando la pagina dove viene caricata l'applet viene disattivata (ad esempio visualizzandone un'altra)
• public void destroy()
eseguito quando si esce dal browser o si chiude la pagina html dove sta il tag per l'applet.
---
• Si può utilizzare uno o più di questi metodi nel codice che definisce un applet. Non c'è nessun obbligo di usarne anche solo uno, anche se pare ragionevole utilizzare almeno
init e/o start.
Un applet può contenere la definizione di un costruttore (anche se normalmente è sostituito dal metodo init() )
Interfaccia interattiva con due bottoni, che visualizza data e ora a richiesta.
import java.util.Date;
import java.awt.*;
import java.awt.event.*;
public class Bottoni extends Frame
implements ActionListener {
Date data = new Date();
public static void main (String argv[]) { Bottoni ist = new Bottoni();
}
Bottoni () { setLayout(null);
setBounds (30, 10, 300, 200);
setTitle (getClass().getName());
Button bData = new Button("Data");
bData.setBounds (50, 150, 50, 30);
bData.addActionListener (this);
Button bEsci = new Button("Esci");
bEsci.setBounds (200, 150, 50, 30);
bEsci.addActionListener (this);
add (bData);
add (bEsci);
setVisible(true);
}
public void paint (Graphics g) { g.drawString (data.toString(), 5, 40);
}
public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Esci")) System.exit(0);
if (e.getActionCommand().equals("Data")){
data = new Date();
repaint();
} } }
• Disegna sulla console grafica una finestra di 300x200 pixel, con un vertice di coordinate 30 e 10.
Due bottoni con scritta “Data” e “Esci” vengono collocati nella finestra.
• Ogni volta che l'utente clicca su “Data” viene visualizzata sulla console la data e ora del giorno.
• Quando l'utente clicca su “Esci” termina l'esecuzione.
// identico programma, utilizzando le classi Swing
import java.util.Date;
//import java.awt.*;
import java.awt.Graphics;
import javax.swing.*; // si importa package Swing import java.awt.event.*;
public class Bottoni extends JFrame implements ActionListener{ // extends JFrame Date data = new Date();
public static void main (String argv[]) { Bottoni ist = new Bottoni(); }
Bottoni () { setLayout(null);
setBounds (30, 10, 500, 300);
setTitle (getClass().getName());
JButton bData = new JButton("Data"); // usa JButton bData.setBounds (50, 100, 80, 50);
bData.addActionListener (this);
JButton bEsci = new JButton("Esci");
bEsci.setBounds (200, 100, 80, 50);
bEsci.addActionListener (this);
add (bData);
add (bEsci);
setVisible(true);}
public void paint(Graphics g) { super.paint(g);
g.drawString (data.toString(), 50, 60); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Esci")) System.exit(0);
if (e.getActionCommand().equals("Data")){
data = new Date();
repaint(); }} }
Identico programma, come APPLET
import java.util.Date;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class ABottoni extends Applet
implements ActionListener {
Date data = new Date();
public void init(){
setLayout(null);
setBounds (30, 10, 300, 200);
// setTitle (getClass().getName());
Button bData = new Button("Data");
bData.setBounds (50, 150, 50, 30);
bData.addActionListener (this);
Button bEsci = new Button("Esci");
bEsci.setBounds (200, 150, 50, 30);
bEsci.addActionListener (this);
add (bData);
add (bEsci);
}
public void paint (Graphics g) { g.drawString (data.toString(), 5, 40);
}
public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Esci")) System.exit(0);
if (e.getActionCommand().equals("Data")){
data = new Date();
repaint();
} } }
Suoni ed Immagini (Applet)
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
public class Immagine extends Applet { Image img;
AudioClip auc;
public void init () {
img = getImage (getDocumentBase(), "mar.gif");
auc = getAudioClip (getDocumentBase(), "97381.au");
}
public void start () { auc.loop(); } public void stop () { auc.stop(); }
public void paint (Graphics g){ g.drawImage (img, 0, 0, this); } }
Sviluppo di Applicazioni per Android (o per iOS)
• Per lo sviluppo di applicazioni iOS è necessario far riferimento a Objective-C, un linguaggio orientato ad oggetti che estende propriamente C (il compilatore può compilare qualsiasi programma C), con caratteristiche simili a Java, ma anche con importanti differenze (non è fortemente tipato, si possono invocare metodi inesistenti, ecc...), oltre ad un ambiente di sviluppo adeguato (e.g.:
Xcode di Apple).
• Per lo sviluppo di applicazioni per Android si può utilizzare Java, studiando le caratteristiche di un ambiente di sviluppo adeguato, come ad esempio Eclipse o Android Studio (fornito da Google).
Eclipse (dal 2001, scritto in Java) è un ambiente di sviluppo integrato multi-linguaggio (per Java, C++, ecc) e multipiattaforma.
Ideato da un consorzio di grandi società quali
Ericsson, Borland, HP, IBM, Intel, MontaVista Software, QNX, SAP e Serena Software, chiamato Eclipse Foundation.
Android Studio (dal 2013, Google)
- permette di vedere tutte le modifiche visive apportate ad una app in tempo reale e di vedere come apparirà su diversi dispositivi Android, ognuno con configurazioni e risoluzioni diverse, contemporaneamente.
Inoltre fornisce:
-un modo semplice per testare le prestazioni su vari tipi di dispositivi.
-procedure guidate e modelli per gli elementi comuni a tutte le programmazioni Android (ad esempio per le interfacce grafiche).
-un editor completo con strumenti per velocizzare lo sviluppo delle applicazioni.