Formatando números no JTable

24 respostas
C

Caros,

Como posso fazer uma coluna no JTable mostrar zeros depois da vírgula (quando a coluna imprimir dados do tipo Double)?
Por exemplo: No meu banco do dados eu defini uma coluna sendo 'Valor" e esta possui 6 números inteiros e 4 decimais. Gostaria de mostrar o número completo, mesmo que esse seja 0. Se for 0 (zero) deveria aparecer 0,0000. Ou ainda se o valor for 3,5 deverá aparecer 3,5000.

desde já agradeço

24 Respostas

marcioa1

Charles,

Veja o código abaixo

public Object getValueAt(int rowIndex, int columnIndex) { Vector row = (Vector)rows.elementAt(rowIndex); if (columnIndex==colunaNormal){ return row.elementAt(columnIndex); } else { NumberFormat formatter = new DecimalFormat("###,###,##0.0000"); String s = formatter.format((Float)row.elementAt(columnIndex)); return s; } }

Coloque-o no seu model ( você está usando um , não está ? ) .

Márcio

C

Perfeito, só que eu necessito que o número fique alinhado à direita e como ele é uma String, na coluna da JTable, este fica alinhado à esquerda. É possível alinhá-lo à direita?

marcioa1

VocE^precisa definir os Renderes da tabela. Eles determinam sua aparência.

O cópodigo abaixo é de um programa meu. Dê uma olhada.
private void defineRenderers() {
		DefaultTableCellRenderer rendererCentro = new DefaultTableCellRenderer();
		rendererCentro.setHorizontalAlignment(SwingConstants.CENTER);
		DefaultTableCellRenderer rendererDireita = new DefaultTableCellRenderer();
		rendererDireita.setHorizontalAlignment(SwingConstants.RIGHT);
		DefaultTableCellRenderer rendererEsquerda = new DefaultTableCellRenderer();
		rendererEsquerda.setHorizontalAlignment(SwingConstants.LEFT);

		JTableHeader header = tabela.getTableHeader(); 
		header.setPreferredSize(new Dimension(0, 25)); 
		TableColumnModel modeloDaColuna = tabela.getColumnModel();
		
		modeloDaColuna.getColumn(0).setCellRenderer(rendererEsquerda);
		modeloDaColuna.getColumn(1).setCellRenderer(rendererDireita);
		modeloDaColuna.getColumn(2).setCellRenderer(rendererDireita);
		modeloDaColuna.getColumn(3).setCellRenderer(rendererDireita);
		modeloDaColuna.getColumn(4).setCellRenderer(rendererDireita);
		
		modeloDaColuna.getColumn(0).setPreferredWidth(300);
		modeloDaColuna.getColumn(1).setMaxWidth(80);
		modeloDaColuna.getColumn(2).setMaxWidth(80);
		modeloDaColuna.getColumn(3).setMaxWidth(80);
		modeloDaColuna.getColumn(4).setMaxWidth(80);
	}

Tem artigo sobre JTabel aqui no GUj. Dê uma procurada.

Abraço,

Márcio

C

Ótimo!! Deu certo.

C

Consegui formatar e alinhar os dados da maneira que gostaria na JTable, porém percebi que ao ordenar (processo de ordenamento dos dados da JTable, ao clicar no cabeçalho da tabela; disponível no site da Sun), devido o valor ser uma String, ele ordena errado. Existe uma maneira de eu formatar os números com vírgula e deixá-los no formato Double?

