Qual a melhor forma de tratar eventos?

olá,

em uma GUI(swing) com varios botoes, como devo tratar os eventos nesses botoes?
é melhor cada botão ter uma classe própria pra tratar seu evento? ou é melhor uma classe que implementa actionListener e tem um monte de IFs pra tratar tudos os eventos?

obrigado povos!

Se possível, evite utilizar vários IFs. Uma classe por botão é, na minha opinião, uma implementação mais correta. Vários IFs encadeados podem dificultar a leitura e a escrita do código.

isso e relativo…

siga o padrão da mãe Sun

mas qual eh o padrão da mamae Sun?

[quote=souarte]olá,

em uma GUI(swing) com varios botoes, como devo tratar os eventos nesses botoes?
é melhor cada botão ter uma classe própria pra tratar seu evento? ou é melhor uma classe que implementa actionListener e tem um monte de IFs pra tratar tudos os eventos?

obrigado povos![/quote]

A resposta é: use o mesmo objeto para responser a eventos de botões que fazem a mesma coisa.
Por exemplo, se vc tem um menu salvar e um botão de toolbar salvar ambos devem chamar o mesmo codigo.

Em swing isso é feito com o uso da classe Action. Uma action pode ser associada a muitos botões diferentes (inclusive menus). Action é uma implementação do padrão Command.

bom, então, se vc tem 50 botões que fazem coisas diferentes terá 50 Actions. Acredite, é muito melhor que 50 ifs.

Eu acho mais organizado implementar o listner na própria interface, você evita a utilização de uma pancada de classes internas.

Implementando um ActionListner, por exmeplo…Eu implemento o método actionPerformed e dentro coloco os IF´s…Só que cada IF chama um método específico para o tratamento de um botão específico, por exemplo.

Todo o ActionEvent passa antes pela seleção e depois cai em seu método de tratamento específico…

bom brigado pelas dicas. eh ki ja ouvi falar q nao eh bom usar muitos ifs.
e queria saber o que fazer numa situação dessas.

obrigado pessoals!!

Para facilitar a sua vida, vc pode consultar a API da Sun para saber os eventos de cada ação … e também usar o eclipse, que automaticamente gera pra vc os eventos necessarios. :wink:

Mas não é só pq falaram aqui que você não deve usar…Quem disse que não se deve usar tem que dizer pq, e com base no argumento você decide…O único mal que vejo é o processamento de um condicional a mais…E se isso me possibilitar a construção de um código mais limpo, organizado e sem dezenas de classes internas, acho um preço bastante justo…Sai muito barato, eu diria…

[quote]
Mas não é só pq falaram aqui que você não deve usar…Quem disse que não se deve usar tem que dizer pq, e com base no argumento você decide…O único mal que vejo é o processamento de um condicional a mais…E se isso me possibilitar a construção de um código mais limpo, organizado e sem dezenas de classes internas, acho um preço bastante justo…Sai muito barato, eu diria…[/quote]

olá novamente,
me desculpa se eu estiver errado, pois sou muito iniesperiente, mas imagino que os ifs são até melhor em termos de processamento e memória que criar um novo objeto pra cada evento diferente. mas criar ifs não deixa o código muito orientado a objetos e essa é a desvantagem. bom, me corrijam se estiver errado.

até maiss.

Vc está errado estude mais colega!

[quote=eclipso]Eu acho mais organizado implementar o listner na própria interface, você evita a utilização de uma pancada de classes internas.

Implementando um ActionListner, por exmeplo…Eu implemento o método actionPerformed e dentro coloco os IF´s…Só que cada IF chama um método específico para o tratamento de um botão específico, por exemplo.

Todo o ActionEvent passa antes pela seleção e depois cai em seu método de tratamento específico… [/quote]

Esta forma de implementar listeners em swing tem vários problemas, mas o principal é que não ha controle sobre a acção. Action é um objeto que é muito mais que um listener. ele controla o estado dos botões associados a ele. De todos os botões associados a ele. É mais simples.

