Tratamento de Evento

Ola,

Eu estava fazendo um aplicativo simples, usando swing, onde eu tenhu um JFrame que possui um botão que quando clicado chama outro frame.

Bom, só fiquei com uma duvida a respeito do evento do botão:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class FrmPrincipal extends JFrame
{
	FlowLayout fl = new FlowLayout();
	JButton btnAbrir = new JButton("Abrir nova Janela");
	JButton btnFechar = new JButton("Fechar Janela!");

	//DECLARAÇÃO DA SEGUNDA JANELA
	public static FrmSegundaJanela fsj;
	
	public FrmPrincipal() //CONSTRUTOR
	{
		//CONFIGURAÇÕES DA JANELA
		super("Primeira Janela!");
		setSize(450, 250);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//REGISTRO DO EVENTO DO BOTÃO   
		btnAbrir.addActionListener  //INICIO DA DUVIDA
		(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if (fsj == null)
					fsj = new FrmSegundaJanela();
				
				mostraFrame(fsj);
			}
		});
		
............

Minha duvida esta na parte do ActionListener e ActionPerformed.
Como funciona essa parte? O que é uma classe anonima?? Toda vez que eu for tratar um evento eu terei que utilizar o metodo ActionListener?

Eu andei procurando a respeito mas o que eu encontrei não esclareceu minha duvida.

Se puderem me dizer como funciona, ou mostrar algum lugar aonde eu possa intender, ficarei grato :stuck_out_tongue:

[]'s

Desculpa…não entendi bem qual é sua dúvida…é sobre a classe anônima ou você só quer saber como funciona o monitoramento de eventos no java?

Olá Thiago!
Bom, classes anônimas são bem isso mesmo: Classes que não têm nome. Isso implica em não ser possível termos uma variável do tipo dessas classes, uma vez que não sabemos qual o seu tipo, ou melhor, qual o nome de seu tipo.
Elas são utilizadas geralmente quando queremos uma classe para implementar uma determinada interface, porém, só vamos utilizar essa classe dentro de um contexto muito restrito.
Uma classe anônima é como qualquer outra classe Java, com a diferença de que você não consegue, por motivos óbvios, declarar modificadores para ela (public, private, protected, static, abstract, etc).
Sendo assim, uma classe anônima pode ser uma classe “?” que implementa uma determinada interface ou que extende uma determinada classe.
Criamos uma classe anônima quando abrimos um bloco de instruções ("{" código, código, código,… “}”) logo após “darmos” um new em uma classe ou - pasme - interface.Veja o seguinte código:

package help.guj.thiagooliver;

public class AnonymousClassTests {
	public static void main(String[] args) {
		A simple = new A();
		
		A anonymous = new A() {
			public String toString() {
				return "Who am I??? What's my name???";
			}
		};
		
		System.out.println("simple: " + simple);
		System.out.println();
		System.out.println("anonymous: " + anonymous);
	}
}

class A{
	public String toString() {
		return "Hi! I am an object of A class!";
	}
}

Neste código temos duas variáveis do tipo A. Enquanto a variável simple referencia um simples objeto do tipo A, a variável anonymous referencia um objeto cujo tipo não podemos dizer qual é, pois trata-se de um tipo anônimo, de uma classe anônima. A única coisa que podemos dizer a respeito da classe do objeto referenciado por anonymous é que é uma classe que extende A.
Se executar este código, veremos no console o seguinte resultado:

simple: Hi! I am an object of A class!

anonymous: Who am I??? What's my name???

Você pode ser perguntar: “Mas ambas as variáveis não são do tipo A? Por que então o toString delas produzem saídas diferentes?” Porque os objetos que estão sendo referenciados pelas variáveis são diferentes. O classe do objeto referenciado por anonymous sobrescreve o método toString implementado pela classe A. Veja que quando declaramos a variável anonymous, atribuimos a ela uma instância de uma classe anônima (porque não tem nome), filha de A(porque utilizamos o construtor da classe A para a criação da classe anônima).
Se alterarmos um pouco o código acima, poderemos ver melhor que a classe anônima é de fato filha de A:

package help.guj.thiagooliver;

public class AnonymousClassTests {
	public static void main(String[] args) {
		A simple = new A();
		
		A anonymous = new A() {
			public String toString() {
				return "Who am I??? What's my name???";
			}
		};
		
		System.out.println("simple: " + simple);
		System.out.println();
		System.out.println("anonymous: " + anonymous);
		System.out.println();
		System.out.println("simple.WhatIAm(): " + simple.WhatIAm());
		System.out.println();
		System.out.println("anonymous.WhatIAm(): " + anonymous.WhatIAm());
	}
}

class A{
	public String toString() {
		return "Hi! I am an object of A class!";
	}
	
	public String WhatIAm() {
		return "I am a Java object.";
	}
}

Teremos a seguinte saída:

simple: Hi! I am an object of A class!

anonymous: Who am I??? What's my name???

simple.WhatIAm(): I am a Java object.

anonymous.WhatIAm(): I am a Java object.[/code]
Como você pode ver, a classe funciona como uma classe como outra qualquer, só que ela não tem nome.
Isso tem uma implicação importante: Um método declarado (Eu disse declarado, não sobrescrito) dentro de uma classe anônima só pode ser acessado via reflexão.
Imagine que nossa classe anônima seja escrita assim:
[code]
A anonymous = new A() {
	public String toString() {
		return "Who am I??? What's my name???";
	}
	
	public int eval() {
		return 78;
	}
};
[/code]
Qual é o problema que temos aqui? Aquele método [i]eval[/i], embora público, é inacessível, diretamente, a partir de [i]anonymous[/i], pois o tipo de [i]anonymous[/i] é [i]A[/i], e a classe [i]A[/i] não declara nenhum método chamado [i]eval[/i]. E como não sabemos o nome do tipo da nossa classe anônima, tampouco podemos obter uma variável do tipo da tal classe anônima...
Esse método só se torna acessível através do uso de técnicas de reflexão:
[code]
int i = anonymous.getClass().getDeclaredMethods()[1].invoke(anonymous);
[/code]
Mais informações sobre reflection [url=http://java.sun.com/docs/books/tutorial/reflect/index.html]aqui[/url]
Você pode se perguntar ainda:
[quote=Thiago.Oliver]Mas se uma classe anônima não tem nome, como que o Java se vira com essas classes se tiver mais de uma delas?[/quote]
Na verdade, essas classes não são tão anônimas assim... Vamos ver como que o Java "nomeia" as classes anônimas, utilizando o método [i]getClass[/i] para obter um objeto [i]Class[/i] referente à classe dos nossos objetos e, apartir destes objetos [i]Class[/i], utilizaremos o método [i]getName[/i] :twisted: :
[code]
package help.guj.thiagooliver;

public class AnonymousMaNonTroppo {
	public static void main(String[] args) {
		A wellKnownA = new A();
		Object wellKnownObject = new Object();
		
		A anonymousA = new A(){
			/*
			 * Veja que não sou obrigado a por código na 
			 * classe anônima, mas isso seria totalmente
			 * sem sentido e inútil...
			 */
		};
		Object anonymousObject = new Object() {
			public String toString() {
				return "My superclass said: " + super.toString();
			}
		};
		
		System.out.println("What is your class?");
		System.out.println("===================");
		System.out.println(
			"wellKnownA said: " + wellKnownA.getClass().getName()
		);
		System.out.println(
			"wellKnownObject said: " + wellKnownObject.getClass().getName()
		);
		System.out.println(
			"anonymousA said: " + anonymousA.getClass().getName()
		);
		System.out.println(
			"anonymousObject said: " + anonymousObject.getClass().getName()
		);
		System.out.println("\n");
		
		System.out.println("Who is your superclass?");
		System.out.println("=======================");
		System.out.println(
			"wellKnownA said: " + 
			wellKnownA.getClass().getSuperclass().getName()
		);
		System.out.println(
			"anonymousA said: " + 
			anonymousA.getClass().getSuperclass().getName()
		);
	}
}
[/code]
O resultado é o seguinte:
[code]
What is your class?
===================
wellKnownA said: help.guj.thiagooliver.A
wellKnownObject said: java.lang.Object
anonymousA said: help.guj.thiagooliver.AnonymousMaNonTroppo$1
anonymousObject said: help.guj.thiagooliver.AnonymousMaNonTroppo$2


Who is your superclass?
=======================
wellKnownA said: java.lang.Object
anonymousA said: help.guj.thiagooliver.A
[/code]
Quando executamos [i]anonymousA.getClass()[/i], por exemplo, é retornado um objeto [i]java.lang.Class[/i] que representa a classe anônima que criamos para a instanciação da variável [i]anonymousA[/i]. Quando invocamos então, desse objeto [i]Class[/i] em questão, o método [i]getName[/i], foi retornado o nome [i]help.guj.thiagooliver.AnonymousMaNonTroppo$1[/i]
Veja que interessante: O Java nomeia as classes anônimas [u]como se fossem[/u] classes internas da classe onde foram declaradas. O nome individual de cada classe anônima é, na verdade, apenas um inteiro. Sabemos que nós, reles programadores Java, não podemos criar uma classe cujo nome começe com um caractere numérico, mas o Java pode  :D 
Em seguida, vemos que a superclasse do objeto referenciado por [i]wellKnownA[/i] é [i]Object[/i], e a de [i]anonymousA[/i] é [i]A[/i].

[b][color=darkblue][size=18]Agora, falando um pouco sobre eventos...[/size][/color][/b]
Os componentes gráficos de Java geralmente têm suporte a tratamento de eventos. Isso quer dizer que podemos programar um conjunto de instruções que pode ser disparado de acordo com a ocorrência de um determinado evento sobre um componente gráfico. Por exemplo, podemos programar que um botão, ao ser clicado (que é um evento), calcule uma conta utilizando valores escritos pelo usuário em campos de texto da tela.
O Java se utiliza do que chamamos de [u]listeners[/u] para tratar eventos, que são representados por classes de eventos, obviamente. A grande maioria dos componentes gráficos de Java podem receber vários tipos de eventos e permitem que sejam associados às suas instâncias um ou mais listeners.
Mas o que é um listener? Essa palavra vem do inglês "ouvinte", e isso é exatamente o que um listener faz: Fica "ouvindo" os eventos recebidos por um componente gráfico. Quando clicamos em um botão, este botão (que é um objeto Java, não se esqueça disso) recebe alguns eventos (Que são objetos também). Nesse momento, para cada evento recebido, o botão verifica se há algum listener "espetado" em si que "ouça" por pelo evento recebido.
Por exemplo: Neste caso do botão, que pode ser um objeto [i]javax.swing.JButton[/i], ao ser clicado, um dos eventos que são disparados é (um objeto da classe) [i]java.awt.event.ActionEvent[/i].
Ao receber um [i]ActionEvent[/i], o [i]JButton[/i] verifica se tem associado em si algum listener capaz de responder, de tratar esse [i]ActionEvent[/i]. A classe [i]JButton[/i] nos permite associar um ou mais listener capazes de tratar um [i]ActionEvent[/i], através do método [i]addActionListener[/i]. Este método recebe como parâmetro um objeto do tipo [i]java.awt.ActionListener[/i]. [i]ActionListener[/i] é um listener que responde a aventos do tipo [i]ActionEvent[/i]. Logo, se um [i]JButton[/i] recebe um [i]ActionEvent[/i], ele passa esse evento para todos os seus [i]ActionListener[/i] previamente adicionados. Cada um desses [i]ActionListener[/i] vai tratar o evento passado.
[quote=Thiago.Oliver]
Quer dizer que o Java já me define que é o cara que vai tratar o evento.... Mas então, como diabos o Java vai saber o que eu quero que seja feito ao ser clicado o raio do [i]JButton[/i]???
[/quote]
Simples: Ele não sabe. É você quem tem que dizer o que fazer. Por isso mesmo [u]todos os listeners são interfaces[/u], ficando assim aberta a implementação do tratamento dos respectivos eventos.
O listener ActionListener, por exemplo, é um dos listener mais simples, por ser uma interface que define apenas um único método. Veja o código fonte da interface ActionListener (no Java 6):
[code]/*
 * @(#)ActionListener.java	1.18 06/04/13
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.awt.event;

import java.util.EventListener;

/**
 * The listener interface for receiving action events. 
 * The class that is interested in processing an action event
 * implements this interface, and the object created with that
 * class is registered with a component, using the component's
 * <code>addActionListener</code> method. When the action event
 * occurs, that object's <code>actionPerformed</code> method is
 * invoked.
 *
 * @see ActionEvent
 * @see <a href="http://java.sun.com/docs/books/tutorial/post1.0/ui/eventmodel.html">Tutorial: Java 1.1 Event Model</a>
 *
 * @author Carl Quinn
 * @version 1.18 04/13/06
 * @since 1.1
 */
public interface ActionListener extends EventListener {

    /**
     * Invoked when an action occurs.
     */
    public void actionPerformed(ActionEvent e);

}[/code]
Para tratar um [i]ActionEvent[/i] recebido por um [i]JButton[/i], você deve criar uma classe que implemente a interface [i]ActionListener[/i] e passar um objeto desta sua classe para o método [i]addActionListener[/i] do objeto [i]JButton[/i]. Vamos ver um exemplo bem simples, onde uma telinha bem simples tem um botão que, ao ser clicado, imprime uma mensagem no console. 
Mas antes, vamos criar o nosso listener, ou seja, uma classe que implemente a interface ActionListener. É essa classe que nos dará objetos capazes de tratar um [i]ActionEvent[/i]. Tal "tratamento" é definido pelo implementação que damos ao método [i]actionPerformed[/i], declarado pela interface [i]ActionListener[/i]. No nosso caso, devemos implementar então este método de forma que ao ser executado, imprima alguma mensagem no console:
[code]package help.guj.thiagooliver;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyButtonHandler implements ActionListener {

	public void actionPerformed(ActionEvent e) {
		System.out.println("OUCH! That hurts!");
	}

}[/code]
Eu tenho o costume de prefixar o nome das minhas classes que implementam listeners com a palavra "Handler", que é algo como manipulador, controlador em inglês. De "controlador" para "tratador" é um pulo, convenhamos...  :lol:
Agora sim! Se criarmos um objeto do tipo [i]MyButtonHandler[/i], e passarmo-lo por parâmetro para o método [i]addActionListener[/i] de um determinado [i]JButton[/i], sempre que este for clicado irá, internamente, invocar o método [i]actionPerformed[/i] a apartir do nosso objeto [i]MyButtonHandler[/i]. Ou seja, Sempre que este [i]JButton[/i] for clicado, aparecerá no console a seguinte mensagem:
[code]OUCH! That hurts![/code]
Vamos fazer agora a telinha de exemplo:
[code]
package help.guj.thiagooliver;

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JButton;
import javax.swing.JFrame;

public class SimpleButtonTest extends JFrame {
	private JButton btn;
	
	public SimpleButtonTest(){
		super("Button Test");
		
		btn = new JButton("OK");
		MyButtonHandler handler = new MyButtonHandler();
		btn.addActionListener(handler);
		
		Container c = getContentPane();
		c.add(btn, BorderLayout.CENTER);
		
		setSize(200, 100);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}

	public static void main(String[] args) {
		SimpleButtonTest app = new SimpleButtonTest();
		app.setVisible(true);
	}

}[/code]
Podemos inclusive adicionar mais de um listener do mesmo tipo. Suponha que queiramos exibir, apos o [i]JButton[/i] ser clicado, também uma mensagem em uma caixa de diálogo. Para isso, vamos criar um outro listener:
[code]package help.guj.thiagooliver;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;

public class MyOtherButtonHandler implements ActionListener {

	public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(null, "Cut it out!!!");
	}

}
[/code]
E agora fazemos alguma pequenas alterações na classe de teste:
[code]package help.guj.thiagooliver;

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JButton;
import javax.swing.JFrame;

