Erro na JTable do tipo Boolean

Boa noite pessoal.
Estou com um problema na minha JTable e não consegui resolver. Criei um método para montar a JTable de forma dinâmica, a ideia é usar TableModel e Renderizar tbem já que em alguns casos quero “Zebrar” a minha Table … tudo funcionando de boa, mas tenho uma tela que tem “Status”, esse cara é do tipo Boolean porem no meu JTable ele aparece “True” or “False” … segue código:

1.     package acao;

2.     import java.awt.Color;
3.     import java.awt.Component;
4.     import javax.swing.JTable;
5.     import javax.swing.table.AbstractTableModel;
6.     import javax.swing.table.DefaultTableCellRenderer;
7.     import javax.swing.table.TableCellRenderer;

8.     public class GeraJTable extends javax.swing.JTable {

9.         private String [] titulo;
10.         private int[][] posicao;
11.         private int[] cor;
12.         private Object[][]dados;
13.         
14.      // Construtores
15.         public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int [] cor, Object[][] dados ){
16.             this.titulo  = titulo;
17.             this.posicao = posicao;
18.             this.cor     = cor;
19.             this.dados   = dados;
20.             this.setModel(new MeuTableModel());
21.          // Define a largura da coluna
22.             for(int i=0;i<tamanho.length;i++){
23.                 this.getColumnModel().getColumn(tamanho[i][0]).setMinWidth(tamanho[i][1]);
24.                 this.getColumnModel().getColumn(tamanho[i][0]).setMaxWidth(tamanho[i][2]);
25.             }
26.          // Esconde uma coluna
27.             for(int i=tamanho.length-1;i>=0;i--){
28.                 if (tamanho[i][1]==0 && tamanho[i][2]==0){
29.                     this.getColumnModel().removeColumn( this.getColumnModel().getColumn(tamanho[i][0]));                      
30.                 }
31.             }
32.          // Renderiza JTable
33.             this.setDefaultRenderer(Object.class , new MeuRenderizador());
34.     //        this.setDefaultRenderer(Double.class , new MeuRenderizador());
35.       //      this.setDefaultRenderer(Integer.class, new MeuRenderizador());
36.         //    this.setDefaultRenderer(Boolean.class, new MeuRenderizador());
37.         }
38.         public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao){
39.             this(titulo, tamanho, posicao, new int[]{}, new Object[][]{} );
40.         }
41.         public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int [] cor){
42.             this(titulo, tamanho, posicao, cor, new Object[][]{});
43.         }
44.         public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, Object[][] dados){
45.             this(titulo, tamanho, posicao, new int[]{}, dados);
46.         }
47.      // Classe AbstractTableModel
48.         public class MeuTableModel extends AbstractTableModel{

49.             public MeuTableModel(){
50.             }
51.             @Override
52.             public String getColumnName(int num){return titulo[num];}
53.             @Override
54.             public int getColumnCount() {return titulo.length;}
55.             @Override
56.             public int getRowCount() {return dados.length;}
57.             @Override
58.             public boolean isCellEditable(int linha, int coluna) {return false;}
59.             @Override
60.             public Object getValueAt(int linha, int coluna) {return dados[linha][coluna];}
61.             @Override
62.             public Class getColumnClass(int coluna) {
63.                 try {
64.                     return this.getValueAt(0, coluna).getClass();
65.                 } catch (Exception e) {
66.                     return java.lang.Object.class;
67.                 }
68.             }
69.         }
70.      // Classe Renderizadora
71.         public class MeuRenderizador extends DefaultTableCellRenderer implements TableCellRenderer {
72.             @Override
73.             public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
74.                 super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
75.                 this.setOpaque(true);
76.                 this.setHorizontalAlignment(LEFT);

77.                 for(int[] pos : posicao) {
78.                     if (column == pos[0]) {
79.                         switch (pos[1]) {
80.                             case 0 : this.setHorizontalAlignment(CENTER); break;
81.                             case 1 : this.setHorizontalAlignment(RIGHT); break;
82.                             default: this.setHorizontalAlignment(LEFT); break;
83.                         }
84.                     }
85.                 }
86.                 if (cor.length==6) {
87.                     Color foreground, background;
88.                     if (isSelected) {
89.                         foreground = Color.getHSBColor(cor[0],cor[0],cor[0]);
90.                         background = Color.getHSBColor(cor[1],cor[1],cor[1]);
91.                     } else
92.                     if (row % 2 == 0) {
93.                         foreground = Color.getHSBColor(cor[2],cor[2],cor[2]);
94.                         background = Color.getHSBColor(cor[3],cor[3],cor[3]);
95.                     } else {
96.                         foreground = Color.getHSBColor(cor[4],cor[4],cor[4]);
97.                         background = Color.getHSBColor(cor[5],cor[5],cor[5]);
98.                     }
99.                   //background = Color.getHSBColor(row,row,row);
100.                     this.setForeground(foreground);
101.                     this.setBackground(background);
102.                 }
103.                 return this;
104.             }
105.             
106.         }
107.     }