Outro problema é ineficencia. Se tiver N if e a acção mais frequente é a ultima vc corre N-1 ifs completamente sem propósito. Com um listener para cada ação vc nem sequer tem if. Um ganho absurdo de eficiencia.
além disso os if se apoiam em comparação de objetos. Para isso é preciso ter acesso às referencias originais o que leva o programador a criar inner-classes para tratar eventos. Pior, faz o próprio objeto implementar a interface de listener. Tudo isto são anti-paterns em swing.
As classes de frame ficam enormes e é estremamente dificil dar manutenção.
O swing usa o padrão composite para definir JComponent. Tire vantagem disso. Construa as intefaces com um builder ou uma factory. Faça associação de listeners com o component de forma desacoplada. não use if nem ==
É muito , muito mais simples porque na manutenção basta mudar a factory ou o builder para criar telas diferentes ou com mais/ menos coisas. Ha herança das factories , etc… o Swing foi desenhado como uma API base , não se devem usar os seus componentes directamente ( a menos que estejamos criando algo muito, muito, simples ou experimental)

[quote=sergiotaborda][quote=eclipso]Eu acho mais organizado implementar o listner na própria interface, você evita a utilização de uma pancada de classes internas.

Implementando um ActionListner, por exmeplo…Eu implemento o método actionPerformed e dentro coloco os IF´s…Só que cada IF chama um método específico para o tratamento de um botão específico, por exemplo.

Todo o ActionEvent passa antes pela seleção e depois cai em seu método de tratamento específico… [/quote]

Esta forma de implementar listeners em swing tem vários problemas, mas o principal é que não ha controle sobre a acção. Action é um objeto que é muito mais que um listener. ele controla o estado dos botões associados a ele. De todos os botões associados a ele. É mais simples.

Outro problema é ineficencia. Se tiver N if e a acção mais frequente é a ultima vc corre N-1 ifs completamente sem propósito. Com um listener para cada ação vc nem sequer tem if. Um ganho absurdo de eficiencia.
além disso os if se apoiam em comparação de objetos. Para isso é preciso ter acesso às referencias originais o que leva o programador a criar inner-classes para tratar eventos. Pior, faz o próprio objeto implementar a interface de listener. Tudo isto são anti-paterns em swing.
As classes de frame ficam enormes e é estremamente dificil dar manutenção.
O swing usa o padrão composite para definir JComponent. Tire vantagem disso. Construa as intefaces com um builder ou uma factory. Faça associação de listeners com o component de forma desacoplada. não use if nem ==
É muito , muito mais simples porque na manutenção basta mudar a factory ou o builder para criar telas diferentes ou com mais/ menos coisas. Ha herança das factories , etc… o Swing foi desenhado como uma API base , não se devem usar os seus componentes directamente ( a menos que estejamos criando algo muito, muito, simples ou experimental)

[/quote]

Boa tarde. Desculpem-me por estar “desenterrando” o tópico, mas fiquei interessado no que você comentou Sérgio. De que maneira tu sugere que seja feita esta associação entre os listeners e os componentes? A idéia do builder ou da factory é pra criar, por exemplo, grupos de componentes, tipo um painel com seus componentes internos? E os listeners, ficam aonde?

Obrigado pela atenção.

[quote=sergiotaborda][quote=eclipso]Eu acho mais organizado implementar o listner na própria interface, você evita a utilização de uma pancada de classes internas.

Implementando um ActionListner, por exmeplo…Eu implemento o método actionPerformed e dentro coloco os IF´s…Só que cada IF chama um método específico para o tratamento de um botão específico, por exemplo.

Todo o ActionEvent passa antes pela seleção e depois cai em seu método de tratamento específico… [/quote]

Esta forma de implementar listeners em swing tem vários problemas, mas o principal é que não ha controle sobre a acção. Action é um objeto que é muito mais que um listener. ele controla o estado dos botões associados a ele. De todos os botões associados a ele. É mais simples.

