Programação Orientada a Evento (em inglês Event-Driven Program ou Architeture) é um paradigma de arquitetura software que trata de ações disparadas por eventos.
Por eventos, podemos entender por exemplo:
Neste curso vamos tratar de Interface de Usuário (em inglês Graphical User Interface ou GUI), que é fazer uma interface para que o usuário possa usar o seu programa. Tipicamente faremos uma janela com alguns botões, caixa de texto de entrada, tabelas, etc...
Em java, usaremos as bibliotecas awt
e swing
. Para definir o funcionamento de qualquer elemento estas bibliotecas (assim como a maioria das bibliotecas de GUI) usam o padrão orientado a eventos.
A primeira coisa que devemos aprender é que este padrão separa a lógica de desenhar a interface, da lógica de interação da interface,
ou seja: vamos desenhar uma interface em uma parte do código e definir funcionamento desta interface em outra parte.
Mais explicitamente:
Mas primeiro... vamos treinar como separar a definição de uma ação da criação da classe que faz esta ação, definindo a ação depois da criada do objeto
Primeiro vamos relembrar como fizemos em LPOO, definindo um comportamento em uma classe e testando:
Definição da classe com o comportamento voar
:
public class Pato { public void voar() { System.out.println("Definido dentro da classe: O pato voa"); } }
Testando a classe:
public class TestePato { public static void main(String[] args) { Pato pato = new Pato(); pato.voar(); } }
Saída
Definido dentro da classe: O pato voa
Ok, agora vamos treinar como definir o comportamento voar
depois da criação do objeto pato
:
Primeiro vamos definir a interface da ação de voar (lembrando que aqui interface
quer dizer classe abstrata)
public interface AcaoVoar { public void fazVoar(); }
Agora podemos criar uma função void fazVoar()
, inclusive ter essa função como parâmetro ou passar essa função como argumento para outra função.
public class Pato { // podemos ter a acao de voar como atributo AcaoVoar acaoVoar; // podemos passar qualquer acao de voar como parametro // para definir (ou redefinir) a acao de voar do pato public void setAcaoVoar(AcaoVoar aAcaoVoar){ this.acaoVoar = aAcaoVoar; } // finalmente pode usar a acao de voar public void voar() { this.acaoVoar.fazVoar(); } }
Agora vamos criar uma ação possivel, entre outras
public class AcaoVoarConcreta implements AcaoVoar { @Override public void fazVoar() { System.out.println("Classe concreta que definine acao: faz voar"); } }
Agora vamos testar: vamos criar o objeto e depois definir a sua ação
public class TestaPato { public void testaPato() { Pato pato = new Pato(); // setando como objeto anonimo de classe externa pato.setAcaoVoar(new AcaoVoarConcreta()); pato.voar(); } public static void main(String[] args) { new TestaPato().testaPato(); } }
O resultado:
Classe concreta que definine acao: faz voar
Podemos reescrever o teste da seguinte forma:
ATENÇÃO: Você não precisa saber todas, apenas uma delas
public class TestaPato { public void testaPato() { Pato pato = new Pato(); // setando como objeto anonimo de classe externa pato.setAcaoVoar(new AcaoVoarConcreta()); System.out.println("\n1) Pato voando"); pato.voar(); System.out.println("\n"); // setando como inner class pato.setAcaoVoar(new AcaoVoarInnerClass()); System.out.println("\n2) Pato voando"); pato.voar(); System.out.println("\n"); // setando como classe anonima pato.setAcaoVoar(new AcaoVoar() { @Override public void fazVoar() { System.out.println("Acao de classe anonima: faz voar"); } }); System.out.println("\n3) Pato voando"); pato.voar(); System.out.println("\n"); // setando como expressao lambda (VOCE NAO PRECISA SABER EXPRESSOES lambda) pato.setAcaoVoar(() -> System.out.println("Acao como expressao lambda: faz voar")); System.out.println("\n4) Pato voando"); pato.voar(); System.out.println("\n"); } // Definicao de inner class (uma classe dentro de outra classe) class AcaoVoarInnerClass implements AcaoVoar{ @Override public void fazVoar() { System.out.println("Acao definida em classe interna: faz voar"); } } public static void main(String[] args) { new TestaPato().testaPato(); } }
E se eu quiser que a ação voar seja uma lista de várias ações que eu queira adicionar ao objeto?
Agora podemos também fazer com que Pato
tenha uma lista de ações de voar, e adicionar ações de voar no pato
para que ele faça todas adicionadas quando voar.
Reescreveremos a classe Pato
como a seguir
import java.util.ArrayList; import java.util.List; public class Pato { List<AcaoVoar> acaoVoarList = new ArrayList<>(); public void addAcaoVoar(AcaoVoar aAcaoVoar){ this.acaoVoarList.add(aAcaoVoar); } public void voar() { for(AcaoVoar acaoVoar : this.acaoVoarList) { acaoVoar.fazVoar(); } } }
Reescreveremos o teste como a seguir (mudando apenas setAcaoVoar
para addAcaoVoar
)
public class TestaPato { public void testaPato() { Pato pato = new Pato(); pato.addAcaoVoar(new AcaoVoarConcreta()); System.out.println("\n1) Pato voando"); pato.voar(); System.out.println("\n"); pato.addAcaoVoar(new AcaoVoarInnerClass()); System.out.println("\n2) Pato voando"); pato.voar(); System.out.println("\n"); pato.addAcaoVoar(new AcaoVoar() { @Override public void fazVoar() { System.out.println("Acao de classe anonima: faz voar"); } }); System.out.println("\n3) Pato voando"); pato.voar(); System.out.println("\n"); pato.addAcaoVoar(() -> System.out.println("Acao como expressao lambda: faz voar")); System.out.println("\n4) Pato voando"); pato.voar(); System.out.println("\n"); } // Definicao de inner class (uma classe dentro de outra classe) class AcaoVoarInnerClass implements AcaoVoar{ @Override public void fazVoar() { System.out.println("Acao definida em classe interna: faz voar"); } } public static void main(String[] args) { new TestaPato().testaPato(); } }
Vamos testar o que aprendemos em um botão JButton
:
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class TesteBotao { public void testeBotao() { // Primeiro vamos fazer uma janela para colocar o botao JFrame janela = new JFrame(); // Agora vamos criar o botao e colocar na janela JButton botao = new JButton("Botao Teste"); janela.add(botao); // Agora vamos criar a acao usando inner class // (poderia ser criada de qualquer jeito, desde que implemente ActionListener) AcaoBotao acaoBotao = new AcaoBotao(); // Vamos inserir a acao no botao botao.addActionListener(acaoBotao); // Agora vamos fazer algumas configuracoes que vamos aprender mais adiante para que servem // 1 - redimensiona para caber todos componentes janela.pack(); // 2 - configura para terminar o programa quando a janela for fechada janela.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 3 - torna a janela visivel janela.setVisible(true); } // Este eh o ActionListener que vai ser inserido no botao class AcaoBotao implements ActionListener{ // Um action listener deve ter um actionPerformed // esta eh a acao que sera acionada quando o botao (evento) for pressionado @Override public void actionPerformed(ActionEvent e) { System.out.println("O Botao foi pressionado!"); } } public static void main(String[] args) { new TesteBotao().testeBotao(); } }
Também podemos inserir ações em botões de outras formas:
import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class TesteBotoes { public void testeBotoes() { JFrame janela = new JFrame(); // Vamos incluir varios botoes, precisamos selecionar um layout janela.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); // criando acao por inner class JButton botaoInnerClass = new JButton("Botao Inner class"); janela.add(botaoInnerClass); botaoInnerClass.addActionListener(new AcaoBotao()); // criando acao por classe anonima JButton botaoClasseAnonima = new JButton("Botao classe anonima"); janela.add(botaoClasseAnonima); botaoClasseAnonima.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Classe Anonima: o botao foi pressionado"); } }); // criando acao por expressao lambda JButton botaoLambda = new JButton("Botao lambda expression"); janela.add(botaoLambda); botaoLambda.addActionListener((ActionEvent e) -> System.out.println("Lambda Expression: o botao foi pressionado")); janela.pack(); janela.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); janela.setVisible(true); } class AcaoBotao implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { System.out.println("Inner class: O Botao foi pressionado!"); } } public static void main(String[] args) { new TesteBotoes().testeBotoes(); } }
.