JP1
marcioa1:
VocE^precisa definir os Renderes da tabela. Eles determinam sua aparência. O cópodigo abaixo é de um programa meu. Dê uma olhada.
private void defineRenderers() {
		DefaultTableCellRenderer rendererCentro = new DefaultTableCellRenderer();
		rendererCentro.setHorizontalAlignment(SwingConstants.CENTER);
		DefaultTableCellRenderer rendererDireita = new DefaultTableCellRenderer();
		rendererDireita.setHorizontalAlignment(SwingConstants.RIGHT);
		DefaultTableCellRenderer rendererEsquerda = new DefaultTableCellRenderer();
		rendererEsquerda.setHorizontalAlignment(SwingConstants.LEFT);

		JTableHeader header = tabela.getTableHeader(); 
		header.setPreferredSize(new Dimension(0, 25)); 
		TableColumnModel modeloDaColuna = tabela.getColumnModel();
		
		modeloDaColuna.getColumn(0).setCellRenderer(rendererEsquerda);
		modeloDaColuna.getColumn(1).setCellRenderer(rendererDireita);
		modeloDaColuna.getColumn(2).setCellRenderer(rendererDireita);
		modeloDaColuna.getColumn(3).setCellRenderer(rendererDireita);
		modeloDaColuna.getColumn(4).setCellRenderer(rendererDireita);
		
		modeloDaColuna.getColumn(0).setPreferredWidth(300);
		modeloDaColuna.getColumn(1).setMaxWidth(80);
		modeloDaColuna.getColumn(2).setMaxWidth(80);
		modeloDaColuna.getColumn(3).setMaxWidth(80);
		modeloDaColuna.getColumn(4).setMaxWidth(80);
	}

Tem artigo sobre JTabel aqui no GUj. Dê uma procurada.

Abraço,

Márcio

Tentei inserir este código na minha aplicação, mas infelizmente, não mudou a formatação da tabela, e nao gerou erro também, o que pode ser?

abs,
JP

marcioa1

JP,

Você deve chamar o método defineRenderes() após a criação da sua JTable. Qualquer coisa coloca o código da criação do JTable e da definição dos renders.

Márcio

marcioa1

Charles,

Não sei como resolver seu problema. Tente , no método setValueAt do seu model ( ele existe ? ) colocar os valores em double, e no método getValueAt ( também do seu model ) retornar a formatação dos valores. Deu apra entender ? Não coloque Strings na coluna de valor, e sim double. Para exibir formatado, o médoto getValueAt deve formatar o valro e retornar o String ( para aquela columna).

Me diga se deu certo.

Márcio

C

Eu tentei o recomendado, porém dá erro de conversão de tipos de dados. String para Double.

marcioa1

Charles,

Coloque o código do setValueAt() e getValueAt() para eu ver. Talvez seja necessário um cast.

Márcio

dyorgio

acredito que não seja necessário um cast…
acho que o problema esta nas virgulas (’,’) divisoras
de grupos decimais…retire-as antes de converter para double…
[]'s dyorgio

C

Bem, no array de Class[] onde ele pega o tipo de dados da coluna eu deixei como Double.class ok? o trecho asseguir está dentro do método getValueAt(int rowIndex, int columnIndex)

NumberFormat formatter = new DecimalFormat("##,###,###,##0.00"); String s = formatter.format(MeuArray[rowIndex].getValor()); Double d = new Double(s); return d;

o columnIndex eu uso em um switch que não está aqui, mas já uso com sucesso em outros exemplos.
Realmente esse exemplo dá problema com a ‘,’ da string formatada; Para tirar a dúvida coloquei um valor aleatório com zero no final depois da vírgula e este é mostrado na tabela sem a formatação.

NumberFormat formatter = new DecimalFormat("##,###,###,##0.00"); String s = formatter.format(125.30); Double d = new Double(s); return d;

marcioa1

Charles,

NumberFormat formatter = new DecimalFormat("##,###,###,##0.00"); String s = formatter.format(MeuArray[rowIndex].getValor()); Double d = new Double(s); return d;

Tente retornar o String mesmo

NumberFormat formatter = new DecimalFormat("##,###,###,##0.00"); String s = formatter.format(MeuArray[rowIndex].getValor()); return s;

Talvez funcione.

Márcio

C

Ele dá um: “Cannot format given Object as a Number”, provavelmente por causa da vírgula que ele coloca no número. O número é 134.30 mas ele passa como 134,30.

marcioa1

Charles,

Estou de saída. Amanhã tento te ajudar. Talvez eu sugira o AbstractTable Model. Dê uma olhada nele.

