Projeto Towel: AutoFiltro em JTable

118 respostas
V

Conheçam a classe do Auto-Filtro em JTable, do projeto Towel.
Funciona exatamente igual ao AutoFiltro do Excel, porém, também suporta filtro por wildcards (estilo os do DOS).

Dêem uma olhada.

118 Respostas

M

Pena que vi isso só agora precisei disso a um tempo e acabei criando o meu.

Mas o meu TableModel, TableHeader e RowFilter se baseia em Reflection.

J
ViniGodoy:
Depois de ver muita gente pedindo aqui no GUJ, decidi postar nossa classe de AutoFiltro para JTable. Funciona exatamente igual ao AutoFiltro do Excel, porém, também suporta filtro por wildcards (estilo os do DOS).

Também anexei um TableModel muito mais inteligente que o DefaultTableModel. Ele se baseia num enum de colunas e já tem todas as funcionalidades que esperamos de um model (ele é muito próximo de um ArrayList).

Dêem uma olhada. Aí tem também um exemplo, que escrevi para mostrar para um aluno meu como se fazia para usar.


Me desculpe por voltar nesse assunto mas eu peguei seu código e não consegui colocar ele na minha tabela.

Tenho um AbstractTabelModel com os seguintes tipos de colunas:
public class FinanceiroTableModel extends AbstractTableModel implements TableModelListener {

    public static String[] TOOLTIP = {
        "Selecionar para fazer uma ação na linha",
        "Situação do lançamento",
        "Data de emissão do documento",
        "Data de vencimento do documento",
        "Descrição do lançamento",
        "Número do documento utilizado",
        "Valor lançado no documento",
        "",
        "", "", "", "", "", "", ""};
    private static final String[] NOME_COLUNA = new String[]{
        "",
        "Status",
        "Emissão",
        "Vencimento",
        "Descrição",
        "No. Doc",
        "Valor",
        "Observação",
        "Tipo",
        "Conta",
        "Subconta",
        "Liquidação",
        "Valor Pago",
        "Vendedor",
        "Cobrança"};
    public static final int[] WIDTH = {20, 150, 90, 90, 350, 90, 110, 350, 30, 160, 160, 90, 110, 200, 200};
    private static final Class[] TIPO_COLUNA = {
        Boolean.class,
        String.class,
        Date.class,
        Date.class,
        String.class,
        Integer.class,
        Double.class,
        String.class,
        String.class,
        Conta.class,
        SubConta.class,
        Date.class,
        Double.class,
        String.class,
        String.class
    };
    ArrayList<Financeiro> lista;
    JTable table;

    public FinanceiroTableModel(JTable table) {
        this.table = table;
        this.lista = new ArrayList<Financeiro>();
    }

    public FinanceiroTableModel(ArrayList<Financeiro> lista) {
        this.lista = lista == null ? new ArrayList<Financeiro>() : lista;
    }
...
Na view:
FinanceiroTableModel modelo = new FinanceiroTableModel(tabela);
        tabela.setModel(modelo);
        TableColumnModel cm = tabela.getColumnModel();
        for (int i = 0; i < FinanceiroTableModel.WIDTH.length; i++) {
            cm.getColumn(i).setPreferredWidth(FinanceiroTableModel.WIDTH[i]);
        }
        //Lib.setHeaderTabela(tabela);
        cm.getColumn(5).setCellRenderer(new IntegerRenderer());
        cm.getColumn(6).setCellRenderer(new MoneyRenderer());
        cm.getColumn(12).setCellRenderer(new MoneyRenderer());