Reparem que eu comentei as linhas 34, 35 e 36. Quando faço isso ele não respeita as cores, mas até ai tudo bem já era de se esperar … mas depois que eu tiro os comentários olha o que acontece.

As colunas “Matricula” e “Salario” respeitam as regras que impus de Centralização e Cor mas o “Status” muda. Alguma ideia do que pode estar acontecendo ?

Segue também o código main do projeto:

package acao;

import java.awt.Container;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
/**
 * Como Criar um JTable - Método pronto
 * @author vonquelbe.caldeira
 */
public class Inicio {

    public static Container container;
    public static JFrame tela;
    public static JScrollPane scrollpane;
    public static GeraJTable table;
    
    public static void main(String[] args) {
        
        tela = new javax.swing.JFrame();
     // Tamanho da tela e container
        tela.setSize(650,385);
        tela.setTitle("Criando JTable");
        tela.setResizable(false);
        tela.setLocationRelativeTo(null);
        tela.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
     // Container da tela
        container = tela.getContentPane();
        container.setLayout(null);       
     // Cria JTable
        Object[][] dados = {
                {"1",1542,"Vanderson Lima"      , new Boolean(false), new SimpleDateFormat("dd/MM/yyyy").format(new Date(System.currentTimeMillis())), new Double("3450.00") },
                {"2",1306,"Oswaldo Sergio Silva", new Boolean(true) , new SimpleDateFormat("dd/MM/yyyy").format(new Date("1978/07/26")), new Double("7230.00") },
                {"3",2112,"Patricia Pereira"    , new Boolean(false), new SimpleDateFormat("dd/MM/yyyy").format(new Date(1988, 5, 4))  , new Double("1500.00") },
                {"4",3,   "Alessandra Sandrinha", new Boolean(true) , new SimpleDateFormat("dd/MM/yyyy").format(new Date(1955/01/03))  , new Double("4483.00") },
                {"5",105, "Brasil Novaes"       , new Boolean(false), new SimpleDateFormat("dd/MM/yyyy").format(new Date("1994/12/26")), new Double("750.00") },
                {"6",202, "Pereira Machado"     , new Boolean(false), new SimpleDateFormat("dd/MM/yyyy").format(new Date("1963/08/22")), new Double("3350.00") },
                {"7",303, "Fabricio Souza"      , new Boolean(false), new SimpleDateFormat("dd/MM/yyyy").format(new Date("1971/07/10")), new Double("3355.11") },
                {"8",404, "Barbara Nunes"       , new Boolean(false), new SimpleDateFormat("dd/MM/yyyy").format(new Date("1945/04/13")), new Double("2789.13") },
        };        
        table = new GeraJTable(new String[]{"Seq","Matricula","Nome","Status","Data Nascimento","Salario"},
                               new int [][]{{0,90,90},{1,90,90},{3,60,60},{4,110,110}},
                               new int [][]{{0,0},{1,0},{3,0},{4,0},{5,1}},
                               new int []{23,243,0,91,0,23},
                               dados
        );
        scrollpane = new javax.swing.JScrollPane(table);
        scrollpane.setBounds(3,3,tela.getWidth()-11,200);
        container.add(scrollpane);
     // Abre tela
        tela.setVisible(true);
    }    
}

Seu TableCellRenderer está implementado de forma estranha.

O método getTableCellRendererComponent deve retornar o componente a ser utilizado para renderizar a célula informada, entretanto você não retorna um componente, você retorna o próprio this.
Sugiro que crie duas variáveis de instância no seu TableCellRenderer, um JLabel e um JCheckBox, quando a coluna for dos campos boolean, atualize e retorne a instância do JCheckBox, se for outra coluna, atualize e retorne a instância do JLabel.

Ficaria algo mais ou menos assim:

public class MeuRenderizador extends DefaultTableCellRenderer {