public class SimpleButtonTest extends JFrame {
	private JButton btn;
	
	public SimpleButtonTest(){
		super("Button Test");
		
		btn = new JButton("OK");
		MyButtonHandler handler = new MyButtonHandler();
		MyOtherButtonHandler otherHandler = new MyOtherButtonHandler();
		btn.addActionListener(otherHandler);
		btn.addActionListener(handler);
		
		Container c = getContentPane();
		c.add(btn, BorderLayout.CENTER);
		
		setSize(200, 100);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}

	public static void main(String[] args) {
		SimpleButtonTest app = new SimpleButtonTest();
		app.setVisible(true);
	}

}

Execute e veja que agora não só temos a mensagem no console, como também temos uma caixa de diáloco com a simpática mensagemzinha, cada vez que clicamos no botão.
Experimente também inverter a ordem em que você adiciona listeners de um mesmo tipo, e depois execute.
Bom, mas como eu disse antes, os componentes gráficos podem suportar vários tipos de eventos. Um outro exemplo, ainda com o JButton, poderia ser eventos relacionados à posição do mouse. Vamos criar um listener do tipo MouseMotionListener. Esta interface tem um método para tratar quando o ponteiro do mouse “entra” no componente, quando o ponteiro do mouse “sai” do componente, quando se aperta o botão do mouse no componente, quando se solta o botão do mouse no componente, ou quando se clica no componente. Vejamos uma implementação bem simples.