        JTextField textField = new JTextField();
        textField.setBorder(BorderFactory.createEmptyBorder());
        DefaultCellEditor editor = new DefaultCellEditor(textField);
        editor.setClickCountToStart(1);
        cm.getColumn(4).setCellEditor(new StringActionTableCellEditor(editor));
        cm.getColumn(7).setCellEditor(new StringActionTableCellEditor(editor));
...
Será que você poderia me dar uma dica como eu posso usar esse seu Filtro na minha tabela?
V

Por que seu model tem uma referência à tabela? Essa referência não deveria existir! =o

FinanceiroTableModel modelo = new FinanceiroTableModel(tabela);  
TableFilter filtro = new TableFilter(tabela.getTableHeader(), modelo);
tabela.setModel(filtro);

É bom guardar a variável do filtro em uma propriedade, já que você precisará dela para converter as linhas da view na linha do model, e vice-versa.

J

ViniGodoy:
Por que seu model tem uma referência à tabela? Essa referência não deveria existir! =o

FinanceiroTableModel modelo = new FinanceiroTableModel(tabela);  
TableFilter filtro = new TableFilter(tabela.getTableHeader(), modelo);
tabela.setModel(filtro);

É bom guardar a variável do filtro em uma propriedade, já que você precisará dela para converter as linhas da view na linha do model, e vice-versa.

Tenho uma referência a tabela porque tenho esse método aqui:

public void tableChanged(TableModelEvent e) { if (e.getType() == TableModelEvent.UPDATE) { int column = e.getColumn(); int row = e.getFirstRow(); table.setColumnSelectionInterval(column + 1, column + 1); table.setRowSelectionInterval(row, row); } }

Esse filtro na verdade apenas reordena as linhas da tabela?

V

Ele reordena e filtra.

O problema é que você passa a ter dois índices, e isso provavelmente irá quebrar seu método.

Um deles é o que o tablefilter está exibindo, o outro é o do seu model. O tablefilter tem métodos para converter um índice no outro.

J
ViniGodoy:
Por que seu model tem uma referência à tabela? Essa referência não deveria existir! =o
FinanceiroTableModel modelo = new FinanceiroTableModel(tabela);  
TableFilter filtro = new TableFilter(tabela.getTableHeader(), modelo);
tabela.setModel(filtro);

É bom guardar a variável do filtro em uma propriedade, já que você precisará dela para converter as linhas da view na linha do model, e vice-versa.

Quando eu uso meu AbastractTableModel:
FinanceiroTableModel modelo = new FinanceiroTableModel(tabela);
tabela.setModel(modelo);
TableColumnModel cm = tabela.getColumnModel();
for (int i = 0; i < FinanceiroTableModel.WIDTH.length; i++) {
    cm.getColumn(i).setPreferredWidth(FinanceiroTableModel.WIDTH[i]);
}
cm.getColumn(5).setCellRenderer(new IntegerRenderer());
cm.getColumn(6).setCellRenderer(new MoneyRenderer());
cm.getColumn(12).setCellRenderer(new MoneyRenderer());

JTextField textField = new JTextField();
textField.setBorder(BorderFactory.createEmptyBorder());
DefaultCellEditor editor = new DefaultCellEditor(textField);
editor.setClickCountToStart(1);
cm.getColumn(4).setCellEditor(new StringActionTableCellEditor(editor));
cm.getColumn(7).setCellEditor(new StringActionTableCellEditor(editor));

...
//======= Adicionando uma linha no modelo
ArrayList<Financeiro> lista1 = new ArrayList<Financeiro>();
FinanceiroTableModel modelo = (FinanceiroTableModel) tabelaContaPagarReceber.getModel();
Financeiro item1 = new Financeiro();
item1.setCodigo(1);
item1.setStatus("LIQUIDADO");
item1.setDataEmissao(new Date());
item1.setDataVencimento(new Date());
item1.setDescricao("COPOLA");
item1.setNumeroDocumento(1001);
item1.setValor(10.00);
item1.setObservacao("");
item1.setTipoDocumento("NF");
item1.setConta(new Conta(1, "RECEITA DE CLIENTE", 1));
item1.setSubConta(new SubConta(1, 1, "VENDA DE SERVIÇOS", true));
item1.setDataLiquidacao(new Date());
item1.setValorPagoRecebido(10.00);
item1.setVendedorSolicitante("FRANCISCO");
item1.setCobrançaPagamento("BRADESCO 234327483274932");
lista1.add(item1);
modelo.setLista(lista1);
Sai com as colunas formatadas com os tamanhos que eu defini e eu consigo adicionar linhas (Financeiro) tranqüilamente: [img]http://lh3.ggpht.com/_iPEXgELGyFA/Sp2ZlNfhe8I/AAAAAAAAA2I/PuB1leb4jxA/Financeiro-1.png[/img] Agora quando eu aplico o modelo com o Filtro as colunas saem todas desconfiguradas e eu não consigo adicionar linhas:
FinanceiroTableModel modelo = new FinanceiroTableModel(tabela);
tabela.setModel(modelo);
TableColumnModel cm = tabela.getColumnModel();
for (int i = 0; i < FinanceiroTableModel.WIDTH.length; i++) {
    cm.getColumn(i).setPreferredWidth(FinanceiroTableModel.WIDTH[i]);
}
cm.getColumn(5).setCellRenderer(new IntegerRenderer());
cm.getColumn(6).setCellRenderer(new MoneyRenderer());
cm.getColumn(12).setCellRenderer(new MoneyRenderer());

JTextField textField = new JTextField();
textField.setBorder(BorderFactory.createEmptyBorder());
DefaultCellEditor editor = new DefaultCellEditor(textField);
editor.setClickCountToStart(1);
cm.getColumn(4).setCellEditor(new StringActionTableCellEditor(editor));
cm.getColumn(7).setCellEditor(new StringActionTableCellEditor(editor));
filtroFinanceiro = new TableFilter(tabela.getTableHeader(), modelo);
tabela.setModel(filtroFinanceiro);
[img]http://lh5.ggpht.com/_iPEXgELGyFA/Sp2ZlSru2hI/AAAAAAAAA2M/Bh6yf0AgqIg/Financeiro-2.png[/img]
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: util.gui.table.TableFilter cannot be cast to kmoney.lib.model.table.FinanceiroTableModel

Alguma dica de como eu poderia resolver isso?

V

Nessa linha:
(FinanceiroTableModel) tabelaContaPagarReceber.getModel();

Você está tentando obter o model e fazer um cast para FinanceiroTableModel. No entanto, o model da tabela agora é um TableFilter.

Eu sugiro que você guarde uma referência do seu Model e do Filter, em atributos que você tenha certeza de quem é quem. Então, evite a chamada de table.getModel e use esses atributos diretamente.

J

Ok, eu guardei a referência ao filtro, minha pergunta é: como eu adiciono dados a JTable?
Quando eu usava o meu modelo eu tinha um método nele que recebia uma lista e atualizava o modelo e a tabela, agora nesse modelo do TableFilter eu não entendi como adicionar dados nele.

V

Basta adicionar dados ao seu modelo, normalmente (e não ao filtro).
Por isso é importante guardar uma referência para o model e para o filtro.

J

Ok, muito obrigado, funcionou como você disse, agora eu gostaria de saber porque está sendo perdida todas as minhas configurações no ColumnModel (CellRenders, CellEditor, largura das colunas)?

No construtor da classe TableFilter eu verifiquei as larguras das colunas e estão chegando corretamente.

public TableFilter(JTableHeader tableHeader, TableModel tableModel) {
        this.filters = new HashMap<Integer, Filter>();
        this.filteredRows = new ArrayList<Integer>();

        this.disableColumns = new TreeSet<Integer>();
        this.sortedOnlyColumn = new TreeSet<Integer>();
        this.upToDateColumns = new HashSet<Integer>();
        this.filterByColumn = new HashMap<Integer, List<Integer>>();

        this.header = tableHeader;
        
        // Codigo adicionado somente para verificar as larguras adicionadas previamente nas colunas
        TableColumnModel cm = tableHeader.getColumnModel();
        for (int i = 0; i < cm.getColumnCount(); i++) {
            System.out.println("Coluna " + i + " = " + cm.getColumn(i).getWidth());
        }
        
        tableHeader.getColumnModel().addColumnModelListener(
                new TableColumnModelAdapter() {

                    @Override
                    public void columnAdded(TableColumnModelEvent e) {
                        int modelIndex = header.getColumnModel().getColumn(e.getToIndex()).getModelIndex();
                        refreshHeader(modelIndex);
                    }
                });
        setTableValues(tableHeader, tableModel);
    }


Coluna 0 = 20
Coluna 1 = 150
Coluna 2 = 90
Coluna 3 = 90
Coluna 4 = 350
Coluna 5 = 90
Coluna 6 = 110
Coluna 7 = 350
Coluna 8 = 30
Coluna 9 = 160
Coluna 10 = 160
Coluna 11 = 90
Coluna 12 = 110
Coluna 13 = 200
Coluna 14 = 200
V

Não sei, nunca vi esse comportamento. E olha que também uso colunas de tamanho diferente, etc.

Não funciona nem se vc definir esses dados depois de associar o filtro?

J
Muito obrigado, agora funcionou, espero não mais ter que precisar te incomodar com esse assunto novamente.
private void setMontaTabelaFinanceiro(JTable tabela) {
        modeloFinanceiro = new FinanceiroTableModel(tabela);
        tabela.setModel(modeloFinanceiro);

        filtroFinanceiro = new TableFilter(tabela.getTableHeader(), modeloFinanceiro);
        tabela.setModel(filtroFinanceiro);

        TableColumnModel cm = tabela.getColumnModel();
        for (int i = 0; i < FinanceiroTableModel.WIDTH.length; i++) {
            cm.getColumn(i).setPreferredWidth(FinanceiroTableModel.WIDTH[i]);
        }
        cm.getColumn(5).setCellRenderer(new IntegerRenderer());
        cm.getColumn(6).setCellRenderer(new MoneyRenderer());
        cm.getColumn(12).setCellRenderer(new MoneyRenderer());

        JTextField textField = new JTextField();
        textField.setBorder(BorderFactory.createEmptyBorder());
        DefaultCellEditor editor = new DefaultCellEditor(textField);
        editor.setClickCountToStart(1);
        cm.getColumn(4).setCellEditor(new StringActionTableCellEditor(editor));
        cm.getColumn(7).setCellEditor(new StringActionTableCellEditor(editor));

        StripedTableCellRenderer.installInTable(tabela, new Color(223, 223, 223), Color.black, null, null);
    }
[img]http://lh4.ggpht.com/_iPEXgELGyFA/Sp5ugRXEBGI/AAAAAAAAA2U/VS8CFXKjY8c/Financeiro-4.png[/img]

Muito obrigado mesmo.

V

Sem problemas. Fico feliz em saber que a classe tenha funcionado num table complexo como o seu. :slight_smile:

J

Na verdade tenho mais uma pergunta.

Onde eu trato a formatação do dado adicionado naquele popUP da coluna, na imagem tem uma coluna do tipo Date que quero mostrar a data no formato: dd/MM/yyyy

Eu (ainda) não consegui localizar nos código onde está sendo feito isso, e também como converter de volta quando for selecionado pelo usuário para atualizar o filtro.

V

Na verdade, ali não trata. Aliás, é uma boa idéia. Numa dessas definir um renderer para lá.

Enfim, o que fazíamos para mostrar datas era retornar o date encapsulado num tipo chamado DateView.

O tipo era esse aqui:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class DateView implements Comparable&lt;DateView&gt;
{
    public static final DateView NULL = new DateView((Date) null);
    
    private Date date;
    private DateFormat format;

    public DateView(Date date)
    {
        this(date, DateFormat.getDateInstance(DateFormat.DEFAULT));
    }

    public DateView(Calendar cal)
    {
        this(cal, DateFormat.getDateInstance(DateFormat.DEFAULT));
    }

    public DateView(Date date, String format)
    {
        this(date, new SimpleDateFormat(format));
    }

    public DateView(Calendar cal, String format)
    {
        this(cal, new SimpleDateFormat(
                format));
    }

    public DateView(Date date, DateFormat format)
    {
        if (format == null)
            throw new IllegalArgumentException("Format cannot be null!");

        this.date = date;
        this.format = format;
    }

    public DateView(Calendar cal, DateFormat format)
    {
        this(cal == null ? (Date) null : cal.getTime(), format);
    }

    public int compareTo(DateView o)
    {
        if (date == null)
            return o.date == null ? 0 : -1;
        if (o.date == null)
            return 1;

        return date.compareTo(o.date);
    }

    @Override
    public String toString()
    {
        if (date == null)
            return "";

        return format.format(date);
    }

    @Override
    public int hashCode()
    {
        return (date == null) ? 0 : toString().hashCode();
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (getClass() != obj.getClass())
            return false;

        final DateView other = (DateView) obj;

        return toString().equals(other.toString());
    }
}

Nada mais é do que um wrapper que retorna a Data no formato que você quiser no toString(), mas faz a comparação usando os valores de data mesmo.

Aí, basta fazer seu model retornar um DateView no lugar de um Date. E no setValueAt, pegar o calendar que está associado ao DateView.

J

Não seria possível usar o mesmo renderer da coluna da tabela? Por exemplo: uma coluna moeda (currency) que possui um Double como tipo.

Eu não entendi direito como você usa esse DateView, e também não é apenas Date, tem Double também tem Integer.

J

Vinícius tenho que te perguntar mais uma coisa sobre esse filtro.

Seguinte, preciso que um método do meu modelo (que foi passado para o TableFilter) se executado apenas sobre as linhas filtradas, esse método retorna a soma dos valores em uma coluna (coluna valor a pagar).

Estou guardando as referências para os atributos conforme você me indicou:
modeloContasPagar = new ContasPagarTableModel(tabela);
        tabela.setModel(modeloContasPagar);