Outro problema é ineficencia. Se tiver N if e a acção mais frequente é a ultima vc corre N-1 ifs completamente sem propósito. Com um listener para cada ação vc nem sequer tem if. Um ganho absurdo de eficiencia.
além disso os if se apoiam em comparação de objetos. Para isso é preciso ter acesso às referencias originais o que leva o programador a criar inner-classes para tratar eventos. Pior, faz o próprio objeto implementar a interface de listener. Tudo isto são anti-paterns em swing.
As classes de frame ficam enormes e é estremamente dificil dar manutenção.
O swing usa o padrão composite para definir JComponent. Tire vantagem disso. Construa as intefaces com um builder ou uma factory. Faça associação de listeners com o component de forma desacoplada. não use if nem ==
É muito , muito mais simples porque na manutenção basta mudar a factory ou o builder para criar telas diferentes ou com mais/ menos coisas. Ha herança das factories , etc… o Swing foi desenhado como uma API base , não se devem usar os seus componentes directamente ( a menos que estejamos criando algo muito, muito, simples ou experimental)

[/quote]

Pensei um pouco melhor e acho que compreendi o que você sugeriu, Sérgio.

Seria algo mais ou menos assim:

class XYZButton extends JButton {
   ActionListener listener;

   XYZButton (ActionListener listener) {
      this.listener = listener;
      this.addActionListener(listener);
   }
}
class XYZListener implements ActionListener {
   public void actionPerformed(ActionEvent evt) {
      //invocar controllers
   }
}

E aí, na Factory eu instanciaria o botão e associaria ao evento. É por aí, né?

O XYZListener não poderia ser considerado uma Estratégia (Strategy) do componente nesse caso? Logicamente seria mais interessante acrescentar um setActionListener pra poder mudar o comportamento do componente em tempo de execução…

Falou.

Não.

É mais assim :

class XYZAction extends Action {

   // trata evento com alguma logica de negocio
}

Action action = new XYZAction(); / /encapsula o comando

// associa a vários componentes
JButton button = ne JButton();
button.addActionListener(action ); 

JMenuItem  menu= ne JMenuItem  ();
menu.addActionListener(action );

Por ai. Mas é o action que é o objeto principal nesta historia e não o componente.
Repare que o componente é qualquer coisa , não tem nome especial, não é atributo de nenhum classe.

Não. Nada disso. O padrão aqui é Observer e Command. Todos os listeners são implementações de Observer e o Action do swing é além disso um command. O Actino do swing é um ActionListener mas ele é muito mais. Ele é um JavaBean que pode mudar a propriedades do componente a que está associado. Por exemplo, desabilitando a action, todos os botões associados a ela ficam desabilitados automáticamente. Isto porque o Swing é baseado em JavaBeans e todo o java bean permite ouvir a alteração de proprieades através do PropertyChangeListener.

Se o comportamento mudar, muda-se o action internamente e não a assoaicação entre ele e o botão. (não faz muito sentido um botão mudar de comportamento, mas … )

Eu sei que muitos controem o suas telas swing criando JFrames que implementam todos os listeners e têm centenas de atributos que são os botões ou qualquer outro componente a que o programador quer ter acesso. Isto é código-esparguete no seu melhor (ou seria pior ?). Não sei porquê mas com o swing o pessoal manda o SoC às urtigas no primeiro minuto.
Não. Swing é baseado em componentes e eventos. Não ha porque manter referencias aos componentes. Ele servem apenas para construir layouts. Se quer manter referencias mantenha dos modelos ou dos beans que são traduzidos na tela.

A ideia da fabrica ou do builder é ter um classe que monta as telas. Ela compõem o layout agregando os objetos certos fazendo uso de loops e polimorfismo da fabrica para criar telas ligeiramente diferentes. pode arecer chato e dificil no inicio mas a manutenção é muito simplificada porque esses objetos de build são autenticos scripts de layout o que permite alterear as coisas muito facilmente.

Hum… neste caso então o componente Controller do MVC na minha aplicação já seria a própria classe que extende Action, correto?

Eu vi algumas implementações onde criava-se um controlador e, posteriormente, uma classe que tratava eventos o invocava. Eu estava usando essa implementação inclusive, mas quando vi que estava criando um monte de ifs resolvi pesquisar uma alternativa.

Bom, obrigado pela resposta!

qual seria o problema se ao invez de usar o padrão command eu implementasse diretamente cada listener no botão? creio que é util implementar esse padrão command quanto eu tiver varios botões que fazem a mesma coisa… dai não teria problema criar varias actions mas quando em meu cenario tiver somente ações diferentes? não seria mais pratico criar um listener diretamente no botão e implementar sua ação la?