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

M

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?

M

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?

J
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

M

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

M

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.

M

Charles,

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

Márcio

D

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;

M

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.

M

Charles,

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

Até amanhã

Márcio

J

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.

M

Charles,

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

Vou dar uma olhada e respondo quando puder.

Abraços,

Márcio

J
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.

J

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.

J

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