    private JLabel    label    = new JLabel();
    private JCheckBox checkbox = new JCheckBox();

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        Component component;
		if (Boolean.class.equals(table.getModel().getColumnClass(column))) {
			component = checkbox;
			checkbox.setSelected((Boolean)value);
		} else {
			component = label;
			label.setText(String.valueOf(value));
	        label.setHorizontalAlignment(LEFT);
            for(int[] pos : posicao) {
                if (column == pos[0]) {
                    switch (pos[1]) {
                        case 0 :
						    label.setHorizontalAlignment(CENTER);
						    break;
                        case 1 :
						    label.setHorizontalAlignment(RIGHT);
							break;
                        default:
						    label.setHorizontalAlignment(LEFT);
							break;
                    }
                }
            }
		}
        component.setOpaque(true);

        if (cor.length==6) {
            Color foreground;
			Color background;
            if (isSelected) {
                foreground = Color.getHSBColor(cor[0],cor[0],cor[0]);
                background = Color.getHSBColor(cor[1],cor[1],cor[1]);
            } else if (row % 2 == 0) {
                foreground = Color.getHSBColor(cor[2],cor[2],cor[2]);
                background = Color.getHSBColor(cor[3],cor[3],cor[3]);
            } else {
                foreground = Color.getHSBColor(cor[4],cor[4],cor[4]);
                background = Color.getHSBColor(cor[5],cor[5],cor[5]);
            }
            component.setForeground(foreground);
            component.setBackground(background);
         }
         return component;
    }
}

Entendi o que vc quis dizer … Quando retorno this na verdade retorno com as alterações que fiz no próprio objeto … mas não achei nenhum método que mudasse o Tipo para CheckBox. Acho que a solução é mesmo o que vc disse … vou tentar implementar.

SIm eu sei, mas isso só funcionou pois o DefaultTableCellRenderer estende da classe JLabel, mas a ideia é que o método retorne qualquer Component que é pra ser utilizado para renderizar a célula, por isso que você recebe como parâmetro todas as informações necessárias:

  • a própria JTable table;
  • o conteúdo da célula;
  • flag identificando se a célula está selecionada;
  • flag indicando se a célula possui foco;
  • número da linha;
  • número da coluna.

Então se o valor for um booleano, você retorna uma instância de JCheckBox, mas antes de retornar, você seta o a seleção do JCheckBox de acordo com o valor recebido.

Nem precisaria extender DefaultTableCellRenderer, pois ele só renderiza JLabel, é só implementar seu próprio TableCellRenderer. :slight_smile:

Melhor explicação não há cara … muito obrigado … Veja como ficou:

 // Classe Renderizadora
    public class MeuRenderizador extends DefaultTableCellRenderer implements TableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

            Component renderer;
         // Verifica se há Coluna tipo Boolean e muda alinhamento
            if (Boolean.class.equals(table.getModel().getColumnClass(column))) {
                renderer = new JCheckBox();
              ((JCheckBox) renderer).setSelected((Boolean)value);
              ((JCheckBox) renderer).setHorizontalAlignment(getPosicao(0));
            } else{
                renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                ((JLabel) renderer).setOpaque(true);
                ((JLabel) renderer).setHorizontalAlignment(getPosicao(2));
                for (int[] pos : posicao) {
                    if (column == pos[0]) {
                        ((JLabel) renderer).setHorizontalAlignment(getPosicao(pos[1]));
                    }
                }
            }
         // Verifica Colunas de Valor
            Object val = table.getValueAt(row, column);
            if (val instanceof Double) {  
                Double valor = (Double) val;  
                NumberFormat nf = NumberFormat.getCurrencyInstance();  
                this.setText(valor != null ? nf.format(valor) : "");  
            } else
            if (val instanceof BigDecimal) {  
                BigDecimal valor = (BigDecimal) val;  
                NumberFormat nf = NumberFormat.getCurrencyInstance();  
                this.setText(valor != null ? nf.format(valor) : "");  
            }
          // Altera a Cor
            if (cor.length==6) {
                Color foreground, background;
                if (isSelected) {
                    foreground = Color.getHSBColor(cor[0],cor[0],cor[0]);
                    background = Color.getHSBColor(cor[1],cor[1],cor[1]);
                } else
                if (row % 2 == 0) {
                    foreground = Color.getHSBColor(cor[2],cor[2],cor[2]);
                    background = Color.getHSBColor(cor[3],cor[3],cor[3]);
                } else {
                    foreground = Color.getHSBColor(cor[4],cor[4],cor[4]);
                    background = Color.getHSBColor(cor[5],cor[5],cor[5]);
                }
                renderer.setForeground(foreground);
                renderer.setBackground(background);
            }
            return renderer;
        }        
    }
    public int getPosicao(int posicao) {
        switch (posicao) {
            case 0: return SwingConstants.CENTER;
            case 1: return SwingConstants.RIGHT;
            default:return SwingConstants.LEFT;
        }
    }    