Até amanhã

Márcio

JP1

marcioa1:
JP,

Você deve chamar o método defineRenderes() após a criação da sua JTable. Qualquer coisa coloca o código da criação do JTable e da definição dos renders.

Márcio

Como eu faço para e a cad consulta ao banco de dados a tabela seja limpa e os dados sejam novamente jogados nela.

C

JP,

após fazer a consulta no BD você deve setar o model na JTable (está usando um TableModel?).

eu faço dessa maneira, deve resolver.

C

Marcio,

existe algum caminho para resolver este problema pela AbstractTableModel? Do outro jeito realmente não obtive sucesso.

desde já agradeço.

marcioa1

Charles,

Me manda seus fontes ( pode ser pro meu email : [email removido] )

Vou dar uma olhada e respondo quando puder.

Abraços,

Márcio

JP1
CharlesVHL:
JP,

após fazer a consulta no BD você deve setar o model na JTable (está usando um TableModel?).

tabela.setModel(meuTableModel);

eu faço dessa maneira, deve resolver.

Charles eu fiz como você me disse, mas não funcionou. Olha como esta minha consulta ao banco.

public static void atualizaLista(){
        String dbURL = "jdbc:mysql://localhost/jusms";
        Connection c = null;
        ResultSet r = null;

        try
        {
           Class.forName("com.mysql.jdbc.Driver").newInstance();
           c = DriverManager.getConnection(dbURL, "", "");
           Statement s = c.createStatement();
           r = s.executeQuery("SELECT * FROM users ORDER BY login");

           while (r.next()){
               DefaultTableModel modelo = (DefaultTableModel)getTabela().getModel();
               modelo.addRow(new String [] {r.getString("nome"), r.getString("login")});
               getTabela().setModel(modelo);
           }

        } catch (InstantiationException e)
        {
           e.printStackTrace();
        } catch (IllegalAccessException e)
        {
           e.printStackTrace();
        } catch (ClassNotFoundException e)
        {
           e.printStackTrace();
        } catch (SQLException e)
        {
           e.printStackTrace();
        } finally
        {
           try
           {
              r.close();
              c.close();
           } catch (SQLException e1)
           {
              e1.printStackTrace();
           }
        }
    }

Como devo fazer?

Obrigado.

C

JP,

este trecho de código que está aí é para popular seu TableModel correto? Você consegue mostrar os dados na tabela só na primeira vez? Então, você deverá fazer o seguinte: depois de executar este método ‘atualizaLista()’, o ‘modelo’ deve ser setado no seu JTable (ex.: minhaTabela.setModel(modelo)); Talvez seja uma boa idéia você fazer este método retornar DefaultTableModel -> modelo para que você possa setar sua JTable.

Espero que tenha ajudado, me diga se deu certo.

JP1

Não deu certo…

Eu consigo pegar novamente os dados da tabela, so que ele nao atualiza ela do jeito certo, ele mostra os dados antigos, e embaixo ele mostra a nova consulta. Repetindo dados.

Eu já tentei:

[<em>]repaint();

[</em>]revalidate();

[*]updateUI();
C

Aqui está um Model bem simples de uma tabela que mostra os continentes cadastrados no BD:

package objetos;

import bancodados.Conexao;
import javax.swing.table.AbstractTableModel;
import java.util.Vector;

public class ContinenteTableModel extends AbstractTableModel
{
    //Títulos das colunas.
    static protected String[] columnNames = {"Continente"};
    // Tipos das colunas.
    static protected Class[]  cTypes = {String.class};
    //Array com informações dos continentes.
    protected Continente[] o;
    
    public ContinenteTableModel()
    {
        o = new Continente[0];
    }
    
    public ContinenteTableModel(Conexao con)
    {
        Continente c = new Continente();
        Vector v = new Vector();
        v = c.loadTableModel(con); //Consulta no BD.
        o = new Continente[v.size()];
        v.copyInto(o);
    }

