Problema Binding Bean-Class em JComboBox

17 Messages Forum Options Options
Permalink
Franzisk
Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Tenho um bean Servico e quero carregar o uma Lista desses beans mostrando no item do ComboBox a propriedade nome do Servico.
No bean que tou trabalhando tem uma propriedade listaServicos que é a ArrayList do tipo Servico, quero *associar* essa propriedade ao combobox.

Segue abaixo uma mensagem que enviei para uma lista em inglês se puder me dar uma dica eu ficaria muito grato.

Abraços
Francisco

Eu tenho esse Bean:
/*
* OrdemServicoFormBean.java
*/
package com.sikgraf.bean;

import com.jgoodies.binding.beans.ExtendedPropertyChangeSupport;
import com.sikgraf.listas.Servico;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class OrdemServicoFormBean {
   private Integer numeroOrdem;
   private Integer numeroOrcamento;
   private Integer numeroNotaFiscal;
   private Date dataCadastro;
   private String nomeUsuario;
   private Date dataBaixa;
   private String nomeCliente;
   private Integer codigoCliente;
   private String nomeContato;
   private Double folhasBoas;
   private String observacao;
   private String mensagem;
   private Date dataVencimentoNotaDebito;
   private boolean baixada;
   private String mensagemNotaLinha1;
   private String mensagemNotaLinha2;
     private List<Servico> listaServicos;
   private List quantidadeAprovadaServico;
   private int indexServico;
     private Servico servico;
     private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport(this);
     /** Creates a new instance of OrdemServicoFormBean */
   public OrdemServicoFormBean() {
       List<Servico> servicos = new ArrayList<Servico>();
       servicos.add(new Servico(0,"Serviços Executados na OS"));
       this.setListaServicos(servicos);
   }
     public void addPropertyChangeListener(PropertyChangeListener x) {
       changeSupport.addPropertyChangeListener(x);
   }
     public void removePropertyChangeListener(PropertyChangeListener x) {
       changeSupport.removePropertyChangeListener(x);
   }
     public Integer getNumeroOrdem() {
       return numeroOrdem;
   }
     public void setNumeroOrdem(Integer numeroOrdem) {
       Integer oldValue = this.numeroOrdem;
       this.numeroOrdem = numeroOrdem;
       changeSupport.firePropertyChange("numeroOrdem", oldValue, numeroOrdem);       }
     public Integer getNumeroOrcamento() {
       return numeroOrcamento;
   }
     public void setNumeroOrcamento(Integer numeroOrcamento) {
       Integer oldValue = this.numeroOrcamento;
       this.numeroOrcamento = numeroOrcamento;
       changeSupport.firePropertyChange("numeroOrcamento", oldValue, numeroOrcamento);       }
     public Integer getNumeroNotaFiscal() {
       return numeroNotaFiscal;
   }
     public void setNumeroNotaFiscal(Integer numeroNotaFiscal) {
       Integer oldValue = this.numeroNotaFiscal;
       this.numeroNotaFiscal = numeroNotaFiscal;
       changeSupport.firePropertyChange("numeroNotaFiscal", oldValue, numeroNotaFiscal);       }
     public Date getDataCadastro() {
       return dataCadastro;
   }
     public void setDataCadastro(Date dataCadastro) {
       changeSupport.firePropertyChange("dataCadastro", this.dataCadastro, dataCadastro);
       this.dataCadastro = dataCadastro;
   }
     public String getNomeUsuario() {
       return nomeUsuario;
   }
     public void setNomeUsuario(String nomeUsuario) {
       String oldValue = this.nomeUsuario;
       this.nomeUsuario = nomeUsuario;
       changeSupport.firePropertyChange("nomeUsuario", oldValue, nomeUsuario);
   }
     public Date getDataBaixa() {
       return dataBaixa;
   }
     public void setDataBaixa(Date dataBaixa) {
       Date oldValue = this.dataBaixa;
       this.dataBaixa = dataBaixa;
       changeSupport.firePropertyChange("dataBaixa", oldValue, dataBaixa);
   }
     public String getNomeCliente() {
       return nomeCliente;
   }
     public void setNomeCliente(String nomeCliente) {
       String oldValue = this.nomeCliente;
       this.nomeCliente = nomeCliente;
       changeSupport.firePropertyChange("nomeCliente", oldValue, nomeCliente);
   }
     public Integer getCodigoCliente() {
       return codigoCliente;
   }
     public void setCodigoCliente(Integer codigoCliente) {
       changeSupport.firePropertyChange("codigoCliente", this.codigoCliente, codigoCliente);
       this.codigoCliente = codigoCliente;
   }
     public String getNomeContato() {
       return nomeContato;
   }
     public void setNomeContato(String nomeContato) {
       String oldValue = this.nomeContato;
       this.nomeContato = nomeContato;
       changeSupport.firePropertyChange("nomeContato", oldValue, nomeContato);
   }
     public Double getFolhasBoas() {
       return folhasBoas;
   }
     public void setFolhasBoas(Double folhasBoas) {
       changeSupport.firePropertyChange("folhasBoas", this.folhasBoas, folhasBoas);
       this.folhasBoas = folhasBoas;
   }
     public String getObservacao() {
       return observacao;
   }
     public void setObservacao(String observacao) {
       changeSupport.firePropertyChange("observacao", this.observacao, observacao);
       this.observacao = observacao;
   }
     public String getMensagem() {
       return mensagem;
   }
     public void setMensagem(String mensagem) {
       changeSupport.firePropertyChange("mensagem", this.mensagem, mensagem);
       this.mensagem = mensagem;
   }
     public List<Servico> getListaServicos() {
       return listaServicos;
   }
     public void setListaServicos(List<Servico> listaServicos) {
       changeSupport.firePropertyChange("listaServicos", this.listaServicos, listaServicos);
       this.listaServicos = listaServicos;
   }
     public List getQuantidadeAprovadaServico() {
       return quantidadeAprovadaServico;
   }
     public void setQuantidadeAprovadaServico(List quantidadeAprovadaServico) {
       changeSupport.firePropertyChange("quantidadeAprovadaServico", this.quantidadeAprovadaServico, quantidadeAprovadaServico);
       this.quantidadeAprovadaServico = quantidadeAprovadaServico;
   }
     public Date getDataVencimentoNotaDebito() {
       return dataVencimentoNotaDebito;
   }
     public void setDataVencimentoNotaDebito(Date dataVencimentoNotaDebito) {
       changeSupport.firePropertyChange("dataVencimentoNotaDebito", this.dataVencimentoNotaDebito, dataVencimentoNotaDebito);
       this.dataVencimentoNotaDebito = dataVencimentoNotaDebito;
   }
     public boolean isBaixada() {
       return baixada;
   }
     public boolean getBaixada() {
       return baixada;
   }
     public void setBaixada(boolean baixada) {
       changeSupport.firePropertyChange("baixada", this.baixada, baixada);
       this.baixada = baixada;
   }
     public String getMensagemNotaLinha1() {
       return mensagemNotaLinha1;
   }
     public void setMensagemNotaLinha1(String mensagemNotaLinha1) {
       changeSupport.firePropertyChange("mensagemNotaLinha1", this.mensagemNotaLinha1, mensagemNotaLinha1);
       this.mensagemNotaLinha1 = mensagemNotaLinha1;
   }
     public String getMensagemNotaLinha2() {
       return mensagemNotaLinha2;
   }
     public void setMensagemNotaLinha2(String mensagemNotaLinha2) {
       changeSupport.firePropertyChange("mensagemNotaLinha2", this.mensagemNotaLinha2, mensagemNotaLinha2);
       this.mensagemNotaLinha2 = mensagemNotaLinha2;
   }
     public List carregarServicos() {
       return getListaServicos();
   }
     public int getIndexServico() {
       return indexServico;
   }
     public void setIndexServico(int indexServico) {
       this.indexServico = indexServico;
   }
     public Servico getServico() {
       return servico;
   }
     public void setServico(Servico servico) {
       changeSupport.firePropertyChange("servico", this.servico, servico);
       this.servico = servico;
   }
}