Agora ta bonito … Ainda não são as cores que quero, só estou testando, por isso que coloquei as cores como parâmetro … a ora que encontrar um tom de cor legal eu padronizo … mas por ora é isso … mas uma vez muito Obrigado ;o) …

Depois com mais calma vou tentar retirar esse cara …

Sensacional!

Dica: Você não precisa ficar instanciando um novo JCheckBox toda vez que o método é invocado.
Por isso no meu exemplo criei duas variáveis de instância, além de economizar memória, é mais rápido.
O mesmo objeto é reaproveitado para as N células que forem renderizadas.
O Swing usa essa instância somente para desenhar os pixels, por isso que a gente tem que setar o conteúdo dele antes de retornar.
É toda a magia do MVC!

Dei uma melhorada no código e estou postando porque vai que serve pra alguém.
Tive que mexer porque quando não passo as cores no parâmetro dava ruim, principalmente no tipo Boolean. Mas é assim mesmo, agente altera e testa e altera de novo … Ainda quero mexer pra passar ArrayList ao invés de Array já que a maioria dos meus métodos retornam um ArrayList, mas isso é pra depois, por enquanto está assim e funcionando galera … Bons Estudos.

package acao;

import java.awt.Color;
import java.awt.Component;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;

public class GeraJTable extends JTable {

    private String [] titulo;
    private int [] [] tamanho;
    private int [] [] posicao;
    private int [] [] tipo;
    private int [] cor;
    private Object [][]dados;
    private DecimalFormat df = new DecimalFormat("#,##0.00");
    private NumberFormat  nf = NumberFormat.getCurrencyInstance();
    
