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à
SWING incluse in AWT incluso 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 è un'altra classe astratta 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
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 un vertice di coordinate 30 e 10
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.
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 classe 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();
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)
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() )
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.
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
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.