        filtroContasPagar = new TableFilter(tabela.getTableHeader(), modeloContasPagar);
        tabela.setModel(filtroContasPagar);
Coloquei o TableModelListener na tabela e estou testando pegar a soma tanto do modelo como do filtro, em nenhum dos casos o valor mudou:
tabela.getModel().addTableModelListener(new TableModelListener() {

            public void tableChanged(TableModelEvent e) {
                double valorPagar = modeloContasPagar.getValorTotalPagar();
                System.out.println("=========================");
                System.out.println("Valor a pagar = " + valorPagar);

                valorPagar = ((ContasPagarTableModel)filtroContasPagar.getTableModel()).getValorTotalPagar();
                System.out.println("Valor a pagar = " + valorPagar);

                if (e.getType() == TableModelEvent.INSERT) {
                } else if (e.getType() == TableModelEvent.DELETE) {
                }
            }
        });

Qual seria o método do filtro que eu tenho acesso as linhas filtradas?

Mais uma vez obrigado pelas dicas.
Francisco

V

Você acredita que só hoje vi sua dúvida? Ela ainda existe, ou conseguiu resolver?

Em todo caso, você usa o método getFilteredRows(). Ele retorna um list, com o índice das linhas que foram mantidas, após o filtro.

J

Ahahaha, já resolvi sim, acho que foi do jeito que você indicou mesmo, mesmo assim obrigado pela resposta.

Abz

R

Boma noite ao pessoal do forum.

Sou iniciante em Swing e estou penando na parte de tabelas.
Baixei o exemplo do Vini mas nao consegui adaptar para uma tabela vinda do banco de dados com varias colunas.
Como exemplo tenho uma tabela de Municipios que teria os campos codEstado, codigo e descricao.
Minha pergunta é como implementar a enumeracao para que receba os tres valores. No exemplo é recebido somente
uma .

É possivel receber um vetor (por exemplo) ou a propria classe “municipio” ? como fica a declaracao ?

public enum apMunicipio implements Column { // como fica a a substituicao do  para vincular aos campos abaixo

codEstado {

public Object getValue(String element) {

return element;

}

},

codigo {

public Object getValue(String element) {

return element;

}

},

descricao {

public Object getValue(String element) {

return element;

}

}

;

Obrigado

V

Só com uma String fica impossível. Você precisa de uma lista de Municipios, então, crie uma classe Municipio contendo os três valores e faça um Column<Municipio>.

C

Boa tarde galera!

Bom eu sou novo em programação java e estou estudando esse modelo de tabela porque até então eu usava a DefaultTableModel.
Mas eu não estou entendendo como eu adiciono as colunas nessa tabela.
Alguem me ajude por favor!

desde já agradeço

V

Você está tentando usar qual modelo? O Auto-Filtro não é um modelo, é só o filtro.
Junto ali tem o ColumnTableModel, é o que você está usando?

Eu recomendo que você use o ObjectTableModel, do Mark.

C

Sim, eu estou tentando usar o ColumnTableModel.

Bom eu acho q eh isso, me fale se eu estiver errado.

Eu tenho q criar um outro Enum implementando a classe Column, e lah eu adiciono as colunas?

outra coisa, qualquer um desses modelos funciona bem com o Hibernate?

obrigado

C

Mas de qualquer forma eu vou estudar o modelo do mark.

Vini eu queria uma opinião sua.

Eu sou recem formado em Sistemas de Informação, eu vi java na faculdade, mais foi basico.
Ai vai minha pergunta: como vcs sabem tudo isso de java, apenas estudando em livros, ou com cursos?
Eu estou estudando o livro Java como Programar do Deitel e tbm o manual do Hibernate, mas tem coisas que são difíceis de entender.

oq vc me sujere, para eu aprender melhor sobre java.

obrigado pela atenção.

V

Oi.

Fiz segundo grau Técnico em Processamento de Dados, na UFPR. Também me formei em Informática pela UTFPR. E ainda tenho pós-graduações em Jogos Digitais pela Universidade Positivo, além de 15 anos de profissão.

Então, como a gente sabe tanto de java? Estudando, trabalhando e ralando pra xuxu. :slight_smile:

É importante não querer fazer as coisas nas coxas. Tem muita gente que se acomoda e simplesmente “faz funcionar”, sem se preocupar se está ou não usando as melhores práticas, ou com manutenção futura. Se você começar a codificar sem entender o que está fazendo, está com um problema.

Para usar o ColumnTableModel, você deve criar um Enum de columns da sua classe de negócio. Ela certamente não será a classe String. O model funciona perfeitamente bem com Hibernate.

Por exemplo, qual é a sua classe de negócio que você quer exibir na tabela? Pode posta-la aqui? Se for uma tabela de clientes, a classe provavelmente será Cliente. Se for de produtos, será Produto. Enfim, que classe vc quer exibir na tabela?

C

Como eu estou utilizando uma classe simples apenas para estudo. Se eu entender o funcionamento basico o resto eu me viro bem.

estou utilizando a classe PessoaDTO (Modelo MVC).

ai esta a minha classe.

package br.com.JavaHibernate.DTO;

public class PessoaDTO

{

private String nome, rg, cpf, sexo;

private int id_pessoa;
//Metodos set's e get's ocultos.

}

V

Oi,

Uma dica: quando postar código aqui no fórum, ponha entre as tags code:
[code]
Seu código aqui
[/code]

Ok. Vamos fazer com sua classe simples.
Embora seja apenas um DTO (você deveria fazer o model sobre as classes quentes, não sobre os DTOs).

O columnTableModel trabalha com duas interfaces. A Column (para colunas read only) e a EditableColumn (para as editáveis). No caso, vamos fazer uma tabela não editável.

public enum PessoaColumns implements Column&lt;PessoaDTO&gt; {
    ID(&quot;Id&quot;) {
        //Esse método precisa retornar para o table o ID da pessoa
        public Object getValue(Pessoa p)
        {
            return p.getId();
        }        
    }, 
    NOME(&quot;Nome&quot;) {
        public Object getValue(Pessoa p)
        {
            return p.getNome();
        }        
    }, 
    RG(&quot;R.G.&quot;)  {
        public Object getValue(Pessoa p)
        {
            return p.getNome();
        }        
    };

   //Daqui para baixo, são configurações que valem para todas as colunas
   private final String nome;

   private PessoaColumns(String nome) {
      this.nome = nome;
   }
 
   public Class&lt; ? &gt; getColumnClass() {
        return Object.class;
   }

    public String getName() {
        return nome;
    }

  public TableCellRenderer getRenderer() {
        return null;
    }

    public int getModelIndex() {
        return ordinal();
    }