[code]package help.guj.thiagooliver;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JOptionPane;

public class MouseHandler implements MouseListener{

public void mouseClicked(MouseEvent e) {
	JOptionPane.showMessageDialog(null, "Please! Leave me alone!!!");
}

public void mouseEntered(MouseEvent e) {
	System.out.println("Oh, God! Please: Make hin do not click me...");
}

public void mouseExited(MouseEvent e) {
	System.out.println("Thank God it gone away...");
}

public void mousePressed(MouseEvent e) {
	System.err.println("Damn it! Get lost!");
}

public void mouseReleased(MouseEvent e) {
	System.out.println("Ah! What a relief!!!");
}

}
[/code]
Agora, vamos tirar a linha que adiciona o MyOtherButtonHandler (Não sei porque, mas esse terceiro listener meio que suprime o tratamento do evento mouseClicked…). Deixe a classe de teste assim:

[code]package help.guj.thiagooliver;

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JButton;
import javax.swing.JFrame;

public class SimpleButtonTest extends JFrame {
private JButton btn;

public SimpleButtonTest(){
	super("Button Test");
	
	btn = new JButton("OK");
	MyButtonHandler handler = new MyButtonHandler();
	MouseHandler mouseHandler = new MouseHandler();
	btn.addActionListener(handler);
	btn.addMouseListener(mouseHandler);
	
	Container c = getContentPane();
	c.add(btn, BorderLayout.CENTER);
	
	setSize(200, 100);
	setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String[] args) {
	SimpleButtonTest app = new SimpleButtonTest();
	app.setVisible(true);
}

}
[/code]
Execute-a e brique passando o mouse sobre o botão, fora do botão, apertando e mantendo pressionado o botão do mouse sobre o botão, etc. Acompanhe as mensagens do console.
Agora, vamos fazer uma outra coisa: Vamos adicionar um botão para fechar a janela. Esse botão terá que tratar um ActionEvent de forma que feche o programa ao ser clicado.
Vamos criar então mais um listener que implemente ActionListener que faça o que estamos querendo.