 // Construtores
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int[][] tipo, int [] cor, Object[][] dados ){
        this.titulo  = titulo;
        this.tamanho = tamanho;
        this.posicao = posicao;
        this.tipo    = tipo;
        this.cor     = cor;
        this.dados   = dados;
        this.setModel(new MeuTableModel());

     // Define a largura da coluna
        for(int i=0;i<tamanho.length;i++){
            this.getColumnModel().getColumn(tamanho[i][0]).setMinWidth(tamanho[i][1]);
            this.getColumnModel().getColumn(tamanho[i][0]).setMaxWidth(tamanho[i][2]);
        }
     // Esconde (remove) uma coluna
        for(int i=tamanho.length-1;i>=0;i--){
            if (tamanho[i][1]==0 && tamanho[i][2]==0){
                this.getColumnModel().removeColumn( this.getColumnModel().getColumn(tamanho[i][0]));                      
            }
        }
     // Renderiza JTable
        this.setDefaultRenderer(Object.class, new MeuRenderizador());
        this.setDefaultRenderer(Double.class , new MeuRenderizador());
        this.setDefaultRenderer(Integer.class , new MeuRenderizador());
        this.setDefaultRenderer(Boolean.class  , new MeuRenderizador());
        this.setDefaultRenderer(BigDecimal.class, new MeuRenderizador());
    }
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao){
        this(titulo, tamanho, posicao, new int[][]{}, new int[]{}, new Object[][]{} );}
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int[][] tipo){
        this(titulo, tamanho, posicao, tipo, new int[]{}, new Object[][]{} );}
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int[][] tipo, Object[][] dados){
        this(titulo, tamanho, posicao, tipo, new int[]{}, dados );}
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int [] cor){
        this(titulo, tamanho, posicao, new int[][]{}, cor, new Object[][]{});}
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, int [] cor, Object[][] dados) {
        this(titulo, tamanho, posicao, new int [][]{}, cor, dados);}
    public GeraJTable(String [] titulo, int [][] tamanho, int[][] posicao, Object[][] dados){
        this(titulo, tamanho, posicao, new int[][]{}, new int[]{}, dados);}
    
 // Classe AbstractTableModel
    public class MeuTableModel extends AbstractTableModel{
        public MeuTableModel(){
        }
        @Override
        public String getColumnName(int num){return titulo[num];}
        @Override
        public int getColumnCount() {return titulo.length;}
        @Override
        public int getRowCount() {return dados.length;}
        @Override
        public boolean isCellEditable(int linha, int coluna) {return false;}
        @Override
        public Object getValueAt(int linha, int coluna) {return dados[linha][coluna];}
        @Override
        public Class getColumnClass(int coluna) {
            try {
                return this.getValueAt(0, coluna).getClass();
            } catch (Exception e) {
                return java.lang.Object.class;
            }
        }
    }
 // Classe Renderizadora
    public class MeuRenderizador extends DefaultTableCellRenderer implements TableCellRenderer {
        private Color corChkB = new Color(184,207,229);
        private JCheckBox checkbox = new JCheckBox();
      //private JLabel label       = new JLabel();
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component renderer;
         // Verifica se há Coluna tipo Boolean e altera parâmetros
            if (Boolean.class.equals(table.getModel().getColumnClass(column))) {
                renderer = checkbox;
              ((JCheckBox) renderer).setSelected((Boolean)value);
              ((JCheckBox) renderer).setHorizontalAlignment(getPosicao(0));
              ((JCheckBox) renderer).setBorderPainted(true);
                if (hasFocus) { // Foco na celula
                  ((JCheckBox) renderer).setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
                } else {
                  ((JCheckBox) renderer).setBorder(noFocusBorder);
                }
                if (cor.length==0) { // Cor da celula
                    if (isSelected) {
                      ((JCheckBox) renderer).setBackground(corChkB);
                    } else {
                      ((JCheckBox) renderer).setBackground(Color.WHITE);
                    }
                }
                for (int[] pos : posicao) { // Alinhamento da celula
                    if (column == pos[0]) {
                      ((JCheckBox) renderer).setHorizontalAlignment(getPosicao(pos[1]));
                    }
                }
            } else{
                renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                //renderer = label;
                ((JLabel) renderer).setOpaque(true);
                ((JLabel) renderer).setText(String.valueOf(value));
                ((JLabel) renderer).setHorizontalAlignment(getPosicao(2));
              //((JLabel) renderer).setFont(new Font("Dialog", Font.PLAIN, 12));
                for (int[] pos : posicao) {
                    if (column == pos[0]) {
                        ((JLabel) renderer).setHorizontalAlignment(getPosicao(pos[1]));
                    }
                }
             // Trata
                for (int[] tip : tipo) {
                    if (column == tip[0] && (tip[1]==1||tip[1]==2)) {
                        Object val = table.getValueAt(row, column);
                        if (val instanceof Double) {  
                            Double valor = (Double) val;  
                          ((JLabel) renderer).setText(getValor(valor,tip[1]));  
                          
                        } else
                        if (val instanceof BigDecimal) {  
                            BigDecimal valor = (BigDecimal) val;  
                          ((JLabel) renderer).setText(getValor(valor,tip[1]));  
                        }
                    }
                }
            }
          // Altera a Cor
            if (cor.length>=6) {
                Color foreground;
                Color background;
                if (isSelected) {
                    foreground = Color.getHSBColor(cor[0],cor[0],cor[0]);
                    background = Color.getHSBColor(cor[1],cor[1],cor[1]);
                } else {
                    if (row % 2 == 0) {
                        foreground = Color.getHSBColor(cor[2],cor[2],cor[2]);
                        background = Color.getHSBColor(cor[3],cor[3],cor[3]);
                    } else {
                        foreground = Color.getHSBColor(cor[4],cor[4],cor[4]);
                        background = Color.getHSBColor(cor[5],cor[5],cor[5]);
                    }
                }
                renderer.setForeground(foreground);
                renderer.setBackground(background);
            }
            return renderer;
        }
    }
    public int getPosicao(int posicao) {
        switch (posicao) {
            case 0: return SwingConstants.CENTER;
            case 1: return SwingConstants.RIGHT;
            default:return SwingConstants.LEFT;
        }
    }
    public String getValor(Double valor, int tipo) {
        if (tipo==1) {
            return (valor != null ? nf.format(valor) : "");
        } else {
            return (valor != null ? df.format(valor) : "");
        }
    }
    public String getValor(BigDecimal valor, int tipo) {
        if (tipo==1) {
            return (valor != null ? nf.format(valor) : "");
        } else {
            return (valor != null ? df.format(valor) : "");
        }
    }
}