    public int getWidth() {
        return 100;
    }
}

Agora, bastaria fazer um ColumnTableModel<PessoaDTO> e passar as colunas desse enum para ele. E sua tabela já sairia funcionando.

C

Oi, ja estou entendendo, e vou parar de tomar seu tempo …hehehe…, mas eu soh gostaria de saber:

Eu não entendi sobre classes quentes.

no construtor do codigo q vc me passou, o Enum aceita apenas o modificador private e nao public como vc utilizou, posso deixar como private?

obs: ate hj eu nao tinha visto um construtor private!!

Porque vc me aconselha o modelo do mark (ObjectTableModel)?
É melhor q esse?

e eu consegui colocar as colunas na tabela. Muito obrigado mesmo pela grande ajuda.

obrigado.

I

Oi Vinny! Eu estou tentando fazer funcionar o seu modelo de TableModel mas estou tendo problemas na hora de setar as colunas…

estou fazendo dessa forma:

public void preenche_jtable(JTable MostraTabela, String nome) throws PersistenciaException
    {  

  ArrayList lista = new ArrayList();
        ClienteVO cli = null;
       
        String comandoSQL = "SELECT idCliente, nCartao, nome, telefone,celular, email FROM Cliente WHERE nome LIKE '" + nome.trim() + "%' ORDER BY nome";

        try {
             PreparedStatement comando = con.getConexao().prepareStatement(comandoSQL);
            ResultSet rs = comando.executeQuery();
         //   ColumnTableModel modelo = (ColumnTableModel) MostraTabela.getModel();
            //modelo.setNumRows(0);
            while (rs.next()) {
               cli = new ClienteVO();

                //.set(rs.get(""));
                cli.setId(rs.getInt("idCliente"));
                cli.setnCartao(rs.getString("nCartao"));
                cli.setNome(rs.getString("nome"));
                cli.setTelefone(rs.getString("telefone"));
                cli.setCelular(rs.getString("celular"));
                cli.setEmail(rs.getString("email"));
                lista.add(cli);



            }
            comando.close();
           
           ColumnTableModel modelo = new ColumnTableModel(lista);
          
           MostraTabela.setModel(modelo); 

        } catch (Exception ex) {
            throw new PersistenciaException(ex,"Erro na seleção por Nome");
        }
}

O erro que aparece é este: “You must provide at least one column!”

Eu nao estou entendendo esta parte de setar o numero de colunas…

vc pode me explicar?

Obrigada.

V

Dê uma olhadinha no construtor. Ele aceita 2 parâmetros, não 1.

Você deve passar para ele a definição das colunas com as quais ele vai trabalhar (veja o exemplo que dei ao caceres, na página anterior).

No caso, são as que você criou naquele enum.

//Pegamos as colunas do enum
Column&lt;ClienteVO&gt; colunas = ClienteVOColumns.values();

//Passamos para o model
ColumnTableModel modelo = new ColumnTableModel(lista, colunas);
V

caceres:
Porque vc me aconselha o modelo do mark (ObjectTableModel)?
É melhor q esse?

O do Mark é mais automático. Não exige tantas definições. Trabalha com anotações.

E pode deixar o construtor private sim, era o jeito certo, eu que me enganei.

De qualquer forma, ambos os modelos trabalham diretamente com sua classe de negócio, e não com aquela abominação de Vectors de Vectors de Objects que o DefaultTableModel faz. Nenhum deles exige que você use o getValueAt ou setValueAt diretamente. Sem casts, sem nada. Basta usar o get() e obter um objeto completo, do seu tipo. E o objeto terá, por exemplo, o getId() mesmo que o ID não esteja sendo exibido na tabela.

Nenhum deles faz qualquer tipo de cópia desnecessária de dados, e o Default trabalha baseado em cópias.

Ambos são super simples de usar, mais ainda de manter.

Além disso, ambos permitem que você faça as operações básicas como remover ou adicionar objetos ao modelo. Tudo usando os tipos corretos, reduzindo chances de bugs.

V

O DTO não é sua classe de negócio. Pelo menos, não deveria ser. Como o nome do padrão já diz é apenas um “Data Transfer Object”. Uma classe que você usa para transportar dados entre camadas diferentes da sua aplicação.

Se você usa-la como classe mesmo, estará criando um modelo anêmico, que deve ser evitado. Eu dificilmente uso DTOs, pois na minha opinião (também) eles vão contra o próprio princípio básico de se ter OO em primeiro lugar. Bem, esse assunto é tema para muita discussão.

Quando falei em classes quentes, falei para você usar as classes de negócio mesmo dentro do model, não os DTOs.

M

caceres:
Porque vc me aconselha o modelo do mark (ObjectTableModel)?
É melhor q esse?

Fora isso, a unica razão de eu e Vini termos implementado um TableModel pratico é que eu construi o meu sem saber da existencia do dele, pois provavelmente eu teria usado esse também.

Mas de qualquer forma… o resultado acabou ficando mais simples mesmo.

C

Obrigado ViniGodoy e Marky. Vou estudar essas melhores praticas dialogadas.
É engraçado q, eu acabei de me formar e ja vejo que algumas coisas q eu aprendi não é uma das melhores opções. (DTO’s da vida).
Eu só pesso um favor a quem puder ai. Mostrar algum tópico onde exemplifica o modelo de desenvolvimento em camadas sem o DTO.
Pode ser em forma de UML, desenhos no paint, qualquer coisa. Mas de qualquer forma eu estou estudando toda essas “novidades”.

Se não for incomodar é claro.
Obrigado, e vcs sao fera msm… hehehe
abraço a todos

V

O problema não está na existência de DTOs, per-se.
Mas os DTOs tem um propósito: servir de objetos de transporte para otimizar o uso de rede.
As versões mais modernas de EJB já dispensam a existência de DTOs em boa parte dos casos.

Mas, se você estudar a modelagem de objetos básica, vai ver que geralmente a lógica e os dados caminham juntos. Esse é o princípio da OO. E o que dizem os DTOs? Geralmente o contrário. Os DTOs nada mais são que agrupados de dados com gets e sets e, fora deles estão métodos para processar esses dados.

Mas conjuntos de dados separados das funções que as processam tem um nome: programação estruturada. DTOs não são muito diferentes de structs, assim como objetos sem atributos não são muito diferentes de namespaces de funções.

Quanto à referências, fica difícil te indicar uma assim, de bate e pronto. Mas você vai cruzar com bastante enquanto estiver estudando arquitetura. A maioria está em livros, como os do Fowler (inclusive o pattern DTO também está descrito no livro dele).

Ah, removi o seu e-mail do tópico anterior. Não poste e-mails aqui na área pública do GUJ, pq os bots de internet não perderão tempo em encontra-lo e te enviar muito lixo. Lembre-se, o fórum é publico para esses programinhas maldosos de e-mail marketing também. :wink:

C

Bom. Por mim esta encerrado. Obrigado, desculpas em perguntar um assunto fora do tópico (AutoFiltro em JTable).
Mas acho q pode ter ajudado mais pessoas tbm.
:smiley:

C

Boa tarde.

Alguém pode me informar onde eu altero as configurações da largura da coluna no JTable com o AutoFiltro (modelo do Vini), para ficar do tamanho da maior string da coluna que foi pega no banco de dados.

Eu tentei analisar o post no começo desse tópico que fala sobre isso, mas não entendi.

E tem como eu bloquear as colunas da tabela para que não sejam trocadas de lugar umas com as outras, com o mouse?

desde já agradeço.

M

Da um ligo nesse código que coloquei junto com meu projeto.

http://code.google.com/p/markutils/source/browse/trunk/src/mark/utils/swing/table/Resizer.java
Só adicionei o método fitAllColumns e aproveitei o código de um amigo aqui do fórum.
Ele faz o resize para o maior conteudo das celulas.

C

Valew Marky. Vou estuda-lo. :smiley:

V

É que largura de coluna é uma informação de view, não de model. O model trata dos dados. Por isso, você define largura de colunas usando o próprio objeto JTable. :wink:

C

Ah ta, eu entendi. Eu adaptei a classe q o Marky me passou e funcionou perfeitamente.
Muito Obrigado.

C

Bom dia a todos. Vini estou com um caso assim. Quando eu abro uma cosulta no banco de dados, eu ja do um select * na tabela do banco que eu quero os dados e jogo no meu jtable com seu model.
Dai eu to na duvida: se eu for selecionar uma linha para restaurar os dados da table para o formulario de apresentação, eu preciso fazer um outro select no banco ou tem como eu aproveitar os dados que ja foram localizados e estao em no list que eu joguei no seu modelo? - Para nao usar o getValueAt, pois nao tenho todos os atributos no table.

Daí, eu pensei q já q eu ja tinha feito um select e estava com todos os dados ali na aplicação nao seria necessario refazer um novo select filtrando, mas sim filtrar na aplicação. (Sendo q antes eu fazia isso, pois era mais facil).

Eu lembrei q vc citou q esse modelo nao precisa utilizar o metodo getValueAt, sendo assim, como utilizar seu modelo para resolver essa questão?

obrigado.

V

Tem sim. Basta você pegar os dados a partir do seu TableModel.

O auto-filtro tem um método que, baseado num valor selecionado da view, ele retorna a linha correspondente no model que está associado a ele. Você usa esse método e então pede pro TableModel o objeto, usando o método get.

C

Ah eh verdade, eu nem lembrava q ele ja fazia isso…rsrsrsrs… Esse auto filtro eh mto bom hein… foi vc q desenvolveu ele tbm??
mto obrigado.

V

caceres:
Ah eh verdade, eu nem lembrava q ele ja fazia isso…rsrsrsrs… Esse auto filtro eh mto bom hein… foi vc q desenvolveu ele tbm??
mto obrigado.

Sim. Eu desenvolvi o auto-filtro e o ColumnTableModel. Na verdade, não desenvolvi sozinho. Um colega do trabalho, o pnizer do fórum, desenvolveu comigo. Ele desenvolveu a primeira versão praticamente sozinho.

Quando começou a dar uns problemas, nós refizemos o filtro todo juntos (em pair programming). Não foi só um refactoring. Efetivamente sentamos, estudamos o conceito e remodelamos a classe inteira.

Deu um trabalhão, mas o resultado final ficou muito bacana.

O ColumnTableModel é autoria minha mesmo. Embora outro colega de trabalho, o anlugifa do fórum, também tivesse algo muito parecido nos projetos dele. Como o Column estava um pouco mais completo, nós só completamentamos com o que faltava, refatoramos para deixar um pouco mais flexível, e então chegamos a essa versão final.

C

Parabens, excelente trabalho. Obrigado.

C

Boa noite.

Vini, vc poderia exemplificar esses metodos… eu verifiquei todos os metodos q existe na classe TableFilter mas nao consegui uma logica para montar isso…

de inicio eu observei q tem os metodos q pegam a linha ou coluna editavel, mas eu nao sei qual eh q faz isso.

te juro q tentei mto… olha a hora q eu postei aqui…rsrsrsrs…

se puder me ajudar, agradeço mto…

V

Você vai fazer mais ou menos assim:

//Pega a linha da tabela selecionada.
//É a linha na view, não no model, pois pode estar filtrado
int vwSelected = suaTable.getSelectedRow();

//Obtém o índice dessa linha no model
int mdlSelected = tableFilter.getModelRow(vwSelected);

//Pede para o model o objeto que está naquela linha
SeuObjeto obj = seuTableModel.get(mdlSelected);

//Chama seu método que copia os dados do objeto
//para os JTextFields, JComboBoxes, etc...
preencherCampos(obj);

Além do getModelRow, existe também o método getModelRows. É útil para, por exemplo, quando você quiser excluir todas as linhas que estão selecionadas.

C

Rapaiz do céu, o negócio fico bunito d+…hehehhe…
Era tão simples e eu tava complicando…
Eu praticamente tava tentando fazer do zero (reinventar a roda - como se diz).
Eu tava pegando o list e jogando ele num outro list (para não perder os dados), e depois tentava filtrar, mais tava meio feio a coisa…

valew ae Vini… abração

H

Vini, esse exemple que vc deu ai pra fazer o FIlter da pra rodar pegando os dados vindos do banco?

Abri ele aki no netbeans e ve q tem outras class, qual q class principal pra o filtro?

M

habinovich, voce nao deveria se preocupar de onde os dados vem, e sim em como eles vão para na JTable, voce precisa estudar sobre o TableModel.

H

Eu consigo pegar os dados mas n consigo e filtra-los usando uma JtextField, para deixar na tabela so os dados q forem digitados neles!

L

Olá Vini,

Eu estava olhando a implementação do seu ColumnTableModel e não consegui entender qual a utilidade dos seguintes métodos:

public static <K, V> ColumnTableModel<Map.Entry<K, V>> createMapModel(Map<K, V> map, String keyHeader, String valueHeader)

public static void applyToTable(JTable table, List< ? extends Column< ? >> columns)

Poderia explicá-lo um pouco mais além do descrito nos comentários? Principalmente o applyToTable(), pois eu estou querendo renderizar componentes(como um JButton e um ComboBox) numa coluna e este método me parece ser o responsável por setar o Renderer e o Editor.

Eu implementei um exemplo, usando a interface EditableColumn, e consegui renderizar um JButton, porém, não sei se foi da forma correta, por dois motivos:
1º)Na minha classe de negocio(Pessoa) eu criei um atributo do tipo JButton e lá tem o método getBotao…muito estranho misturar atributos de negocio e um botão com uma ação de detalhe não acha?(rsrs)
2º)Na interface EditableColumn tem o método getEditor()(que retorna um TableCellEditor) e tem por extends o método getRenderer()(que retorna um TableCellRenderer), mas eu não os utilizei para renderizar o JButton eu deveria usa-los? E onde eles são chamados?

Eu consegui resolver a minha necessidade, mas não sei se da melhor maneira, entende. Tem alguma dica?

Obrigado pela atenção.

Abraços

W

Ola Vini, você poderia postar um exemplo simples de como implementar a classe EditableColumn (ao invés de Column)?

Estou em duvida como implementar o método public TableCellEditor getEditor().

V

Oi. Posso sim, mas no final de semana.

Lintz, desculpe não te responder. O GUJ não me enviou um e-mail com a sua dúvida, só vi hoje. Você ainda precisa disso?

L

Segue um exemplo:

package pessoaSimple;


public class Pessoa {
	private Integer id;
	private String nome;
	private String rg;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public String getRg() {
		return rg;
	}
	public void setRg(String rg) {
		this.rg = rg;
	}

}
package pessoaSimple;

import javax.swing.JButton;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import util.gui.table.EditableColumn;
import util.gui.table.UtilTableCellRenderer;