[code]package help.guj.thiagooliver;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class ExitHandler implements ActionListener {

public void actionPerformed(ActionEvent e) {
	JButton b = (JButton)e.getSource();
	Window window = (Window) b.getRootPane().getParent();
	window.dispose();
}

}
[/code]
Todo objeto que representa um Evento dos componentes gráficos de Java têm como superclasse (direta ou indiretamente) a classe abstrata java.awt.AWTEvent. Esta classe provê, entre outros, o método getSource, que retorna uma referência do tipo Object a qual referencia o objeto (componente gráfico) que disparou o evento. No nosso listener acima utilizamos esse método para recuperar o JButton que disparou o ActionEvent.
Nas linhas seguintes busca-se a janela na qual o JButton está inserido e a “dispensa” (fecha).
O programa principal agora está assim:

[code]package help.guj.thiagooliver;

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JButton;
import javax.swing.JFrame;

public class SimpleButtonTest extends JFrame {
private JButton btnOk, btnExit;

public SimpleButtonTest(){
	super("Button Test");
	
	btnOk = new JButton("OK");
	MyButtonHandler handler = new MyButtonHandler();
	MouseHandler mouseHandler = new MouseHandler();
	btnOk.addActionListener(handler);
	btnOk.addMouseListener(mouseHandler);
	
	btnExit = new JButton("Exit");
	ExitHandler exitHandler = new ExitHandler();
	btnExit.addActionListener(exitHandler);
	
	Container c = getContentPane();
	c.add(btnOk, BorderLayout.NORTH);
	c.add(btnExit, BorderLayout.SOUTH);
	
	setSize(200, 125);
	setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String[] args) {
	SimpleButtonTest app = new SimpleButtonTest();
	app.setVisible(true);
}

}
[/code]
Rode o programa e teste o botão “Exit”. Funciona que é uma beleza.
Só tem uma coisa que não está legal: O listener do botão “exit”.
Nada impede que eu adicione esse listener a um JTextField, por exemplo…
Nesse caso, teríamos um problema seríssimo!!! Se o JTextField disparasse um ActionEvent, o método actionPerformed de ExitHandler seria executado. Me diga: O que aconteceria, neste caso, quando o Java fosse executar essa linha:

JButton b = (JButton)e.getSource();

:?: :?: :?:
Simples!

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JTextField cannot be cast to javax.swing.JButton
	at help.guj.thiagooliver.ExitHandler.actionPerformed(ExitHandler.java:16)
	at javax.swing.JTextField.fireActionPerformed(Unknown Source)
	at javax.swing.JTextField.postActionEvent(Unknown Source)
	at javax.swing.JTextField$NotifyAction.actionPerformed(Unknown Source)
	at javax.swing.SwingUtilities.notifyAction(Unknown Source)
	at javax.swing.JComponent.processKeyBinding(Unknown Source)
	at javax.swing.JComponent.processKeyBindings(Unknown Source)
	at javax.swing.JComponent.processKeyEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
	at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
	at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
	at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

Uma bela e gorda ClassCastException, pois o getSource de ActionEvent irá retornar o JTextField e vamos tentar “transformá-lo” em um JButton… Aí é pau… :twisted:
Das duas uma, ou tratamos essas condições excepcionais, verificando antes que tipo de componente o getSource está nos retornando, ou então reduzimos ao máximo o escopo do nosso listener ExitHandler.
A primeira opção pode tornar o nosso listener mais flexível, reutilizável, apropriado se formos desenvolver várias classes com um botão que serve apenas para “fechar” a janela que detém o dito botão. Já a segunda opção vai ser bem específica, de escupo bem pequeno, ideal se não temos pretensão de reutilizar o código de ExitHandler.
[size=18]Neste segundo caso é [color=darkblue]onde se juntam os conceitos de listener e de classes anônimas[/color].[/size]
Lembra que não temos criar uma variável que seja do tipo de uma classe anônima? O máximo que podemos é criar uma variável de um determinado tipo X que referencia um objeto de uma classe anônima que ou éfilha de X ou implementa X, se X for uma interface. O escopo de uma classe abstrata, como pode ver, é beeeem restrito.
Vamos refazer a classe de teste então, associando ao botão “exit” um objeto de uma classe anônima que implementa ActionListener:

