Problemas com JTable e TableCellRenderer?

Salve galera

Seguinte, estou tentado ainda sem sucesso implementar um TableCellRenderer para pintar as linhas conforme um valor. No caso para Clientes, caso o cliente esteja com o status “A” pinta de verde, caso not pinta de vermelho.

Estou tentando assim.

//POJO
public class Clientes{
      private Long id;
      private String nome;
      private String status;
      //get e set
}

//AbstractTableModel
public class ClientesTableModel extends AbstractTableModels{
        //aqui meus metodos de AbstractTableModel
}


// Renderer
public class ClientesTableCellRenderer extends JLabel implements TableCellRenderer{
       public Component getClientesTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

              Clientes cli = (Clientes)value;              
              if(cli.getStatus().equals("A"){
                   setBackground(Color.GREEN);
              }else{
                   setBackground(Color.RED);
              }
              return this;
       }
}


//JDialog
public class Clientes extends JDialog{
        JTable tabela = new JTable();
        List<Clientes> lista = new ClientesDAO().getAllClientes();
        ClientesTableModel model = new ClientesTableModel(lista);
        tabela.setModel(model);
        tabela.setDefaultRenderer(Object.class, new ClientesTableCellRenderer());
}

Como resolver isso ?

obrigado

alguns desses topicos deve ter a resposta

http://www.guj.com.br/java/124963-jtable-dinamica/3
http://www.guj.com.br/java/236764-como-pintar-o-bakground-de-uma-row-de-uma-jtable-resolvido
http://www.guj.com.br/java/55403-jlabel-no-jtable
http://www.guj.com.br/java/55314-jtable--void-paintimmediately#292964

[quote=eduJava]alguns desses topicos deve ter a resposta

http://www.guj.com.br/java/124963-jtable-dinamica/3
http://www.guj.com.br/java/236764-como-pintar-o-bakground-de-uma-row-de-uma-jtable-resolvido
http://www.guj.com.br/java/55403-jlabel-no-jtable
http://www.guj.com.br/java/55314-jtable--void-paintimmediately#292964[/quote]

Eu ja havia visto esses links, inclusive eu tenho um modelo aqui em que uso DefaultTableCellRenderer. Mas não sei pq cargas d’agua não estou conseguindo fazer funcionar.
O problema agora é que quando consigo pintar as linhas, os valores não são exibidos.

aqui como estou tentando, agora.

//POJO
public class Clientes{  
      private Long id;  
      private String nome;  
      private String status;  
      //get e set  
}  


//ClientesDAO
public List<Clientes> getAllClientes(){
      List<Clientes> lista = new ArrayList<Clientes>();
      PreparedStatement stm = con.prepareStatement("SELECT * FROM clientes");
      ResultSet rs = stm.executeQuery();
      while(rs.next()){
            Clientes c = new Clientes();
            c.setId(rs.getLong("id"));
            c.setNome(rs.getString("nome"));
            c.setStatus(rs.getString("status"))
            lista.add(c);
      }
}


//AbstractTableModel  
public class ClientesTableModel extends AbstractTableModels{  
        //aqui meus metodos de AbstractTableModel  
}  


// TableCellRenderer  
public class ClientesTableCellRenderer extends JLabel implements TableCellRenderer{  
       public Component getClientesTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {  
  
              Clientes cli = (Clientes)value;                
              if(cli.getStatus().equals("A"){  
                   setBackground(Color.GREEN);  
              }else{  
                   setBackground(Color.RED);  
              }  
              return this;  
       }  
}  


//JDialog  
public class Clientes extends JDialog{  
        JTable tabela = new JTable();  
        List<Clientes> lista = new ClientesDAO().getAllClientes();  
        ClientesTableModel model = new ClientesTableModel(lista);  
        tabela.setModel(model);  
        tabela.setDefaultRenderer(Object.class, new ClientesTableCellRenderer());  
}  

Alguma sugestão ?

obrigado

cara me parece que vc está colocando um label dentro com cor, mais nao tem o value
tenta algo assim depois de setar a cor

[quote=eduJava]cara me parece que vc está colocando um label dentro com cor, mais nao tem o value
tenta algo assim depois de setar a cor

Não resolveu…

O que preciso é testar se o Cliente estiver com status “A”, pinta de verde, senão pinta de vermelho.

t+ e obrigado

entao vc disse

O problema agora é que quando consigo pintar as linhas, os valores não são exibidos.

vc esta passando um jlabel no seu renderer e vc só esta setando o background

Clientes cli = (Clientes)value; if(cli.getStatus().equals("A"){ setBackground(Color.GREEN); }else{ setBackground(Color.RED); } setText("aparece isso?"); return this;

cara fiz um teste aqui, meu value não é objeto igual o seu, mais…

[code]
class TabelaRender implements TableCellRenderer{

	@Override
	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
		JPanel panel = new JPanel(new GridLayout(1,0));
		if(table.getValueAt(row, 2).equals("A")){
			panel.setBackground(Color.white);
		}else{
			panel.setBackground(Color.black);
		}
		JLabel jlabel = new JLabel(value.toString());
		jlabel.setForeground(Color.blue);
		panel.add(jlabel);
		return panel;
	}
}[/code]

[quote=eduJava]cara fiz um teste aqui, meu value não é objeto igual o seu, mais…

[code]
class TabelaRender implements TableCellRenderer{