//---------- Eu quero popular o ComboBox com a propriedade listaServicos que contem uma List do tipo Servico
/*
* Servico.java
*/

package com.sikgraf.listas;

import com.jgoodies.binding.beans.ExtendedPropertyChangeSupport;
import java.beans.PropertyChangeListener;

public class Servico {
   private Integer codigo;
   private String nome;
   private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport(this);
     /**
    * Creates a new instance of Servico
    */
   public Servico() {}
     public Servico(int codigo, String nome) {
       this.setCodigo(codigo);
       this.setNome(nome);
   }
     public Integer getCodigo() {
       return codigo;
   }
     public void setCodigo(Integer codigo) {
       changeSupport.firePropertyChange("codigo", this.codigo, codigo);
       this.codigo = codigo;
   }
     public void addPropertyChangeListener(PropertyChangeListener x) {
       changeSupport.addPropertyChangeListener(x);
   }
     public void removePropertyChangeListener(PropertyChangeListener x) {
       changeSupport.removePropertyChangeListener(x);
   }
   public String getNome() {
       return nome;
   }
     public void setNome(String nome) {
       changeSupport.firePropertyChange("nome", this.nome, nome);
       this.nome = nome;
   }
     // Esse metodo decide qual proprieda sera mostrada no ComboBox
   public String toString() {
       return getNome();
   }
}