    public void addValue(Continente pJ)
    {
        int q = o.length;
        Continente[] u = new Continente[q + 1];

        for(int r = 0; r < q; r++)
        {
            u[r] = o[r];
        }

        u[u.length - 1] = pJ;
        o = new Continente[u.length];
        o = u;
    }

    public void deleteValue(Continente pJ)
    {
        int q = o.length;
        Continente[] u = new Continente[q - 1];

        boolean s = false;
        for(int r = 0; r < q; r++)
        {
            if(o[r].getCodContinente() == pJ.getCodContinente())
            {
                if(r < u.length)
                    u[r] = o[r + 1];
                s = true;
            }
            else
            {
                if(r < u.length)
                {
                    if(!s)
                    {
                        u[r] = o[r];
                    }
                    else
                    {
                        u[r] = o[r + 1];
                    }
                }
            }
        }

        o = new Continente[q - 1];
        o = u;
    }

    /** Returns the number of columns in the model. A
     * <code>JTable</code> uses this method to determine how many columns it
     * should create and display by default.
     *
     * @return the number of columns in the model
     * @see #getRowCount
     *
     */
    public int getColumnCount()
    {
        return columnNames.length;
    }

    public String getColumnName(int column) 
    {
        return columnNames[column];
    }

    /** Returns the number of rows in the model. A
     * <code>JTable</code> uses this method to determine how many rows it
     * should display.  This method should be quick, as it
     * is called frequently during rendering.
     *
     * @return the number of rows in the model
     * @see #getColumnCount
     *
     */
    public int getRowCount()
    {
        return o.length;
    }
    
    /** Returns the value for the cell at <code>columnIndex</code> and
     * <code>rowIndex</code>.
     *
     * @param	rowIndex	the row whose value is to be queried
     * @param	columnIndex 	the column whose value is to be queried
     * @return	the value Object at the specified cell
     *
     */
    public Object getValueAt(int rowIndex, int columnIndex)
    {
        if(rowIndex < o.length)
        {
            switch (columnIndex)
            {
		//-1 - para quando eu quiser buscar o Registro inteiro.
                case -1:
                    return o[rowIndex];
                case 0:
                    return new String(o[rowIndex].getContinente());
                default:
                    return null;
            }
        }
        else
            return null;
    }

    public Class getColumnClass(int c)
    {
        return cTypes[c];
    }

    /*
     * Don't need to implement this method unless your table's
     * data can change.
     */
    public void setValueAt(Object value, int row, int col)
    {
        if(row < o.length)
        {
            switch (col)
            {
                case 0:
                    o[row].setContinente(value.toString());
                    break;
            }
        }
        fireTableCellUpdated(row, col);
    }
}

Aqui está o objeto Continente, pode ver que eu crio um Array do tipo Continente no TableModel, ali que eu guardo os registros lidos no BD:

package objetos;

import bancodados.Conexao;
import bancodados.BDContinente;
import java.util.*;

public class Continente
{
    private int codContinente;
    private String continente, erro;
    private boolean excessao;

    public Continente()
    {
        codContinente = 0;
        continente = "";
        erro = "";
        excessao = false;
    }

    public Continente(Continente c)
    {
        codContinente = c.getCodContinente();
        continente = c.getContinente();
        erro = c.getErro();
        excessao = c.getExcessao();
    }

    public void setCodContinente(int codigo)
    {
        try
        {
            codContinente = codigo;
        }
        catch(Exception e)
        {
            codContinente = 0;
        }
    }

    public void setContinente(String nome)
    {
        try
        {
            continente = nome;
        }
        catch(Exception e)
        {
            continente = "";
        }
    }

    public void setErro(String s)
    {
        try
        {
            erro += s.trim() + " ";
        }
        catch(Exception e)
        {
            erro = "";
        }
    }

    public void setExcessao(boolean b)
    {
        try
        {
            excessao = b;
        }
        catch(Exception e)
        {
            excessao = false;
        }
    }

    public void limpaErro()
    {
        try
        {
            erro = "";
        }
        catch(Exception e)
        {
            erro = "";
        }
    }