	@Override
	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
		JPanel panel = new JPanel(new GridLayout(1,0));
		if(table.getValueAt(row, 2).equals("A")){
			panel.setBackground(Color.white);
		}else{
			panel.setBackground(Color.black);
		}
		JLabel jlabel = new JLabel(value.toString());
		jlabel.setForeground(Color.blue);
		panel.add(jlabel);
		return panel;
	}
}[/code][/quote]

O erro q esta acontecendo agora é no meu Cast…

Aqui o erro:

java.lang.ClassCastException: java.lang.String cannot be cast to ibg.yanoffice.beans.Clientes

//acontece nesta linha do TableCellRenderer
Clientes cli = (Clientes)value;       

hehe
é String e não Cliente por isso não converte

cara copia minha classe TabelaRender e substitui a sua
senão funcionar (teste), vc vai debugando e vendo o erro

[quote=eduJava]hehe
é String e não Cliente por isso não converte

cara copia minha classe TabelaRender e substitui a sua
senão funcionar (teste), vc vai debugando e vendo o erro[/quote]

Sim, é o cast, mas como estou passando o Objeto Cliente, o value deveria recebe-lo não ? Para q assim eu consiga trabalhar com seus métodos.

obrigado.

[quote=fernandopaiva][

Sim, é o cast, mas como estou passando o Objeto Cliente, o value deveria recebe-lo não ? Para q assim eu consiga trabalhar com seus métodos.

[/quote]

Depende. Como é que você definiu seu TableModel?

[quote=entanglement][quote=fernandopaiva][

Sim, é o cast, mas como estou passando o Objeto Cliente, o value deveria recebe-lo não ? Para q assim eu consiga trabalhar com seus métodos.

[/quote]

Depende. Como é que você definiu seu TableModel? [/quote]

Aqui esta como foi definido meu AbstractTableModel

public class ClientesTableModel extends AbstractTableModel{
    private List<Clientes> lista;
    private String[] colunas = {"Id", "Nome", "Status"};
    
    
    public ClientesTableModel(){
        lista = new ArrayList<Clientes>();
    }
    
    
    public ClientesTableModel(List<Clientes> lista){
        this();
        this.lista.addAll(lista);
    }
    

    @Override
    public int getRowCount() {
        return lista.size();
    }

    
    @Override
    public int getColumnCount() {
        return colunas.length;
    }
    
    
    public String getColumnName(int column) {
	if(colunas[column] == "Id"){
            return "Id";
        }else if(colunas[column] == "Nome"){
            return "Nome";
        }else if(colunas[column] == "Status"){
            return "Status";
        }
        return "";
    }
    
    
    public Class getColumnClass(int columnIndex) {
	if(colunas[columnIndex] == "Id"){
            return long.class;
        }else if(colunas[columnIndex] == "Nome"){
            return String.class;
        }else if(colunas[columnIndex] == "Status"){
            return String.class;
        }
        return Object.class;
    }
    

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Clientes c = lista.get(rowIndex);
        switch(columnIndex){
            case 0: return new FormataCodigos().retornaCodigoFormatado(r.getId());
            case 1: return c.getNome();
            case 2: return c.getStatus();
            default: return new String();
        }
    }
    
    
    public Clientes getClientes(int row){
        return lista.get(row);
    }
    
    
    public List<Clientes> getListaClientes(){
        return lista;
    }
    
    public void alterList(List<Clientes> lista){
        this.lista = lista;
        fireTableDataChanged();
    }
}

vlw, obrigado !

Ou seja, seu TableCellRenderer recebe sempre uma String, porque ela é usada para as colunas 0, 1 e 2. Pense mais ou menos assim: quando o Java precisa desenhar uma célula, ele chama getValueAt, e ele retorna um objeto. Então ele chama o método getTableCellRendererComponent e passa esse objeto para ser mostrado. Só que pelo que você escreveu aí, o tipo do objeto é sempre String.

Se precisar obter o objeto do tipo Clientes, você precisa pegar o parâmetro “row” que é passado para getTableCellRendererComponent, para achar na lista de Clientes qual é o cliente que corresponde a essa linha. OK?

[quote=entanglement][quote]

    @Override  
    public Object getValueAt(int rowIndex, int columnIndex) {  
        Clientes c = lista.get(rowIndex);  
        switch(columnIndex){  
            case 0: return new FormataCodigos().retornaCodigoFormatado(r.getId());  
            case 1: return c.getNome();  
            case 2: return c.getStatus();  
            default: return new String();  
        }  
    }  

[/quote]

Ou seja, seu TableCellRenderer recebe sempre uma String, porque ela é usada para as colunas 0, 1 e 2. Pense mais ou menos assim: quando o Java precisa desenhar uma célula, ele chama getValueAt, e ele retorna um objeto. Então ele chama o método getTableCellRendererComponent e passa esse objeto para ser mostrado. Só que pelo que você escreveu aí, o tipo do objeto é sempre String.

Se precisar obter o objeto do tipo Clientes, você precisa pegar o parâmetro “row” que é passado para getTableCellRendererComponent, para achar na lista de Clientes qual é o cliente que corresponde a essa linha. OK?
[/quote]

Opa, estou passando o List para o TableCellRenderer, veja.


// TableCellRenderer
public class ClientesTableCellRenderer extends JLabel implements TableCellRenderer{
    private List<Clientes> lista;
    
    public ClientesTableCellRenderer(List<Clientes> lista){
        this.lista = lista;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        Clientes c = lista.get(row);
        if(c.getStatus().equals("S")){
            setBackground(Color.YELLOW);
        }else if(c.getStatus().equals("N")){
            setBackground(Color.RED);
        }
        return this;
    }
}



// JDialog
public class Clientes extends JDialog{
       List<Clientes> lista = new ClientesDAO().getAllClientes();
       clientesTableModel = new ClientesTableModel(lista);        
       tabela.setModel(clientesTableModel);       
       tabela.setDefaultRenderer(Object.class, new ClientesTableCellRenderer(lista)); 
}

Obrigado.

Mesmo assim não funciona pintar as linhas necessárias, affs !!!
JTable no Java é tenso d++…é um dos componentes mais tensos de mexer q eu acho.

Qquer sugestão, posta ae !

obrigado.

Antes tarde do que nunca, afinal de contas mais alguém pode chegar aqui e não obter a resposta.

O JTable vai no Modelo para saber que tipo de renderizador irá utilizar logo em:

    public Class getColumnClass(int columnIndex) {  
    if(colunas[columnIndex] == "Id"){  
            return long.class;  
        }else if(colunas[columnIndex] == "Nome"){  
            return String.class;  
        }else if(colunas[columnIndex] == "Status"){  
            return String.class;  
        }  
        return Object.class;  
    }  

Você especifica o tipo de renderizador vai utilizar para cada coluna, ele simplesmente ignora o tipo de Objeto realmente passado e usa o tipo de coluna, no seu caso você ta passando String.class para as colunas “Id”, “Nome” e “Status”,
logo, faça assim:

    public Class getColumnClass(int columnIndex) {  
    if(colunas[columnIndex] == "Id"){  
            return Clientes.class;  
        }else if(colunas[columnIndex] == "Nome"){  
            return Clientes.class;  
        }else if(colunas[columnIndex] == "Status"){  
            return Clientes.class;  
        }  
        return Object.class;  
    }  

E …

// TableCellRenderer    
public class ClientesTableCellRenderer extends JLabel implements TableCellRenderer{    
       public Component getClientesTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {    
    
              Clientes cli = (Clientes)value;                  
              if(cli.getStatus().equals("A"){    
                   setBackground(Color.GREEN);    
              }else{    
                   setBackground(Color.RED);    
              } 
         if(colunas[columnIndex] == "Id"){  
            setText(cli.getId());  
        }else if(colunas[columnIndex] == "Nome"){  
            setText(cli.getNome());  
        }else if(colunas[columnIndex] == "Status"){  
            setText(cli.getStatus());
        }  

              return this;    
       }    
}    

Particularmente, acho que eu construiria um render padrão com comportamentos da linha, e depois estenderia ele sobrescrevendo o método getClientesTableCellRendererComponent para cada coluna.