public enum PessoaColumns implements EditableColumn<Pessoa>{
	ID("Id") {   
        //Esse método precisa retornar para o table o ID da pessoa   
        public Object getValue(Pessoa p)   
        {   
            return p.getId();   
        }

    },   
    NOME("Nome") {   
        public Object getValue(Pessoa p)   
        {   
            return p.getNome();   
        }  
        public boolean isEditable(Pessoa p){
        	return true;
        }

    },   
    RG("R.G.")  {   
        public Object getValue(Pessoa p)   
        {   
            return p.getRg();   
        } 
        public boolean isEditable(Pessoa p){
        	return true;
        }
    };   
  
   private final String nome;
   
   //Daqui para baixo, são configurações que valem para todas as colunas
   private PessoaColumns(String nome) {   
      this.nome = nome;   
   }   
  
   public Class< ? > getColumnClass() {   
        return Object.class;   
   }   
  
    public String getName() {   
        return nome;   
    }   
  
    public TableCellRenderer getRenderer() {   
        return null;   
    }   
    
    public TableCellEditor getEditor(){
    	return null;
    }
  
    public int getModelIndex() {   
        return ordinal();   
    }   
  
    public int getWidth() {   
        return 300;   
    }   
    
    public boolean isEditable(Pessoa p){
    	return false;
    }
    
    public void setValue(Pessoa object, Object value){
    	
    }
    
}
package pessoaSimple;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;

import util.gui.table.ColumnTableModel;
import util.gui.table.UtilTableCellRenderer;

public class PessoaSample extends JFrame {


    private static final long serialVersionUID = 1L;
    private JPanel jContentPane = null;
    private JPanel pnlButtons = null;
    private JButton btnAdd = null;
    private JButton btnRemove = null;
    private JButton btnClose = null;
    private JScrollPane scrlTable = null;
    private JTable tblPessoa = null;
   // private TableFilter tableFilter;
    private ColumnTableModel<Pessoa> tableModel;

    public PessoaSample() {
        super();
        initialize();
    }

    private void initialize() {
        this.setSize(453, 304);
        this.setContentPane(getJContentPane());
        this.setTitle("JFrame");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private JPanel getJContentPane() {
        if (jContentPane == null) {
            jContentPane = new JPanel();
            jContentPane.setLayout(new BorderLayout());
            jContentPane.add(getPnlButtons(), BorderLayout.SOUTH);
            jContentPane.add(getScrlTable(), BorderLayout.CENTER);
        }
        return jContentPane;
    }

    private JPanel getPnlButtons() {
        if (pnlButtons == null) {
            pnlButtons = new JPanel();
            pnlButtons.setLayout(new FlowLayout());
            pnlButtons.add(getBtnAdd(), null);
            pnlButtons.add(getBtnRemove(), null);
            pnlButtons.add(getBtnClose(), null);
        }
        return pnlButtons;
    }

    private JButton getBtnAdd() {
        if (btnAdd == null) {
            btnAdd = new JButton();
            btnAdd.setText("Add");
            btnAdd.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent e) {
                    onAdd();
                }
            });
        }
        return btnAdd;
    }

    private JButton getBtnRemove() {
        if (btnRemove == null) {
            btnRemove = new JButton();
            btnRemove.setText("Remove");
            btnRemove.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent e) {
                    onRemove();
                }
            });
        }
        return btnRemove;
    }

    private JButton getBtnClose() {
        if (btnClose == null) {
            btnClose = new JButton();
            btnClose.setText("Close");
            btnClose.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent e) {
                    System.exit(0);
                }
            });
        }
        return btnClose;
    }

    private JScrollPane getScrlTable() {
        if (scrlTable == null) {
            scrlTable = new JScrollPane();
            scrlTable.setViewportView(getTblPessoa());
        }
        return scrlTable;
    }

    private JTable getTblPessoa() {
        if (tblPessoa == null) {
        	tblPessoa = new JTable();
            // Associe sua tabela ao table filter DEPOIS de cria-la
          //  tblString.setModel(getStringTableFilter());
        	tblPessoa.setModel(getPessoaTableModel());
        	
        	tblPessoa.setDefaultRenderer(JButton.class, UtilTableCellRenderer.getButtonRenderer());
        	tblPessoa.setDefaultEditor(JButton.class,  UtilTableCellRenderer.getButtonEditor());
        }
        return tblPessoa;
    }

     /**
     * Retorna o table model.
     */
    private ColumnTableModel<Pessoa> getPessoaTableModel() {
        if (tableModel == null) {
            // Esse model se comporta como um arraylist! :)
            tableModel = new ColumnTableModel<Pessoa>(PessoaColumns.values());
            ColumnTableModel.applyToTable(tblPessoa, PessoaColumns.values());
        }
        return tableModel;
    }

    private void onRemove() {
        if (getTblPessoa().getSelectedRowCount() == 0)
            return;

        // Precisamos traduzir as linhas que estamos vendo, para as linhas que
        // estão no
        // modelo. Fazemos isso usando esse método.
       // int[] modelRows = getStringTableFilter().getModelRows(
       //         getTblString().getSelectedRows());

        // Já fornecemos um método conveniente para esse tipo de remoção.
        getPessoaTableModel().remove(getTblPessoa().getSelectedRow());
    }

    private void onAdd() {
        String valueId= JOptionPane.showInputDialog("Entre com um id");
        if (valueId == null)
            return;
        
        String valueNome = JOptionPane.showInputDialog("Entre com um nome");
        if (valueNome == null)
            return;
        
        String valueRg = JOptionPane.showInputDialog("Entre com um RG");
        if (valueRg == null)
            return;
        
        Pessoa pessoa = new Pessoa();
        pessoa.setId(new Integer(valueId));
        
        pessoa.setNome(valueNome.toString());
        pessoa.setRg(valueRg.toString());
        
        pessoa.setAcao(new JButton());
        
        // Simplesmente adicionamos no model.
        getPessoaTableModel().add(pessoa);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new PessoaSample().setVisible(true);
            }
        });
    }


}
L

ViniGodoy:
Oi. Posso sim, mas no final de semana.

Lintz, desculpe não te responder. O GUJ não me enviou um e-mail com a sua dúvida, só vi hoje. Você ainda precisa disso?

Oi Vini,

Eu já descobri… mas valeu.

Abraços

X

Bom dia a todos.
É o meu primeiro post, espero que possa postar mais vezes.

Tenho uma dúvida, Marky e ViniGodoy vocês que são mais experientes usam hibernate com estes table models para popular a tabel?
Caso outras pessoas se interessarem, podem responder também, ficaria grato.

ViniGodoy:
Oi. Posso sim, mas no final de semana.

Lintz, desculpe não te responder. O GUJ não me enviou um e-mail com a sua dúvida, só vi hoje. Você ainda precisa disso?

V

Os models trabalham com listas de objetos. O hibernate carrega essas listas.
Então, sim, é possível interoperar um com o outro tranquilamente.

X

Muito obrigado Vini.
Estou procurando no forum a respeito do assunto, caso você ou outro user guj tenha algum link que se baseou para fazer essa implementação com hibernate e puder passar, ficaria grato.

Os models trabalham com listas de objetos. O hibernate carrega essas listas.
Então, sim, é possível interoperar um com o outro tranquilamente.

M

Voce não precisa mudar nada no model para funcionar com Hibernate, voce não pode misturar essas duas coisas.

Em algum lugar voce deve consultar com o hibernate os dados, pegar a List de objetos que ele retorna e passar para o model.

X

Marky, muito obrigado pela respota.
Gostaria de parabenizá-lo e ao Vini, pelos projetos referentes ao JTable, é muita dor de cabeça para quem inicia.

Irei buscar mais informação sobre o assunto, quando implementar, posto o agradecimento.

Marky.Vasconcelos:
Voce não precisa mudar nada no model para funcionar com Hibernate, voce não pode misturar essas duas coisas.

Em algum lugar voce deve consultar com o hibernate os dados, pegar a List de objetos que ele retorna e passar para o model.

B

ola Vini

kara vi q tu manda bem em table

kara to tentando implementar uma table com um combobox, vc por acaso teria um exemplo funcionando ?

pq todos os exemplos que achei a combo não fica selecionada o item que eu escolhi, sempre volta para o inicio

abc

V

Que tal criar um tópico sobre o assunto ao invés de pegar carona nesse, ou enviar MP?

H

ViniGodoy,

Pelo que tenho notado vc e o Mark são referência quando o assunto é JTable! (minha opinão)
Então, por que não fazer um artigo mostrado as boas práticas da JTable (que considero o componente mais complexo do swing), este artigo poderia mostrar e solucionar os erros mais frequentes postados no forum e assim juntar tudo em um unico documento.

Imagine os benefícios que seria para os desenvolvedores iniciantes e até mesmo pra vc, servir de referencia quando o assunto é JTable. Além disso, com este suposto artigo poderiamos referencia-lo sempre que alguém entrar no forum peguntando sobre JTable. Q tal?

Claro entendo que nisso tudo existe a questão do tempo. Por isso fica a dica.

I

Ola!

Gostaria de colocar um JButton em uma das minhas colunas sei (pelo menos acho) que tenho que sobrescrever o método getRenderer() só não sei como!

Sendo mais preciso a minha duvida é como ficaria o método getRenderer() para asseitar JButton. (se não é pedir muito)

se for pelo menos me indicam algum material que ensine a criar um objeto TableCellRenderer para que eu consiga pelo menos tetar sobrscrever

até!

V

Oi. Crie um tópico para a dúvida.

I

Ok. Desculpa por postar no lugar errado é que sou novo por aqui!

até!

C

Vini, esse seu modelo tem algum método que me retorna a lista da forma que o usúario ordenou?

Pois eu preciso gerar um relatório em PDF (utilizei o IReport) dos dados ordenados no meu jtable. Então eu preciso passar esse parâmetro na hora que eu for mandar gerar.

