windowbuilder

Java Swing, appunti

Il modo più semplice di gestire gli eventi di una finestra creata da Swing è quello di assegnare ad un componente un listener:

public class MyFrame extends JFrame {
	private JButton bottone = new JButton("Bottone");
	Ascoltatore listener = new Ascoltatore();

	public MyFrame() {
			...
			Container c = this.getContentPane();
			c.add(bottone);
			// Assegno l' ascoltatore
			bottone.addActionListener(listener);
	}
}

public class Ascoltatore implements ActionListener {
	public void actionPerformed(ActionEvent event) {
		// Accedo all' oggetto che ha scatenato l' evento
		JButton b = (JButton) event.getSource();
		JOptionPane.showMessageDialog(null, "E` stato premuto" + b.getText());
	}
}

ma il problema di questa tecnica è che non si può accedere ad un elemento diverso da quello che ha scatenato l’ evento: con la classe che implementa l’ interfaccia ActionListener posta “esternamente” alla classe del frame, è impossibile accedere agli altri oggetti del frame.

Una prima soluzione è quella di scrivere il listener internamente al frame, così da poter accedere ai suoi membri:

public class MyFrame extends JFrame {
	private JButton bottone = new JButton("Bottone");

	public MyFrame() {
			...
			Container c = this.getContentPane();
			c.add(bottone);
			// Assegno l' ascoltatore in modo anonimo
			bottone.addActionListener(new Ascoltatore());
	}

	class Ascoltatore implements ActionListener {
		public void actionPerformed(ActionEvent event) {
			// Accedo all' oggetto che ha scatenato l' evento
			// semplicemente accedendo al metodo "bottone" della classe
			JButton b = bottone;
			JOptionPane.showMessageDialog(null, "E` stato premuto" + b.getText());
		}
	}
}

Lo svantaggio di questa soluzione è che la classe del frame può diventare eccessivamente grande al crescere della complessita della GUI, e si avrà anche un codice poco leggibile con 2 classi eterogenee fuse tra loro.

La soluzione migliore è quella di definire un costruttore del listener che prende come parametro un riferimento alla finestra che contiene i vari componenti.

public class MyFrame extends JFrame {
	// Componenti della GUI come membri della classe
	JPanel centro = new JPanel();
	JPanel sud = new JPanel();
	JTextField txt = new JTextField(20);
	JButton button = new JButton("Premi");
	// Inizializzazione del listener
	Listen ascolt=new Listen(this);

	public MyFrame() {
		super("Esempio");
		centro.add(txt);
		...
		button.addActionListener(ascolt);
		txt.addActionListener(ascolt);
		...
	}
}

class Listen implements ActionListener {
	MyFrame frame;
	// Costruttore che riceve il riferimento al frame
	public Listen(MyFrame aFrame)
		{ frame = aFrame; }

	// Da qui accediamo ai metodi del frame !
	public void actionPerformed(ActionEvent e) {
	JTextField text = frame.txt;
	JOptionPane.showMessageDialog(null,text.getText());
	}
}

A questo punto bisogna dire che non si può pensare di creare un listener per ogni componente: si può invece raggruppare vari componenti ed assegnargli un unico listener condiviso, con lo stessa funzione actionPerformed condivisa tra essi.

Dunque, in actionPerformed bisogna distinguere quale oggetto ha generato l’ evento; si può fare in 2 modi:

  • con il metodo getSource() della classe ActionEvent. Questa tecnica è fattibile se si può confrontare il riferimento dato da getSource() con il riferimento memorizzato nella classe del frame: è, in generale, il caso della classe interna vista prima.
  • con la proprietà actionCommand dei componenti di swing. Con questa tecnica, in actionPerformed() non è più necessario prendere i riferimenti agli oggetti, ma basta leggere l’ actionCommand e chiamare la funzione appropriata.
    Questa tecnica è utile anche nel caso in cui ci siano diversi componenti che condividono la stessa azione: ad esempio un bottone e una voce di menu possono fare la stessa cosa, quindi basta scrivere una sola funzione e farla chiamare da actionPerformed tramite un actionCommand.
    Rimane il fatto che per accedere ai componenti del frame sia necessario passare al costruttore del listenere il riferimento al frame che contiene quei componenti come metodi della classe.

    public class MyFrame extends JFrame {
    	...
    	JMenuItem UpOpt = new JMenuItem("Up");
    	JMenuItem DownOpt = new JMenuItem("Down");
    	JMenuItem RandomOpt = new JMenuItem("Random");
    	Listener ascolt = new Listener();
    	public MyFrame() {
    		...
    		UpOpt.addActionListener(ascolt);
    		UpOpt.setActionCommand(ascolt.UPOPT);
    		DownOpt.addActionListener(ascolt);
    		DownOpt.setActionCommand(ascolt.DOWNOPT);
    		RandomOpt.addActionListener(ascolt);
    		RandomOpt.setActionCommand(ascolt.RANDOMOPT)
    		...
    	}
    }
    
    public class Listener implements ActionListener {
    	public final static String UPOPT = "up";
    	public final static String DOWNOPT = "down";
    	public final static String RANDOMOPT = "random";
    	// Eventualmente scrivere un costruttore
    	// per avere un riferimento al frame
    
    	public void actionPerformed(ActionEvent e) {
    		String com = e.getActionCommand();
    		if (com == UPOPT)
    			upOpt();
    		else if (src == DOWNOPT)
    			downOpt();
    		else if (src == RANDOMOPT)
    			randomOpt();
    	}
    
    private void upOpt()
    { ... }
    private void randomOpt()
    { ... }
    private void downOpt()
    { ... }
    }
    
    

Java Swing livello avanzato: http://home.cogeco.ca/~ve3ll/jatutorc.htm
MVC: http://www.macs.hw.ac.uk/guidebook/?name=Using%20The%20GUI&page=1

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...