// ------------- No View tenho
ordemServicoFormBean = new OrdemServicoFormBean();


BeanAdapter adapter = new BeanAdapter(ordemServicoFormBean, true);

// set the presentation model up to the first bean.
//PresentationModel beanOSPresentationModel = new PresentationModel(ordemServicoFormBean.getListaServicos().get(0), trigger);
PresentationModel beanOSPresentationModel = new PresentationModel(ordemServicoFormBean.getListaServicos().get(0));
ValueModel beanProperty = new PropertyAdapter(beanOSPresentationModel, "bean", true);       ValueModel servicosModel = new PropertyAdapter(ordemServicoFormBean, "listaServicos", true);       ComboBoxAdapter comboServicosModel = new ComboBoxAdapter(ordemServicoFormBean.getListaServicos(), servicosModel);
comboServicosOrcamentoOrdem.setModel( comboServicosModel );

Suponha que eu queira que minha listaServicos tenha o seguinte conteudo (lembrando que quero carregar dinamicamente atraves de um DAO esses dados na List)
List<Servico> theList = new ArrayList<Servico>();
theList.add( new Servico(1, "Service #1") );
theList.add( new Servico(2, "Service #2") );
theList.add( new Servico(3, "Service #3") );

O ComboBox mostra apenas uma linha e nesse formato:
[Service #1, Service #2, Service #3]

O que estou fazendo errado?
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
(This post was updated on )
Olá Francisco,

O código que você postou é um pouco extenso para o compilador da minha cabeça ... hehe.

Vamos por partes:
Se você quer mostrar uma lista de objetos em um JComboBox, você deve usar duas coisas: um SelectionInList (que é um wrapper de uma lista e o item selecionado) e um ValueModel (que aponta para o item selecionado na JComboBox).
Veja o meu exemplo neste artigo:
http://www.componenthouse.com/article-14

Quando você terminar, você verá que a combobox mostra o valor retornado pelo toString() do bean.
Assim, uma forma de mostrar o nome do serviço na lista é sobrecarregar esse método e retornar o nome (o que é feio perante as regras da API Swing) ou partir para a solução recomendada, que é implementar um Renderer no JComboBox que lê o nome do serviço e o desenha na tela.

Alguma outra pergunta?

Abraços,
Hugo.
Franzisk
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Bom, vou perguntar mais devagar e por partes entao porque ainda nao entendi direito.

Como eu faria para preencher um ComboBox com uma propriedade do Bean que retorna um JList do tipo Servico (codigo, nome)? (não entendi como devo criar o ValueModel e o SelectionInList)

Porém quero mostrar no combo apenas o nome, o método toString de Servico já está retornando o nome.

Quando houver uma ação no combo quero fazer *alguma coisa* com o código (propriedade de Servico).

Se puder dar um *exemplinho* eu agradeço.
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
OK, vamos por partes.
Primeiro, você declara um ValueModel que guardará a seleção do combobox:

    ValueModel servicoSelecionadoHolder = new ValueHolder();

Depois, precisamos da lista com serviços disponíveis.
Eu vou criar uma lista simples aqui, mas você pode preenchê-la com o seu DAO:

    List servicos = new ArrayList();
    servicos.add(new Servico(1, "Servico 1"));
    servicos.add(new Servico(2, "Servico 2"));
    servicos.add(new Servico(3, "Servico 3"));


Então, crie um objeto SelectionInList utilizando as duas variaveis acima:

    SelectionInList servicoSelectionInList = new SelectionInList(servicos, servicoSelecionadoHolder);

Pronto. Agora, para criar a JComboBox, você faz:

    JComboBox comboBox = new JComboBox(new ComboBoxAdapter(servicoSelectionInList));

Durante a execução, você pode pegar o item selecionado na comboBox assim:

    Servico selecionado = (Servico) servicoSelecionadoHolder.getValue();

Ficou mais fácil agora?
Franzisk
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Fantástico seu exemplo, bem explicativo sim.

Do jeito que você enviou (criando a lista servicos na view e adicionando ao SelectionInList) funcionou perfeitamente.

Do jeito que eu estou tentando fazer não preencheu o combobox (lembrando que o JComboBox já existe, eu apenas informo o ComboBoxModel para ele).

Do jeito que você mandou:
BeanOS = new OrdemServicoFormBean();
BeanAdapter adapter = new BeanAdapter(BeanOS, true);

List<Servico> servicos = new ArrayList<Servico>();
servicos.add(new Servico(1, "Servico 1"));
servicos.add(new Servico(2, "Servico 2"));
servicos.add(new Servico(3, "Servico 3"));

ValueModel servicoSelecionadoHolder = new ValueHolder();
SelectionInList servicoSelectionInList = new SelectionInList(servicos, servicoSelecionadoHolder);        
comboServicosOrcamentoOrdem.setModel( new ComboBoxAdapter(servicoSelectionInList) );



Do jeito que eu estou tentando fazer (ta errada minha abordagem?):
// O 'true' eh para osbervar as mudancas no bean
BeanOS = new OrdemServicoFormBean();
BeanAdapter adapter = new BeanAdapter(BeanOS, true);

ValueModel servicoSelecionadoHolder = new ValueHolder();
SelectionInList servicoSelectionInList = new SelectionInList(BeanOS.getListaServicos(), servicoSelecionadoHolder);                
comboServicosOrcamentoOrdem.setModel( new ComboBoxAdapter(servicoSelectionInList) );

Ou seja, quando eu informo o metodo do bena que retorna a lista e em certo ponto eu carrego o bean o combobox nao preenche.

----- Metodos da Lista no Bean --------
public List<Servico> getListaServicos() {
        return listaServicos;
}
   
public void setListaServicos(List<Servico> listaServicos) {
        changeSupport.firePropertyChange("listaServicos", this.listaServicos, listaServicos);
        this.listaServicos = listaServicos;
}


----- Carregando os valores nas propriedades do bean
BeanOS = new OrdemServicoDAO(c).getOrdemServico(codigoOrdemServicoOrcamento, BeanOS);

** aqui seu eu olhar o BeanOS.getListaServicos() eu consigo ver que o conteudo foi carregado corretamente na lista.

Pode ser que minha abordagem esteja totalmente errada quanto a carregar dinamicamente, saberia me dizer?
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
O problema é que você muda o objeto listaServicos no método setListaServicos(...).
O SelectionInList continua usando o objeto antigo depois que você atualizou a lista.
Assim, para corrigir o problema, é preciso fazer duas coisas:

1 - Ao invés de usar a interface List, utilize a interface ListModel. Essa última possui os mesmos métodos da interface List, só que o ListModel é observável. Assim, quando você mudar o conteúdo da lista, a combobox vai refletir a mudança.
Exemplo:

    ListModel listaServicos = new ArrayListModel();
    listaServicos.add(new Servico(1, "AAA"));
    listaServicos.add(new Servico(2, "BBB"));
    listaServicos.add(new Servico(3, "CCC"));


2 - Não mude o objeto no método setListaServicos(...).
Apenas troque o conteúdo da lista:

    this.listaServicos.clear();
    this.listaServicos.addAll(listaServicos);
    changeSupport.firePropertyChange("listaServicos", this.listaServicos, this.listaServicos);


Não deixe de avisar se funcionou.
Franzisk
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Esse ListModel é do tipo javax.swing.ListModel ?
Se for ele não possui o método .add(....)
Franzisk
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Coloquei isso:
ValueModel servicoSelecionadoHolder = new ValueHolder();
SelectionInList servicoSelectionInList = new SelectionInList(BeanOS.getListaServicos(), servicoSelecionadoHolder);                
comboServicosOrcamentoOrdem.setModel( new ComboBoxAdapter(servicoSelectionInList) );


Depois de carregar os dados no bean e funcionou.

Para JTable você tem alguma *receita* por aí?

Valeu por ajuda prestada ate agora.
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
É esse ListModel sim, mas eu esqueci de declarar a variavel como ArrayListModel mesmo:

    ArrayListModel listaServicos = new ArrayListModel();
    listaServicos.add(new Servico(1, "AAA"));
    listaServicos.add(new Servico(2, "BBB"));
    listaServicos.add(new Servico(3, "CCC"));

Assim funciona
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Que bom que funcionou.
Crie um novo tópico no forum para JTable que a gente discute
Franzisk
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Perfeito, agora o combobox ta OK, muito obrigado.
Teria alguma dica sobre JTable?

Outra perguntinha (ja tou te "enchendo"), como faço para para habilitar/desabilitar um componente baseado no estado de uma propriedade do bean?
 

PS.
Estou usando o Bindign do JGoodies porque achei mais *fácil*, comparado ao Genesis que tive um problema que o ClassLoader não encontrava o arquivo messages.properties de jeito nenhum.
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Por favor, crie um topico novo para cada pergunta.
Assim a gente mantém o forum organizado.
jcomp
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Olá, tb estou precisando ligar um ComboBox (já pronto) a um bean. O binding já está pronto, mas olhando seu exemplo aqui, para que serve o:

BeanAdapter
e o  changeSupport.firePropertyChange("listaServicos", this.listaServicos, listaServicos);

grato!
Franzisk
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Eu segui esse artigo:
http://www.javalobby.org/java/forums/t17672

Mas tenho certeza que o Hugo pode te explicar direitinho o que esses dois significam.
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
O artigo mencionado aqui é uma boa referência, mas vou falar um pouco sobre isso:

BeanAdapter
O BeanAdapter é um wrapper para um bean.
Ele fornece ValueModels para cada propriedade do bean e facilita a montagem de uma interface.
Podemos mudar o valor guardado pelo adapter que todos os componentes da tela refletem a mudança.
Repare que, para isso funcionar, é preciso lançar eventos dentro dos métodos set (setters) do bean.

ChangeSupport
Eu particularmente não uso o ChangeSupport do jeito que foi definido no exemplo.
Eu sempre faço os meus bens herdarem de com.jgoodies.binding.beans.Model, pois assim eu posso chamar o método firePropertyChange(...) facilmente.
Note que precisamos lançar esses eventos para que o binding funcione corretamente, pois quase tudo funciona a base de listeners, principalmente ValueModels, ListModels e BeanAdapters.

Veja meu exemplo completo aqui.

Abraços,
Hugo Teixeira
www.componenthouse.com
jcomp
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
Olá Hugo, mas toda vez que add objetos na ListModel, eu devo chamar o método setListModel(); (no caso setListaServicos)

Pq não percebi onde usar este set!


Grato!
Hugo Teixeira
Re: Problema Binding Bean-Class em JComboBox
Reply Threaded More
Print post
Permalink
jcomp wrote:
Olá Hugo, mas toda vez que add objetos na ListModel, eu devo chamar o método setListModel(); (no caso setListaServicos)
Na verdade, não.
Você só deve chamar o setListaServicos() se o objeto ListModel não for mais o mesmo.
Se o objeto ListModel é sempre o mesmo, você pode adicionar/remover objetos que tudo funciona perfeitamente.