Se minha dúvida for caso de abrir um novo tópico me avise por favor. Eu ainda não sei mto bem onde colocar minhas dúvidas.

Obrigado desde já.

V

Quanto à abrir ou não um tópico. Seu assunto se refere ao meu TableFilter, então, é por aqui mesmo que eu respondo. É que o povo vem pegar carona para coisas de JTable que não tem nada a ver com o tópico original.

Sim, existe o método getFilteredRows(). Ele retorna uma lista com os índices que sobraram após o filtro, na ordem que sobraram. Aí basta pedir esses índices ao model.

C

Entendi Vini. Mas o metodo get do tableModel só aceita 1 integer como parâmetro. Como eu vou passar uma lista para ele?
Eu verifiquei os outros métodos e não consegui identificar nenhum que receba a lista dos índices e me devolva a lista com o objeto.

Eu tentei assim.

List<Comunicacao> lista = tableModel.get(tableFilter.getFilteredRows());

Vc pode me exemplificar fazendo favor. É erro de iniciante, mas logo eu chego lá.

Obrigado.

V

Tem que fazer um foreach mesmo e montar outra lista. Mas tem razão, seria interessante ter esse método já direto no TableFilter.

List&lt;Comunicacao&gt; lista = new ArrayList&lt;Comunicacao&gt;(); for (Integer index : tableFilter.getFilteredRows()) { lista.add(tableModel.get(index.intValue()); }

C

Obrigado Vini, funcionou perfeitamente.

C

Olá Vini.

Desculpa encher o saco novamente, mas como estou utilizando seu modelo em um projeto aqui na empresa, estou propenso a dúvidas.

Bom, eu gostaria de saber se no filtro tem alguma configuração diferente para dados do tipo inteiro ??

Pois tive um problema quando mandei ordenar tanto de forma crescente como decrescente.
O filtro ordenou, mas ele ordenou de acordo com o elemento da esquerda e não pelo número ser maior ou menor que o outro.

Ex.:

8
7
5
33
2
18

Quando os números tem apenas uma casa decimal ele ordena perfeitamente, mas quando tem duas ou mais acontece isso.
Se vc quiser até te mando um print do problema. Eu tentei colocar o print aqui mas não consegui.

Obrigado.

I

Ola!

Só uma perguntinha simples, existe um método que permita só o personalizar do seu TableFilter (que não permita ordenar) é que tenho uma coluna Documento que seria bom permitir que o usuário filtrasse por documento

caso não aja poderias me dar uma dica de como criar um método que faça isso no seu TableFilter

caceres dando um palpite no seu problema. Ele deve ta acontesendo porque a Class da coluna deve estar como String e NÃO Integer
deve ser isso mais só foi chute!

até!

V

Isso não tem, e não é muito trivial de implementar. Mas qual é o problema de deixar ele também ordenar por documento? O filtro e a ordenação são operações separadas.

C

É isso Vini?

Na verdade meu javabean que se relaciona com a classe Columns esta correto (string onde é string e int onde é int).

No aguardo.
Obrigado.

V

Como está o seu TableModel (ou seus Columns)? É ele que indica como as colunas devem ser ordenadas.
E tem sim, um tratamento especial para inteiros.

C

Não não tem. Era isso q eu gostaria de saber. Sobre esse tratamento.

Segue minha classe:

public enum ComunicacaoColumns implements Column<Comunicacao_Dias> 
{
        CARRO("Carro") 
        {  
            //Esse método precisa retornar para o table o ID da pessoa  
            public Object getValue(Comunicacao_Dias p)  
            {  
                return p.getCarro();  
            }          
        },   
        COMUNICACAO_ANTERIOR("Comunicação Anterior") 
        {  
           public Object getValue(Comunicacao_Dias p)  
           {  
               return p.getComunicacao_anterior();  
           }          
        },   
        
       ULTIMA_COMUNICACAO("Última Comunicação")  
       {  
           public Object getValue(Comunicacao_Dias p)  
           {  
               return p.getUltima_comunicacao();  
           }          
       },
       
       DIAS("Dias")
       {
       	public Object getValue(Comunicacao_Dias p)
       	{
       		return p.getDias();
       	}
       };
     
      //Daqui para baixo, são configurações que valem para todas as colunas  

    private final String nome;  
     
	private ComunicacaoColumns(String nome) 
	{  
		this.nome = nome;  
	}  
     
	public Class< ? > getColumnClass() 
	{  
		return Object.class;  
	}  
	 
	public String getName() 
	{  
		return nome;  
	}  
	 
	public TableCellRenderer getRenderer() 
	{  
		return null;  
	}  
	 
	public int getModelIndex() 
	{  
		return ordinal();  
	}  
	
	public int getWidth() 
	{  
		return 100;  
	}

Como seria um exemplo desse tratamento?

Criar um outro construtor recebendo parâmetro do tipo int e retornando?
Como seria chamado isso dentro da classe?

Obrigado.

V

O seu getColumnClass() está sempre retornando Object.class.

Você deve fazer retornar Integer.class para as colunas inteiras. Veja com a coluna Dias:

public enum ComunicacaoColumns implements Column&lt;Comunicacao_Dias&gt; 
{
   CARRO("Carro") {  
      //Esse método precisa retornar para o table o ID da pessoa  
      public Object getValue(Comunicacao_Dias p)  {  
         return p.getCarro();  
      }          
   },   
   COMUNICACAO_ANTERIOR("Comunicação Anterior") {  
      public Object getValue(Comunicacao_Dias p) {  
         return p.getComunicacao_anterior();  
      }          
   },          
   ULTIMA_COMUNICACAO("Última Comunicação")  {  
      public Object getValue(Comunicacao_Dias p)  {  
         return p.getUltima_comunicacao();  
      }          
   },       
   DIAS("Dias") {
      public Object getValue(Comunicacao_Dias p) {
         return p.getDias();
      }

      public Class&lt; ? &gt; getColumnClass() {  
		return Integer.class;  
      }  
   };
     
   //Daqui para baixo, são configurações que valem para todas as colunas  

   private final String nome;  
     
   private ComunicacaoColumns(String nome)  {  
      this.nome = nome;  
   }  
     
   public Class&lt; ? &gt; getColumnClass() {  
      return Object.class;  
   }  
	 
   public String getName() {  
      return nome;  
   }  
	 
   public TableCellRenderer getRenderer() {  
      return null;  
   }  
	 
   public int getModelIndex() {  
      return ordinal();  
   }  
	
   public int getWidth() {  
      return 100;  
   }
}
C

Era isso mesmo. O engraçado é que os dados dessa coluna agora ficaram alinhados para a direta (ao contrario de quando estava retornando do tipo String). E ao contrário das outras colunas.

É assim mesmo? Existe algum método que alinha isso centralizado por exemplo, ou isso ja faz parte do layout do table e é outra história?

Muito obrigado, e é só isso.

Abraço.

V

Isso depende é do renderer da coluna. Por padrão ele usa o DefaultRenderer que alinha números a direita, e demais dados a esquerda.

I

ViniGodoy:
Como está o seu TableModel (ou seus Columns)? É ele que indica como as colunas devem ser ordenadas.
E tem sim, um tratamento especial para inteiros.

o problema não é como é ordenado o problema é que eu não quero que ordene olhe a imagem da minha JTable para entenderem melhor o que eu quero


porque pelo menos ao meu ver poder ordenar uma coluna de documento ou telefone fica esquisito mais se o usuário querer pegar todos os telefones que tenha o mesmo código de área ou se lembrar de parte do documento o personalizar seria ótimo

V

Então, como eu falei, esse suporte ele não dá.

Você tem a opção de desabilitar totalmente o filtro, mas eu deixaria a possibilidade de ordenação. Fica meio ridículo, mas é um preço muito pequeno a se pagar por uma funcionalidade tão bacana.
E vai saber, as vezes seu usuário vai querer listar todos os números ordenados por código de área…

J

Vini parabéns pelo post… Me poupou um tempão! :shock:
Ficou muito bom esse seu AutoFiltro e o table model!

Vou começar a estudar o projeto do mark agora e talvez implementá-lo no meu projeto. :wink:
Parece ser um pouco mais interessante por trabalhar com anotações. Tenho tabelas do banco com praticamente 50 ou mais colunas.
É um pouco doloroso escrever enums para tabelas grandes assim. :shock:
Mas ainda assim é bem melhor que trabalhar com DefaultTableModel e de quebra tem o auto filtro que é muito bom! :wink:

V

Sim. E o auto-filtro funciona com qualquer TableModel. Incluindo o (argh) Default e o do Mark. :slight_smile:

J

Realmente o modelo do Mark é bem mais interessante! Dispensa comentários! :wink:
Vini, o auto filtro realmente funfa de boa com o modelo do Mark. Vcs estão de parabéns…
Nem gosto de imaginar se tivesse que construir isso do zero… :shock:

Obrigado.

M

Hehe, fizemos um bom trabalho juntos(na realidade foi separado, mas os dois são tão independentes que funcionam bem juntos, ironico não?) :stuck_out_tongue:

Obrigado aos comentários também.

J

Marky.Vasconcelos:
Hehe, fizemos um bom trabalho juntos(na realidade foi separado, mas os dois são tão independentes que funcionam bem juntos, ironico não?) :stuck_out_tongue:

Obrigado aos comentários também.

Sim, é irônico…
Mark, você não pensa em implementar o auto filtro direto no seu projeto não? Seria uma boa :?:

Baixei os fontes do seu projeto e estou estudando-os.

Mais uma vez… valeu pela força.

M

Sim, pretendo colocar o auto-filtro no meu projeto, só estou procurando tempo para fazer essas coisas.

J

Mark,
Como vc trata os dados do tipo Double para ficarem formatados com as casas decimais e tal e alinhar o texto a direita?

No meu caso, os campos na classe POJO estão declarados como BigDecimal, mas preciso mostrá-los como double porque como BigDecimal os números ficam sem formatação
e quando o número é 0 ele mostra como 0E-9...

import java.text.DecimalFormat;
import mark.utils.bean.Formatter;

/**
 *
 * @author jsilva
 */
public class DoubleFormatter implements Formatter{
    DecimalFormat formatter = new DecimalFormat();
    public Object format(Object o) {
        String valor = formatter.format(o);
        return valor;
    }

    public Object parse(Object o) {
        return Double.parseDouble(o.toString());
    }

    public String getName() {
        return "double";
    }

}

Essa é a classe que fiz para formatar o valor, mas como ele retorna uma String os valores ficam alinhados a esquerda!
Como vc faz pra informar que a classe de uma determinada coluna é um Double ou outro tipo qualquer?

M

Depende do que voce quer fazer, mostrar um double na tabela não vai resolver seu problema, se voce quiser formatado voce pode usar o DecimalFormatter e converter para String mesmo.

Só algo importante, o método format deve declarar o retorno do mesmo tipo que voce quer exibir na coluna, nos eu caso seria mais ou menos o seguinte:

import java.text.DecimalFormat;
import mark.utils.bean.Formatter;

/**
 *
 * @author jsilva
 */
public class DoubleFormatter implements Formatter{
    DecimalFormat formatter = new DecimalFormat("##,##");
    public String format(Object o) {
        String valor = formatter.format(o);
        return valor;
    }

    public Object parse(Object o) {
        return Double.parseDouble(o.toString());
    }

    public String getName() {
        return "double";
    }

}
J

Tá, no format não declarei o retorno do que quero exibir porque não quero limitar as casas, assim como tá ele faz o que quero que é colocar o separador de milhares e só.

Mas na verdade, o que quero é especificar o tipo de classe de uma determinada coluna, por exemplo com uma anotação “columnType” onde eu informe o tipo de classe
a ser utilizada para determinada coluna.

Não posso utilizar uma Double direto porque preciso do tipo como BigDecimal, os campos têm muitas casas decimais e não posso perder a precisão deles.

Mas voltando… é basicamente isso, pelo que percebi, vc utiliza o tipo declarado na variável para definir o tipo de classe a ser utilizado na coluna.
O que quero é poder mudar o tipo manualmente.

É possível fazer isso com o seu model?

M

Ai que está o segredo, o tipo da coluna é exatemente o que voce coloca na assinatura do Formatter.

public String format(Object o) {

Será String.

public boolean format(Object o) {

Será Boolean, o wraper, por que modifiquei para utilizar apenas os wrapers como class.

E assim vai, voce pode colocar qualquer objeto, desde que tenha um Renderer apropriado.

J

Marky.Vasconcelos:
Ai que está o segredo, o tipo da coluna é exatemente o que voce coloca na assinatura do Formatter.

public String format(Object o) {

Será String.

public boolean format(Object o) {

Será Boolean, o wraper, por que modifiquei para utilizar apenas os wrapers como class.

E assim vai, voce pode colocar qualquer objeto, desde que tenha um Renderer apropriado.

Você é o cara!! :smiley:
Nem pensei nisso… :shock:

Eu já estava aqui fuçando no source e implementando uma anotação “columnType”… :?

Valeu Mark…

M

Eu também tinha pensado no columnType, mas ia ser meio idiota ficar declarando nas annotations esse tipo, ainda mais que em um caso voce pode querer mostrar como String e outro como double, e isso não seria resolvido com a annotation.

Só se lembre, o método parse recebe um objeto do mesmo tipo que o format retorna.

J

Marky.Vasconcelos:
Eu também tinha pensado no columnType, mas ia ser meio idiota ficar declarando nas annotations esse tipo, ainda mais que em um caso voce pode querer mostrar como String e outro como double, e isso não seria resolvido com a annotation.

Só se lembre, o método parse recebe um objeto do mesmo tipo que o format retorna.

É verdade, a solução do Formatter foi bem mais inteligente, ficou realmente muito bom.
Parabéns pelo trabalho.

C

Boa noite a todos.

Vini, eu me deparei com a seguinte situação. Quando eu mando filtrar os dados do table eu faço um FOR EACH e pego a lista de dados na ordem em que foram filtrados ou ordenados, até ai normal.
Mas e quando eu não tenho todos os atributos da minha classe de negócio no meu table. Nesse caso, minha classe de negócio (lista) tem 8 atributos, e fica inviável representar todos no table, então eu só exibo 3 atributos. A questão é: existe a possibilidade de quando ordenado esses 3 atributos no meu table, ordenar juntamente minha lista com todos os 8 atributos?

Desde já agradeço a atenção.

Obrigado.

V

O auto-filtro ordena apenas a visualização.

O máximo que ele fornece é um método que te retorna o índice de todos os índices do model, na ordem que aparecem na view. Com esse método você pode todos os objetos, com todos os campos deles (sendo mostrados ou não) na ordem que o usuário deixou.

C

Ah ta, entendi… valew então…
Obrigado.

F

Olá, aproveitando o gancho, gostaria de saber se através deste projeto, tem como que definir o tamanha das colunas da tabela?

Grato,

C

Resolvido… Vlw a inspiração…

C

Bom dia a todos.

Vini ou Marky, eu gostaria de uma opinião de vcs.

Eu precisava formatar a data apresentada no table (utilizando o model do Vini - com AutoFiltro), daí eu fiz da seguinte forma.

No ENUM que eu defino as colunas do meu table

DATA_PROCESSAMENTO("Data Processamento")  
	   {  
	       public Object getValue(PowerUP p)  
	       {  
	           return new DataString().formataData(p.getData_processamento());  // chamo a classe para formatar...
	       }
	   };

Classe que formata a data

public class DataString {
	private final DateFormat FORMATAR = new SimpleDateFormat("dd/MM/yyyy");
	
	public Object formataData(Object date){
		return FORMATAR.format(date);
	}
}

É uma boa prática da forma que eu desenvolvi? Funcionou corretamente, mas eu me preocupo em não fazer gambiarras.

Vlw

R
Olá, estou utilizando o ObjectTableModel do marky com o TableFilter do Vini, estou trabalhando com uma tela única para realizar as pesquisas, para isto estou criando/configurando os models desta forma:
public static TableFilter modelCidade(JTable table){
        AnnotationResolver resolver = new AnnotationResolver(Cidade.class);
        cidadeModel = new ObjectTableModel&lt;Cidade&gt;(
                resolver, "nomeCidade,nomeEstado,paisEstado");
        filterCidade = new TableFilter(table.getTableHeader(),
                cidadeModel);
         return filterCidade;
}

public static TableFilter modelContato(JTable table){
        AnnotationResolver resolver = new AnnotationResolver(Contato.class);
        contatoModel = new ObjectTableModel&lt;Contato&gt;(
                resolver, "nomeContato,emailContato,telefoneContato,nomePessoa");
        filterContato = new TableFilter(table.getTableHeader(),
                contatoModel);
         return filterContato;
}
Na minha tela de pesquisa eu crio uma única instância da JTable:
public JTable table = new JTable();
Quando seleciono o cadastro que desejo pesquisar (faço isso em um JComboBox) a tela atualiza as colunas conforme o model selecionado, o código responsável por isso é o seguinte:
public void setTipoPesquisa() {
        codigoSelecionado = -1;
        jcbTipoPesquisa.setSelectedItem(cadastroPesquisa);        
        if (cadastroPesquisa.equals(BD.EstruturaBanco.CIDADE)) {            
            table.setModel(telasPesquisa.TableModels.modelCidade(table));
        } else if (cadastroPesquisa.equals(BD.EstruturaBanco.CONTATO)) {
            table.setModel(telasPesquisa.TableModels.modelContato(table));
        }
        this.setTitle("Pesquisa de " + cadastroPesquisa);
        jbTodos.setToolTipText("Pesquisar por todos os registros de " + cadastroPesquisa);
        Resizer.fitAllColumns(table);
}
[img]http://images.orkut.com/orkut/photos/OgAAABRPIdFqChFMOZQy67N3dt9kSgOGzS9BH98251_uZ9cu0DqSzomY568vxgfzwzTP7Q3TIhOVptooQPEDOjNr778Am1T1UC9WM1qVG2hJlnd1KDZ1NhwijvmN.jpg[/img]

Más estou com um problema, está dando um erro no ArrayList quando faço a troca do model com 3 colunas para o de 4 colunas,
imagino que eu saiba o por que do erro, más não sei como corregi-lo, alguém pode me ajudar?

PS.: Quando troco de um model com 3 colunas para outro com o mesmo numero de colunas não ocorre erro.

segue o erro:
Exception occurred during event dispatching:
java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
        at java.util.ArrayList.RangeCheck(ArrayList.java:547)
        at java.util.ArrayList.get(ArrayList.java:322)
C

Vc tem que verificar se esta correto essa troca de model’s (3 colunas por 4), pois esse log de erro eh justamente a tentativa de acesso de uma posição inválida na lista. Eu não sei como vc esta chamando na view, e pelo q eu entendi o usuário pode trocar de model conforme ele queira. Será que vc não tem q remover o model anterior antes de adicionar o novo? Eu não tenho certeza, mas talvez ele esta tentando colocar um model “em cima” do outro. Não conheço o model do Mark, pois eu uso o do Viny, mas ta uma idéia pra vc.

R

então caceres, justamente isso que eu não sei como fazer,
já tinha pesquisado sobre o erro, e você está certo, más justamente isso que eu disse, não sei como fazer isso,
tem alguma forma de remover o model?
tentei fazer uma remoção das colunas, mas da forma que eu fiz, o erro persiste.

R

alguém? :cry:

M

Cara, nunca vi esse erro acontecer nessas circunstancias. Será que não é nenhum problema ao carregar seus dados?

Como teste, troque de um model para outro vazio e veja se ocorre o problema.

R

marky, o pior é que já fiz isso,
e também quando troco de um model com mais colunas que o que vou adicionar não da erro algum,
somente da esse erro quando troco de um model menor para um maior… =[

R

na verdade nem carrego dados na tabela quando seto o model,
só irão ser adicionados valores (linhas) a tabela depois de digitar
alguma coisa no field ou clicar no botao pesquisar todos.

R

como o erro persiste depois de muitas tentativas de correção resolvi postar o erro completo,
para que assim talvez vocês possa me ajudar… desconfio que seja algo com o tablefilter,
algo que eu esteja fazendo de forma errónea?

Exception occurred during event dispatching: java.lang.IndexOutOfBoundsException: Index: 3, Size: 3 at java.util.ArrayList.RangeCheck(ArrayList.java:547) at java.util.ArrayList.get(ArrayList.java:322) at Testes.Table.util.gui.table.headerPopup.TableHeaderPopup.getPopup(TableHeaderPopup.java:199) at Testes.Table.util.gui.table.TableFilter.refreshHeader(TableFilter.java:151) at Testes.Table.util.gui.table.TableFilter.access$100(TableFilter.java:35) at Testes.Table.util.gui.table.TableFilter$3.columnAdded(TableFilter.java:139) at javax.swing.table.DefaultTableColumnModel.fireColumnAdded(DefaultTableColumnModel.java:516) at javax.swing.table.DefaultTableColumnModel.addColumn(DefaultTableColumnModel.java:108) at javax.swing.JTable.addColumn(JTable.java:2772) at javax.swing.JTable.createDefaultColumnsFromModel(JTable.java:1263) at javax.swing.JTable.tableChanged(JTable.java:4373) at javax.swing.JTable.setModel(JTable.java:3675) at Testes.TelaPesquisa.setTipoPesquisa(TelaPesquisa.java:219) at Testes.TelaPesquisa$1.actionPerformed(TelaPesquisa.java:137) at javax.swing.JComboBox.fireActionEvent(JComboBox.java:1240) at javax.swing.JComboBox.setSelectedItem(JComboBox.java:567) at javax.swing.JComboBox.setSelectedIndex(JComboBox.java:603) at javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased(BasicComboPopup.java:817) at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:273) at java.awt.Component.processMouseEvent(Component.java:6263) at javax.swing.JComponent.processMouseEvent(JComponent.java:3267) at javax.swing.plaf.basic.BasicComboPopup$1.processMouseEvent(BasicComboPopup.java:481) at java.awt.Component.processEvent(Component.java:6028) at java.awt.Container.processEvent(Container.java:2041) at java.awt.Component.dispatchEventImpl(Component.java:4630) at java.awt.Container.dispatchEventImpl(Container.java:2099) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168) at java.awt.Container.dispatchEventImpl(Container.java:2085) at java.awt.Window.dispatchEventImpl(Window.java:2478) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:178) at java.awt.Dialog$1.run(Dialog.java:1046) at java.awt.Dialog$3.run(Dialog.java:1098) at java.security.AccessController.doPrivileged(Native Method) at java.awt.Dialog.show(Dialog.java:1096) at java.awt.Component.show(Component.java:1563) at java.awt.Component.setVisible(Component.java:1515) at java.awt.Window.setVisible(Window.java:842) at java.awt.Dialog.setVisible(Dialog.java:986) at Testes.TelaPesquisa.&lt;init&gt;(TelaPesquisa.java:91) at Testes.TelaPesquisa.abreTela(TelaPesquisa.java:284) at asf_automation_system_farms.TelaPrincipal.actionPerformed(TelaPrincipal.java:135) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242) at javax.swing.AbstractButton.doClick(AbstractButton.java:357) at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1223) at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1264) at java.awt.Component.processMouseEvent(Component.java:6263) at javax.swing.JComponent.processMouseEvent(JComponent.java:3267) at java.awt.Component.processEvent(Component.java:6028) at java.awt.Container.processEvent(Container.java:2041) at java.awt.Component.dispatchEventImpl(Component.java:4630) at java.awt.Container.dispatchEventImpl(Container.java:2099) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168) at java.awt.Container.dispatchEventImpl(Container.java:2085) at java.awt.Window.dispatchEventImpl(Window.java:2478) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

