Tratamento de Evento  XML
Índice dos Fóruns » Java Básico
Autor Mensagem
Thiago.Oliver
Thread.start()
[Avatar]

Membro desde: 15/06/2007 02:12:47
Mensagens: 45
Localização: São Bernardo do Campo - SP
Offline

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:



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

[]'s


"Até a pé nós iremos, para o que der e vier, mas o certo é que nós estaremos com o Gremio onde o Gremio estiver..."
arochafademac
JavaChild
[Avatar]

Membro desde: 21/06/2007 18:35:21
Mensagens: 113
Offline

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?


'Garbage Collector X collector NET'
NET = Pede pra sair!, não vai? ahh..q peninha
Garbage Collector = Poe no Saco!
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

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:


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:

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:

Teremos a seguinte saída:

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:

Qual é o problema que temos aqui? Aquele método eval, embora público, é inacessível, diretamente, a partir de anonymous, pois o tipo de anonymous é A, e a classe A não declara nenhum método chamado eval. 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:

Mais informações sobre reflection aqui
Você pode se perguntar ainda:
Thiago.Oliver wrote: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?

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 getClass para obter um objeto Class referente à classe dos nossos objetos e, apartir destes objetos Class, utilizaremos o método getName :

O resultado é o seguinte:

Quando executamos anonymousA.getClass(), por exemplo, é retornado um objeto java.lang.Class que representa a classe anônima que criamos para a instanciação da variável anonymousA. Quando invocamos então, desse objeto Class em questão, o método getName, foi retornado o nome help.guj.thiagooliver.AnonymousMaNonTroppo$1
Veja que interessante: O Java nomeia as classes anônimas como se fossem 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
Em seguida, vemos que a superclasse do objeto referenciado por wellKnownA é Object, e a de anonymousA é A.

Agora, falando um pouco sobre eventos...
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 listeners 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 javax.swing.JButton, ao ser clicado, um dos eventos que são disparados é (um objeto da classe) java.awt.event.ActionEvent.
Ao receber um ActionEvent, o JButton verifica se tem associado em si algum listener capaz de responder, de tratar esse ActionEvent. A classe JButton nos permite associar um ou mais listener capazes de tratar um ActionEvent, através do método addActionListener. Este método recebe como parâmetro um objeto do tipo java.awt.ActionListener. ActionListener é um listener que responde a aventos do tipo ActionEvent. Logo, se um JButton recebe um ActionEvent, ele passa esse evento para todos os seus ActionListener previamente adicionados. Cada um desses ActionListener vai tratar o evento passado.
Thiago.Oliver wrote:
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 JButton???

Simples: Ele não sabe. É você quem tem que dizer o que fazer. Por isso mesmo todos os listeners são interfaces, 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):

Para tratar um ActionEvent recebido por um JButton, você deve criar uma classe que implemente a interface ActionListener e passar um objeto desta sua classe para o método addActionListener do objeto JButton. 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 ActionEvent. Tal "tratamento" é definido pelo implementação que damos ao método actionPerformed, declarado pela interface ActionListener. No nosso caso, devemos implementar então este método de forma que ao ser executado, imprima alguma mensagem no console:

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...
Agora sim! Se criarmos um objeto do tipo MyButtonHandler, e passarmo-lo por parâmetro para o método addActionListener de um determinado JButton, sempre que este for clicado irá, internamente, invocar o método actionPerformed a apartir do nosso objeto MyButtonHandler. Ou seja, Sempre que este JButton for clicado, aparecerá no console a seguinte mensagem:

Vamos fazer agora a telinha de exemplo:

Podemos inclusive adicionar mais de um listener do mesmo tipo. Suponha que queiramos exibir, apos o JButton ser clicado, também uma mensagem em uma caixa de diálogo. Para isso, vamos criar um outro listener:

E agora fazemos alguma pequenas alterações na classe de teste:

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.

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:

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.

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:

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:


Simples!

Uma bela e gorda ClassCastException, pois o getSource de ActionEvent irá retornar o JTextField e vamos tentar "transformá-lo" em um JButton... Aí é pau...
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.
Neste segundo caso é onde se juntam os conceitos de listener e de classes anônimas.
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:

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/

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
Ratao
Virtual Machine Man
[Avatar]

Membro desde: 14/05/2006 22:09:25
Mensagens: 529
Localização: Cachoeiro de Itapemirim - ES
Offline



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

"Não existe limites para a mente humana... sendo então ilimitado nosso poder de realização."
Victor Zangerolame Fim
[Email] [MSN]
fabim
GUJ Master
[Avatar]

Membro desde: 14/12/2006 19:30:03
Mensagens: 1268
Localização: Vitoria - Espirito Santo
Offline

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

parabens mantu!

ειπεν αυτη ο ιησους εγω ειμι η αναστασις και η ζωη ο πιστευων εις εμε καν αποθανη ζησεται

Sun Certified Web Component Developer
Sun Certified Java Programmer
Sun Certified Java Associate
Sun Certified Business Component Developer - Em Andamento
Bacharelando em Sistemas de Informacao


[MSN]
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

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

parabens mantu!

Por mais que fosse uma aaaula como você disse (O que, de fato, não chega nem perto. Quem me dera ), 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

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
Ratao
Virtual Machine Man
[Avatar]

Membro desde: 14/05/2006 22:09:25
Mensagens: 529
Localização: Cachoeiro de Itapemirim - ES
Offline

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

"Não existe limites para a mente humana... sendo então ilimitado nosso poder de realização."
Victor Zangerolame Fim
[Email] [MSN]
Thiago.Oliver
Thread.start()
[Avatar]

Membro desde: 15/06/2007 02:12:47
Mensagens: 45
Localização: São Bernardo do Campo - SP
Offline

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

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

Mantu wrote:
Quanto ao caso para deixar aquele nosso listener ExitHandler reutilizável, fica como exercício pra você, ok?


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!


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

"Até a pé nós iremos, para o que der e vier, mas o certo é que nós estaremos com o Gremio onde o Gremio estiver..."
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

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

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
Thiago.Oliver
Thread.start()
[Avatar]

Membro desde: 15/06/2007 02:12:47
Mensagens: 45
Localização: São Bernardo do Campo - SP
Offline

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



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

Era isso mesmo??

"Até a pé nós iremos, para o que der e vier, mas o certo é que nós estaremos com o Gremio onde o Gremio estiver..."
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

Legal! É isso mesmo! Parabéns!

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
hackum
Java Ninja
[Avatar]

Membro desde: 18/11/2009 18:45:06
Mensagens: 287
Localização: Minas Gerais.
Offline

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

"O topo da inteligência é alcançar a humildade."
(Textos Judaicos)

"Ensinar é aprender duas vezes."
(Joseph Joubert)
 
Índice dos Fóruns » Java Básico
Ir para:   
Powered by JForum 2.1.8 © JForum Team