Java Standard Edition (Java SE) 6.0 (chamado Mustang), adiciona algumas características que possibilitam fazer a ordenação e a filtragem de dados em um JTable de forma mais simples. Algumas tabelas mais modernas permitem ao usuário fazer a ordenação da coluna apenas clicando no cabeçalho desta tabela. Isto pode ser feito com o JTable. Porém esta funcionalidade(ordenar a coluna) teve que ser implementada manualmente para cada tabela que precisasse desta característica. Com o Mustang, este trabalho é reduzido. Filtrar é outra opção geralmente disponível nas interfaces do usuário. Filtrar os dados, permite aos usuários exibir somente as filas de uma tabela que sejam necessárias ao usuário. Com o Mustang, o processo de filtragem também é facilitado.
Ordenando as linhas de uma tabela
A base da ordenação e filtragem de linhas no Mustang é a classe abstrata RowSorter. RowSorter mantém o mapeamento de linhas em um JTable para os elementos do modelo subjacente. Isto permite fazer a ordenação e a filtragem. A classe é genérica o sufiente para trabalhar com TableModel e ListModel. Porém, somente a classe TableRowSorter pode ser utilizada quando estamos utilizando o JTable.
No caso mais simples, você passa o TableModel ao constructor de TableRowSorter, e então passa o RowSorter criado no método setRowSorter() de JTable. O código abaixo é um programa de exemplo, que demonstra a ordenação em uma tabela:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
public class SortTable {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Ordenando um JTable");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Object rows[][] = {
{"AMZN", "Amazon", 41.28},
{"EBAY", "eBay", 41.57},
{"GOOG", "Google", 388.33},
{"MSFT", "Microsoft", 26.56},
{"NOK", "Nokia Corp", 17.13},
{"ORCL", "Oracle Corp.", 12.52},
{"SUNW", "Sun Microsystems", 3.86},
{"TWX", "Time Warner", 17.66},
{"VOD", "Vodafone Group", 26.02},
{"YHOO", "Yahoo!", 37.69}
};
String columns[] = {"Sigla", "Nome", "Preço"};
TableModel model =
new DefaultTableModel(rows, columns) {
public Class getColumnClass(int column) {
Class returnValue;
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
returnValue = Object.class;
}
return returnValue;
}
};
JTable table = new JTable(model);
RowSorter<TableModel> sorter =
new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
JScrollPane pane = new JScrollPane(table);
frame.add(pane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
Clique em uma das colunas da tabela exibida, e note que seu conteúdo é reordenado.
Estas são as três linhas responsáveis pela ordenação, fundamentais no programa apresentado anteriormente:
JTable table = new JTable(model);
RowSorter<TableModel> sorter =
new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
A primeira linha associa o modelo com a tabela. A segunda linha cria um modelo específico de RowSorter. A terceira linha associa o RowSorter com o JTable. Isto permite a um usuário clicar sobre o cabeçalho da coluna para que esta seja ordenada. Clicar uma segunda vez na mesma coluna inverte a ordem da ordenação.
Se você quiser adicionar sua própria ação quando for feita a ordenação, você pode ligar o RowSorterListener ao RowSorter. A interface tem um método que permite isso:
void sorterChanged(RowSorterEvent e)
O método permite que você atualize o texto na barra de status, ou executa alguma tarefa adicional. O RowSorterEvent permite que você descubra quantas linhas estavam presentes antes da sorte, caso o RowSorter filtrar linhas.
Filtrando as linhas da tabela
Você pode associar um RowFilter com o TableRowSorter e usá-lo para filtrar os índices de uma tabela. Por exemplo, você pode usar o RowFilter de forma que uma tabela indica somente as linhas onde o nome começa com a letra A, ou onde o preço conservado em estoque é maior que $50. A classe abstrata RowFilter tem um método que é usado para filtragem:
boolean include(RowFilter.Entry entry)
Para cada entrada no modelo associado com o RowSorter, o método indica se a entrada especificada deve ser mostrada na vista atual do modelo. Em muitos casos, você não necessita criar sua própria execução de RowFilter. O RowFilter ja oferece seis métodos estáticos para criar filtros.
andFilter(Iterable<? extends RowFilter<? super M,? super I>> filters)
dateFilter(RowFilter.ComparisonType type, Date date, int... indices)
notFilter(RowFilter<M,I> filter)
numberFilter(RowFilter.ComparisonType type, Number number, int... indices)
orFilter(Iterable<? extends RowFilter<? super M,? super I>> filters)
regexFilter(String regex, int... indices)
Para o RowFilter, somente o conjunto das colunas que correspondem aos índices especificados é verificado dentro o modelo. Se nenhum índice for especificado, todas as colunas serao verificadas para ver se há algum elemento em comum.
O dateFilter permite que você verifique se há datas iguais. O numberFilter checa se existem numeros em comum. O notFilter é usado invertendo um outro filtro, ou seja inclui as entradas que o filtro fornecido desprezou. Você pode usá-lo para fazer coisas como por exemplo: encontrar as informações que não foram geradas em 12/25/2005. O andFilter e o orFilter (filtros logicos) podem ser utilizados para combinar um ou mais filtros. O regexFilter usa uma expressão regular para fazer a filtragem. Abaixo esta um programa chamado FilterTable que usa um regexFilter para filtrar o índice da tabela:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.regex.*;
public class FilterTable {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Ordenando JTable");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Object rows[][] = {
{"AMZN", "Amazon", 41.28},
{"EBAY", "eBay", 41.57},
{"GOOG", "Google", 388.33},
{"MSFT", "Microsoft", 26.56},
{"NOK", "Nokia Corp", 17.13},
{"ORCL", "Oracle Corp.", 12.52},
{"SUNW", "Sun Microsystems", 3.86},
{"TWX", "Time Warner", 17.66},
{"VOD", "Vodafone Group", 26.02},
{"YHOO", "Yahoo!", 37.69}
};
Object columns[] = {"Sigra", "Nome", "Preco"};
TableModel model =
new DefaultTableModel(rows, columns) {
public Class getColumnClass(int column) {
Class returnValue;
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
returnValue = Object.class;
}
return returnValue;
}
};
JTable table = new JTable(model);
final TableRowSorter<TableModel> sorter =
new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
JScrollPane pane = new JScrollPane(table);
frame.add(pane, BorderLayout.CENTER);
JPanel panel = new JPanel(new BorderLayout());
JLabel label = new JLabel("Filtro");
panel.add(label, BorderLayout.WEST);
final JTextField filterText =
new JTextField("SUN");
panel.add(filterText, BorderLayout.CENTER);
frame.add(panel, BorderLayout.NORTH);
JButton button = new JButton("Filtro");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String text = filterText.getText();
if (text.length() == 0) {
sorter.setRowFilter(null);
} else {
try {
sorter.setRowFilter(
RowFilter.regexFilter(text));
} catch (PatternSyntaxException pse) {
System.err.println("Erro");
}
}
}
});
frame.add(button, BorderLayout.SOUTH);
frame.setSize(300, 250);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
A figura abaixo apresenta a execução do código apresentado acima. Neste exemplo faremos uma filtragem, fazendo com que apareça apenas siglas que contenham a palavra SUN.
Apos a filtragem ser feita, serah apresentado apenas uma linha da tabela. Isso pode ser visto na figura abaixo.
Mude o texto do filtro para mudar o conjunto de linhas mostradas na tabela. Se você quiser ver todas as linhas na tabela, remova o texto do filtro.