[code]package help.guj.thiagooliver;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class SimpleButtonTest extends JFrame {
private JButton btnOk, btnExit;

public SimpleButtonTest(){
	super("Button Test");
	
	btnOk = new JButton("OK");
	MyButtonHandler handler = new MyButtonHandler();
	MouseHandler mouseHandler = new MouseHandler();
	btnOk.addActionListener(handler);
	btnOk.addMouseListener(mouseHandler);
	
	btnExit = new JButton("Exit");
	btnExit.addActionListener(
		new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				SimpleButtonTest.this.dispose();
			}
		}
	);
	
	Container c = getContentPane();
	c.add(btnOk, BorderLayout.NORTH);
	c.add(btnExit, BorderLayout.SOUTH);
	
	setSize(200, 125);
	setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String[] args) {
	SimpleButtonTest app = new SimpleButtonTest();
	app.setVisible(true);
}

}
[/code]
Veja que agora temos um objeto de classe anônima sendo passado para o addActionListener do botão “exit”. Perceba também que, devido ao fato de a classe anônima estar inserida no escopo da classe SimpleButtonTest, podemos utilizar this diretamente a partir do nome desta classe para nos referenciarmos à instancia atual de SimpleButtonTest.
Por outro lado, é fácil notar o potencial de emporcalhamento que uma classe anônima pode ter. Mesmo indentando organizadinho o código, se a implementação da classe anônima ficar muito grande, o código começa a ficar difícil de ler, fica difícil de perceber que temos ali, de fato, uma classe anônima.
Se executar o código acima, verá que temos o mesmo comportamento de antes.
Quanto ao caso para deixar aquele nosso listener ExitHandler reutilizável, fica como exercício pra você, ok?
Espero ter ajudado (E que ninguém tenha dormido…)
Qualquer dúvida, pergunte mais!
Divirta-se!

P.S. Sempre consulte a documentação das classes do Java. Nela você pode encontrar todos os addXxxxxListeners disponíveis para cada classe de componente gráfico que deseja utilizar

API Java 6:
http://java.sun.com/javase/6/docs/api/index.html

API Java 5:
http://java.sun.com/j2se/1.5.0/docs/api/

API Java 2:
http://java.sun.com/j2se/1.4.2/docs/api/

:shock: :shock: :shock:

Cara… se merece um troféu! hauhauhauhauha…
Teacher Mantu!

Acredito que depois dessa aula ninguem vai postar mais nada sobre tratamento de eventos nem sobre classes anônimas

parabens mantu!

[quote=fabiocsi]Acredito que depois dessa aula ninguem vai postar mais nada sobre tratamento de eventos nem sobre classes anônimas

parabens mantu![/quote]
Por mais que fosse uma aaaula como você disse (O que, de fato, não chega nem perto. Quem me dera :oops: ), pode ter certeza que sempre irá alguél refazendo a mesma pergunta… Por isso eu sempre guardo o link de alguns tópicos no meu favoritos :lol:

Já está em favoritos, assim como aquela da Formatação de um post. hehhehee…

Mantu, eu não sei se te parabenizo ou se te agradeço…enfim, mto bom :stuck_out_tongue:

Acabei de ler agora (Depois de 1 hora lendo), e pretendo ler novamente ate fixar o que vc passou.

Mantu wrote:

Pode dexá que eu vo tentar fazer e qualquer duvida eu posto aqui.

Ah, antes uma coisa…

Mantu wrote:

Essa classe só funcionou comigo quando importei java.awt.Window. Antes tava dando erro apontando para o “W” do Window window = (Window) b.getRootPane().getParent(); .
Normal isso?

Abraços, e muito Obrigado! :stuck_out_tongue:

Obs: Acho que começo a intender da sujeira de código que o pessoal fala que o eclipse gera usando o VEP.

Normalíssimo. O erro é exatamente pelo fato de não ter o import.

Ah, só pra deixar a maneira como eu fiz para deixar o listener ExitHandler reutilizável, vai o código:

[code]import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.awt.Window;

public class ExitHandler implements ActionListener
{

public void actionPerformed(ActionEvent sair) 
{
	if (sair.getSource() instanceof JButton)
	{
		JButton b = (JButton)sair.getSource();
		Window window = (Window) b.getRootPane().getParent();
		window.dispose();
	}
		
}

}[/code]

Bom, agora quando eu adiciono um JTextField e pressiono enter, ele não apresenta mais os erros de antes.

Era isso mesmo?? :stuck_out_tongue:

Legal! É isso mesmo! Parabéns! :thumbup:

Oi, Mantu!
Obrigado pelo seu belo post!
Sensacional!