T

Primeiro parabéns por esse projeto, muito interessante o ObjectTableModel e o Auto-Filtro, eu inclusive havia criado um modelo de tabela chamado de ObjectTableModel por não conhecer esse… :oops:

Só teve uma coisa que eu não gostei no auto-filtro, quando é usado algum look and feel que tem borda em labels, como o Nimbus por exemplo, o header fica meio estranho, parecendo que tem borda só no label…

Pra deixar mais bonito, em vez de colocar um JToggleButton na classe TableHeaderPopup, eu adicionei um icone no label.
Acho que o ideal é o botão, mas eu não consegui resolver isso usando um botão :cry:

Se resolver lançar uma nova versão e tiver tempo, da uma olhada nisso :lol:

E pra quem está tendo o mesmo “problema” que eu segue o que eu alterei.

panel.add(label, gridBagConstraints);
            label.setHorizontalTextPosition(JLabel.LEFT);
            ImageIcon icon = null;
            
            if (modified.get(modelIndex) == null || !modified.get(modelIndex))
            	icon = new ImageIcon(getClass().getResource(
                  "/res/gui/down.gif"));
            else
            	icon = new ImageIcon(getClass().getResource(
                  "/res/gui/down_red.gif"));
            FontMetrics fm = table.getFontMetrics(table.getFont());
            label.setIconTextGap(table.getColumnModel().getColumn(column).getWidth() - (fm.stringWidth(label.getText()) + 20));
            label.setIcon(icon);
            