    public int getCodContinente()
    {
        try
        {
            return codContinente;
        }
        catch(Exception e)
        {
            return 0;
        }
    }

    public String getContinente()
    {
        try
        {
            return continente;
        }
        catch(Exception e)
        {
            return "";
        }
    }

    public String getErro()
    {
        try
        {
            return erro;
        }
        catch(Exception e)
        {
            return "";
        }
    }

    public boolean getExcessao()
    {
        try
        {
            return excessao;
        }
        catch(Exception e)
        {
            return false;
        }
    }

    public Vector loadTableModel(Conexao con)
    {
        Vector retorno = new Vector();

        try
        {
            BDContinente bdC = new BDContinente();

            retorno = bdC.loadTableModel(con);
        }
        catch (Exception e)
        {
        }
        return retorno;        
    }
}

A classe a seguir é onde eu defino as consultas no BD:

package bancodados;


import objetos.Continente;
import objetos.ValidaData;
import java.sql.*;
import java.util.*;

public class BDContinente
{
    public Vector loadTableModel(Conexao con)
    {
        Continente c;
        Vector tabela = new Vector(1, 10);

        try
        {
            Statement statement = con.connect.createStatement();

            String query = "SELECT * FROM Continente ORDER BY Continente ASC";

            ResultSet rs = statement.executeQuery(query);

            try
            {
                while (rs.next())
                {
                    c = new Continente();
                    c.setCodContinente(rs.getInt("CodContinente"));
                    c.setContinente(rs.getString("Continente"));

                    tabela.addElement(c);
                }
            }
            catch(SQLException sqlex)
            {
                sqlex.printStackTrace();
            }

            statement.close();
        }
        catch(SQLException sqlex)
        {
            sqlex.printStackTrace();
        }
        tabela.trimToSize();

        return tabela;
    }
}

Você deve criar uma instância de Conexao para se conectar ao BD (já deixei configurado para o seu BD):

package bancodados;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.sql.*;

public class Conexao
{
   public Conexao()
   {
      try
      {
	 url = "jdbc:mysql://localhost/jusms";
         Class.forName("com.mysql.jdbc.Driver").newInstance();
	 connect = DriverManager.getConnection(dbURL, "", "");
	 conexao = true;
	 status = "Conexão com banco de dados ativado.";

      }
      catch(ClassNotFoundException cnfex)
      {
         cnfex.printStackTrace();
         conexao = false;
         status = "Conexão com banco de dados desativado.";
      }
      catch(Exception ex)
      {
         ex.printStackTrace();
         status = "Conexão com banco de dados desativado.";
      }
   }

   public void disconnect()
   {
       try
       {
           connect.close();
       }
       catch(Exception e)
       {
       }
   }

   public Connection getConexao()
   {
       return connect;
   }

   public String getStatus()
   {
      return status;
   }

   protected String url;
   protected String status;
   protected boolean conexao;
   protected Connection connect;
}

Agora que você já possui o TableModel, o Objeto e a Consulta ao BD é só montar o TableModel e setá-lo na JTable. Declare as variáveis a seguir na classe onde está o JTable...

//variáveis necessárias na classe GUI (Interface gráfica)
//Cria conexao com o BD;
private Conexao conexao = new Conexao();
private ContinenteTableModel cTM;

...e no construtor desta mesma classe faça como no código a seguir:

//conexao - instância da classe Conexao.
               cTM = new ContinenteTableModel(conexao);
                tabPrincipal.setModel(sorter);

Sempre que você quiser atualizar o JTable, basta criar novamente o cTM (cTM = new ContinenteTableModel(conexao)) e setá-lo na JTable. Eu faço assim e funciona bem. Espero que não tenha ficado muito confuso. Se precisar de ajuda estamos ai.

JP1

Muito obrigado, hoje a noite eu vou pegar esses exemplos e irei implementar aqui. Caso apareçam dúvidas(com certeza sempre tem) eu volto aqui.

Muito obrigado :thumbup:

Criado 15 de julho de 2005
Ultima resposta 22 de jul. de 2005
Respostas 24
Participantes 4