//            JToggleButton button = new JToggleButton();

//            if (modified.get(modelIndex) == null || !modified.get(modelIndex))
//                button.setIcon(new ImageIcon(getClass().getResource(
//                        "/res/gui/down.gif")));
//            else
//                button.setIcon(new ImageIcon(getClass().getResource(
//                        "/res/gui/down_red.gif")));
//
//            button.setPreferredSize(new Dimension(16, 16));
//            button.setMaximumSize(new Dimension(16, 16));
//            button.setMinimumSize(new Dimension(16, 16));
//            button.setFocusable(false);
//            button.setSelected(column == selected);

//            panel.add(button, new GridBagConstraints());
//
//            Border border = label.getBorder();//UIManager.getBorder("TableHeader.cellBorder");
//            	//border.getBorderInsets(c).set(0, 2, 1, 1);
//            panel.setBorder(border);
//            label.setBorder(null);
//            //jLA
           

            return label;

E mais uma vez, parabéns pelo projeto :smiley:

R

Cara muito bacana o Auto-Filtro mas eu quero saber se tem como eu adicionar um novo filtro tipo onde eu escolha de tal dia até tal dia e ele deixe no grid apenas os registros pertencentes periodo, queria saber se é possivel implementar isso na classe TableFilter se sim deem uma dica to perdido aqui.

J

Marky.Vasconcelos,

Estava tentando utilizar a sua classe
http://code.google.com/p/markutils/source/browse/trunk/src/mark/utils/swing/table/Resizer.java
para ajustar a largura da coluna conforme o conteúdo carregado no model, mas não funcionou aqui.

Fiz algumas mudanças, mas apenas para conteúdo onde é String. Segue o código abaixo.

import javax.swing.JTable;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

public class Resizer {
	
	private static final int STRING_WIDTH = 6;
	/**
	 * Método que ajuasta a coluna conforme da JTable conforme o tamanho do
	 * conteúdo carregado no model
	 * 
	 * @param coluna
	 *            Recebe a coluna que sera redimensionada
	 * @param margin
	 *            espaço de bonus colocado caso a contagem dos campos esteja
	 *            errada
	 * @param tabela
	 *            tabela que será implementada o redimensionamento
	 */

	public static void fitColumn(int coluna, JTable tabela) {
		TableColumnModel colModel = tabela.getColumnModel();
		TableColumn col = colModel.getColumn(coluna);
		TableModel model = tabela.getModel();
		int chars = 0;
		for (int i = 0; i &lt; model.getRowCount(); i++) {
			Object value = tabela.getValueAt(i, coluna);
			if (value instanceof String) {
				String text = (String) value;
				if (text.length() &gt; chars) {
					chars = text.length();
				}
			}
		}
		col.setMinWidth(chars * STRING_WIDTH);
	}

	public static void fitAllColumns(JTable table) {
		TableColumnModel colModel = table.getColumnModel();
		for (int i = 0; i &lt; colModel.getColumnCount(); i++)
			fitColumn(i, table);
	}
}
I

jean.zunino
Isso era um probleminha conhecido que ficou de ser visto nas futuras revisões.

W

javer:
Na verdade tenho mais uma pergunta.

Onde eu trato a formatação do dado adicionado naquele popUP da coluna, na imagem tem uma coluna do tipo Date que quero mostrar a data no formato: dd/MM/yyyy

Eu (ainda) não consegui localizar nos código onde está sendo feito isso, e também como converter de volta quando for selecionado pelo usuário para atualizar o filtro.

A

Gostaria de parabenizar ao Vini Godoy pela iniciativa de criar o Table Filter.
Estou utilizando em minha aplicação e tem me ajudado bastante.
Porém, estou com uma dúvida, estou querendo alterar a descrição do Pop Up dos filtros para português PT -BR.
Dei uma olhada na api e não encontrei como faz isto…

Criado 22 de agosto de 2008
Ultima resposta 19 de ago. de 2013
Respostas 118
Participantes 22