Você está na página 1de 9

Tutorial sobre JTable do Swing - parte I

Tutorial do JTable do Swing Com esse tutorial voce aprender a criar desde uma JTable simples, at uma complexa, utilizando as princpais classes ( editor, renderer, model, etc ). Este tutorial estar subdividindo em diversos capitlos, aumentando sua complexidade a medida que entrarmos em um novo captulo.CAPITULO 1 - Construindo uma JTable Simples Introduo: A classe JTable utilizada para vizualizar dados em grid no Swing e um dos componentes mais complexos desse pacote. Alias o JTable possui at um pacote especial, que contm diversas classes para sua utilizao: javax.swing.table. A JTable um componente MVC: o seu trabalho dividido em 3 partes: Model: a parte que cuida dos dados, quem controla e distribui os dados na jtable. implementado pela interface TableModel ( AbstractTableModel e DefaultTableModel ). Ela responsavel por fornecedor os dados para a tabela, a qual requisitar os dados atraves do mtodo getValueAt, informando a linha e a coluna. Este mtodo retorna um Object, ou seja, um objeto qualquer, que pode ser um Integer, uma String ou uma outra classe que voc tenha implementado. View: a parte que cuida da apresentao. implementado pela interface CellRenderer. como a apresentao dada celula a celula na tabela, o renderer deve ser fornecedido para uma celula especifica. Na Jtable possivel fornecer tanto um renderer para a tabela inteira como para uma coluna especifica. Assim como na tablemodel requisitar o valor na linha e coluna especifica, aqui ele requisitara o objeto que ira apresentar o dados, passando como parametro a linha, a coluna o valor (object), a tabela (jtable), se esta celula esta selecionada e se ela celula possui o foco. Este mtodo o getCellRendererComponent, que ir retornar um JComponent. O DefaultCellRenderer implementa o JLabel para apresentar os dados, que a forma de apresentao mais comum para um valor. Controller: a parte que controla a apresentao dos dados na view. a prpria JTable. Como a JTable ja vem implementada para usar os tipos defaults existentes e implementados, para criar uma jtable simples no to complicado. O unico problema que voce acaba se engessando quando precisar de algum recurso mais "completo". Criando uma JTable Vamos agora conhecer uma forma de contruir uma JTable, simplesmente fornecedor os dados que quero exibir nela.
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9.

String[] colunas = new String []{"Estado","Cidade"}; String[][] dados = new String [][] { {"SP","Sao Paulo"}, {"RJ","Rio de Janeiro"}, {"RN","Rio Grande do Norte"}, {"PR","Parana"} }; JTable jtable = new JTable(dados, colunas);

O exemplo acima cria uma instncia da classe JTable passando como argumentos as variveis dados e colunas. Existem diversos contrutores para a JTable, e um deles a passagem de arrays (linhas e colunas) como argumentos. Este o modo mais simples de fornecer JTable os dados que deseja exibir. Ela utliza toda a estrutura default para exibio deste codigo. Trabalhando com a JTable: DefaultTableModel() Tendo nossa JTable criada, podemos trabalhar em cima do modelo (TableModel) que ela criou. Para obtermos o modelo dessa JTable criada, basta chamarmos o mtodo getModel() que retorna uma instncia de classe que implementa o TableModel. Como o argumento para criao de nossa JTable foi uma coleo, o modelo utilizado internamente foi o DefaultTableModel. O DefaultTableModel uma classe de javax.swing.table e implementa a interface TableModel, fornecedo-nos todo o controle dos dados da JTable. Claro que uma classe com mtodos bsicos para trabalhar com os dados da JTable. - getValueAt():

obtem o valor de uma determinada linha e coluna na JTable. - setValueAt(): seta o valor em uma determinada linha e coluna na JTable. - addRow(): adiciona uma nova linha na JTable. Recebe um array simples. - addColumn(): adiciona uma nova coluna no modelo. Com base no exemplo anterior, digamos que seria necessario adicionar outras linhas apos a criao da nossa JTable. Vamos alterar nosso codigo para tirarmos o peso de controlar os dados da prpria JTable e jogar esse trabalho pro DefaultTableModel:
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.

String[][] dados = new String [][]{ {"SP","Sao Paulo"}, {"RJ","Rio de Janeiro"}, {"RN","Rio Grande do Norte"}, {"PR","Parana"} }; String[] colunas = new String []{"Estado","Cidade"}; // Ao inves de passar direto, colocamos os dados em um modelo DefaultTableModel modelo = new DefaultTableModel(dados, colunas); // e passamos o modelo para criar a jtable JTable jtable = new JTable( modelo );

O que fizemos foi pegar as colunas e os dados, e jog-los em algum para cuidar deles: no caso um TableModel, que o responsavel por controlar os dados de uma JTable. Agora que criamos uma JTable passando um TableModel que controla os dados, podemos trabalhar em cima desse modelo. Uma coisa que devemos ter em mente sempre saber que modelo tal JTable est usando, pois assim podemos pega-lo de volta e trabalhar em cima dele. - addRow() Digamos que, na nossa tela, colocamos um novo boto para incluir novas linhas nessa minha JTable. E para tal, criamos o mtodo adicionaLinha(), chamado pelo ActionPerformed deste boto. Este mtodo ir obter o nosso modelo, quem controla os dados, e incluir uma nova linha em branco.
view plainprint?

1. /** 2. * Mtodo para adicionar uma nova linha na JTable 3. */ 4. public void adicionaLinha() { 5. // Obtem o modelo da JTable 6. DefaultTableModel modelo = (DefaultTableModel)getTabela().getModel(); 7. // Adiciona uma nova linha em branco no modelo 8. modelo.addRow( new String [] {"", ""} ); 9. }

- removeRow() A mesmo coisa poderia ser feito se quisermos deletar uma determinada linha. Digamos que vamos excluir a linha atualmente selecionada. Para saber qual linha est selecionada, devemos perguntar a JTable, que o controlador. O mtodo utilizado o getSelectedRow() e retorna um int, a linha selecionada. Se nao houver linhas selecionadas, o retorno -1.
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.

/** * Remove a linha do modelo. * @param linha */ public void removeLinha(int linha){ // Obtem o modelo da JTable DefaultTableModel modelo = (DefaultTableModel)getTabela().getModel(); // Remove a linha modelo.removeRow(linha);

13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34.

} /** * Obtem a linha selecionada e chama o mtodo para remover * do modelo */ public void removeLinha(){ // Obtem a linha selecionada na tabela e chama o mtodo // para excluir a linha int linhaSelecionada = getTabela().getSelectedRow(); // Verificamos se existe realmente alguma linha selecionada if( linhaSelecionada < 0 ){ return; }else{ // Remove a linha do modelo removeLinha(linhaSelecionada); }

- ListSeleciont Trabalhar com seleo de linhas e colunas na JTable tambem um trabalho a parte. Existem mtodos para obter nao s a linha, mas o numero de linhas selecionadas, as linhas selecionadas ( que retorna um array de int[] ). Assim como as linhas, os mesmos mtodos se encontram para obter as colunas seleciondas. Vale a pena dar uma olhada na API da JTable para conferir estes mtodos. Para setar o modo de seleo no qual sua JTable ir trabalahar, vamos permitir somente a seleo de linhas ( unicas ) e nao multiplas.
view plainprint?

1. .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

- getValueAt e setValueAt Em algum ponto de sua aplicao, voce pode querer substituir o contedo de uma celula, ou de vrias linhas em uma determinada coluna. Com os mtoso getValueAt e setValueAt podemos obter e setar o valor em uma determinada coluna e linha. Vamos criar um mtodo para subtituir um determinado valor por outro, em uma coluna especifica.
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20.

/** * Mtodo para subtituir um valor por outro em uma determinada * coluna. * @param oldValue * @param newValue * @param column * @return Numero de substituies */ public int substituirValor(String oldValue, String newValue, int column){ // Flag para saber se algum valor foi int total = 0; // Obtem o modelo da JTable DefaultTableModel modelo = (DefaultTableModel)getTabela().getModel(); // Faz um looping em cima das linhas do modelo for( int linha=0; linha<modelo.getRowCount(); linha++){ // Obtem o valor atual na coluna String valorAtual = (String)modelo.getValueAt(linha, column); if( valorAtual.equals(oldValue) ){ // Substitui pelo novo valor na linha e coluna modelo.setValueAt(newValue, linha, column);

21. 22. 23. 24. 25. 26. }

// Adiciona mais um no numero de linhas atualizadas total++; } } return total;

Poderiamos ter utilizado o Iterator para trabalhar em cima dos dados, basta obter o iterator do vetor de linhas dos dados retornado pelo modelo e obter os valor por meio de array de strings.
view plainprint?

1. Iterator i = modelo.getDataVector().iterator(); 2. String [] row = i.next();

Implementando meu prprio TableModel Para implementar o TableModel, existem diversos pontos que devemos cobrir - devemos tratar o controle dos dados ( colunas e linhas ). Uma opo simples para comearmos, ser a de estender a classe AbstractTableModel que fornece diversos mtodos j sobrescritos exceto aqueles que retornam dados: - public Object getValueAt( int row, int col ) - public int getRowCount() - public int getColumnCount() Esta classe tambm j implementa 7 mtodos de atualizao da JTable ( TableModelEvents ). Estes mtodos so utilizados para informar as alteraes ocorridas dentro de um modelo. Exemplo seria a incluso de uma nova linha, que dispara o mtodo fireTableRowsInserted. Durante a criao dos mtodos para trabalhar com os dados, iremos ver estes eventos. Mas este assunto vamos tratar na prxima parte do artigo. At l!

Tutorial sobre JTable - Parte 2: Implementando Seu Modelo


Tutorial sobre JTable - Parte 2: Implementando Seu Modelo Bem vindo parte 2 do tutorial sobre JTable. O primeiro artigo voce encontraclicando aqui.Nesta parte iremos criar o nosso prprio modelo de tabela e aprenderemos a trabalhar com ele.Implementado o TableModel No nosso primeiro tutorial foi dado uma pequena palinha de como uma implementao de um TableModel deve ser feita, utilizando a classe abstrata AbtractTableModel. Se no se lembra, a classe abstrata AbstractTableModel implementa diversas funcionalidades da TableModel: incluindo os eventos que disparam para a JTable alteraes ocorridas nos dados do modelo. Estes mtodos esto disponveis para uso nas subclasses, pois so mtodos internos do modelo. Agora, com relao aos mtodos que tratam os dados propriamente ditos, no implementado nenhum mtodo: isso significa que voc dever implementar do melhor jeito ( pelo menos que voc ache ) de armazenar os dados que sero exibidos pela JTable e que o modelo ir fornecer a ela. O modelo de dados funciona como um repositrio dos dados, portanto ele deve armazenar-los em algum lugar: nada melhor do que um array para armazenas o contedo das linhas. Agora, imagine que, em cada linha, podemos ter 2 colunas. Como armazenar 2 colunas dentro de um array? Podemos usar um array de String de tamanho 2, por exemplo. Ou at mesmo outro array do tipo java.util.List. Por ser um contedo dinmico ( que pode ser alterado em tempo de execuo: exemplo remover ou incluir novas linhas ) , nunca podemos saber o tamanho exato maximo que esse array dos dados ter. Por isso, o melhor jeito ter uma Collection para armazena-lo. Neste exemplo vamos usar a classe java.util.ArrayList para armazenar os dados da linha e um array de String para colunas. Primeiro, vamos criar a classe e suas variveis internas que iro guardar o dados do nosso modelo:
view plainprint?

1. public class SimpleTableModel extends AbstractTableModel{

2. 3. 4. 5. 6. 7. 8. 9. 10. }

private ArrayList linhas = null; private String [] colunas = null; public String[] getColunas() {return colunas;} public ArrayList getLinhas() {return linhas;} public void setColunas(String[] strings) {colunas = strings;} public void setLinhas(ArrayList list) {linhas = list;}

Agora que temos onde guardar os dados que queremos exibir, devemos implementar os mtodos que fornecem a JTable os dados suficientes para ela saber montar a parte visual: o numero de colunas, numero de linhas e os valores para preencher as clulas:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. /** * Retorna o numero de colunas no modelo * @see javax.swing.table.TableModel#getColumnCount() */ public int getColumnCount() {return getColunas().length;} /** * Retorna o numero de linhas existentes no modelo * @see javax.swing.table.TableModel#getRowCount() */ public int getRowCount() {return getLinhas().size();} /** * Obtem o valor na linha e coluna * @see javax.swing.table.TableModel#getValueAt(int, int) */ public Object getValueAt(int rowIndex, int columnIndex) { // Obtem a linha, que uma String [] String [] linha = (String [])getLinhas().get(rowIndex); // Retorna o objeto que esta na coluna return linha[columnIndex]; }

Agora, devemos criar o construtor da classe que ir receber os dados e as colunas que desejamos.
1. public SimpleTableModel(ArrayList dados, String[] colunas){ 2. setLinhas(dados); 3. setColunas(colunas); 4. }

A partir disto, j temos o nosso modelo pronto para exibir os dados contido nele. Agora vamos criar uma apresentao simples utilizando este nosso modelo. Vamos criar algo parecido com a do exemplo da primeira parte deste tutorial, e usaremos o mesmo nome: MyTableViewer. Abaixo segue como deve ficar o mtodo que cria a JTable :
view plainprint?

1. /** 2. * Cria a JTable 3. * @return 4. */ 5. public JTable createJTable() { 6. 7. ArrayList dados = new ArrayList(); 8. String[] colunas = new String[] { "Estado", "Cidade" };

9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. }

// Alimenta as linhas de dados.add(new String[] { dados.add(new String[] { dados.add(new String[] { dados.add(new String[] {

dados "SP", "RJ", "RN", "ES",

"So Paulo" }); "Rio de Janeiro" }); "Rio Grande do Norte" }); "Espirito Santo" });

SimpleTableModel modelo = new SimpleTableModel(dados, colunas); JTable jtable = new JTable(modelo); jtable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); return jtable;

Observe que o mtodo acima alimenta as variveis: dados agora um ArrayList, e inclumos nele diversos arrays de String , pois o esperado dentro da linha ( veja a implementao do mtodo getValueAt ). Se rodarmos o cdigo agora, ele ir apresentar a Jtable com nossos dados, e no ir permitir alterar, diferentemente do modelo DefaultTableModel. Isso porque no implementamos o mtodo isCellEditable, e ele acabou herdando do AbstractTableModel, que retorna false para todas as clulas. No default, este mtodo retorna true. Alterando o Contedo Do Modelo: Para permitir a edio da clula, e, principalmente, que seu valor venha parar aqui no modelo ( se voc implementar somente o mtodo isCellEditable sem o setValueAt, simplesmente ele permite a edio, mas no "fixa" seu valor na clula, pois ele no vem para o seu modelo no refletindo de volta em sua JTable ) devemos implementar os seguintes mtodos:
view plainprint?

1. public boolean isCellEditable(int row, int col) 2. public void setValueAt(Object value, int row, int col)

Voc pode deixar separado o controle de edio de suas clulas, permitindo em tempo de execuo quando determinada clula ir permitir alterao. Neste exemplo vamos permitir que seja informado, na criao do modelo, quais colunas vamos permitir edio e quais no. Para isso, vamos ter uma varivel que um array de boolean que guardar o valor de cada coluna.
view plainprint?

1. private boolean [] colsEdicao; 2. public boolean isCellEditable(int row, int col){ 3. return colsEdicao[col]; 4. }

E vamos alterar o construtor para receber esse novo parmetro:


view plainprint?

1. public SimpleTableModel(ArrayList dados, String[] colunas, boolean [] edicao){ 2. 3. 4. 5. } setLinhas(dados); setColunas(colunas); colsEdicao = edicao;

O mtodo para setar o valor, nada mais faz do que obter o objeto na linha e coluna e altera-lo. Porm, devemos lembrar que quando feito uma alterao do contedo do

modelo, devemos informar fireTableCellUpdated.


view plainprint?

JTable.

Fazemos

isso

atraves

do

mtodo

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.

/** * Seta o valor na linha e coluna * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int) */ public void setValueAt(Object value, int row, int col){ // Obtem a linha, que uma String [] String [] linha = (String [])getLinhas().get(row); // Altera o conteudo no indice da coluna passado linha[col] = (String)value; // dispara o evento de celula alterada fireTableCellUpdated(row,col); }

Para visualizarmos as alteraes que permitem alterar o valor da clula na JTable, devemos fazer as seguintes alteraes na apresentao ( MyTableViewer ) no mtodo de criao da JTable:
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9.

MyTableViewer.createJTable() String[] colunas = new String[] { "Estado", "Cidade" }; // sem alterao // linha adicionada apos a criao das colunas boolean [] edicao = {false, true}; // Alterar chamada de criao do modelo SimpleTableModel modelo = new SimpleTableModel(dados, colunas, edicao); // para enviar as propriedades de edicao das colunas

Inclusao de novas linhas Como a jtable no faz incluso de linhas no modelo diretamente, este mtodo no uma implementao, ou seja, no preciso ter uma assinatura especifica. Para incluir novas linhas, devemos adicionar um novo objeto no array de linhas. Este objeto deve ser do mesmo tipo em todas as linhas, ou seja, se for utilizar um array de String[2], sempre incluir arrays de String[2]. Pois no mtodo getValueAt voc tem que saber o que pegar nas linhas. Abaixo segue um exemplo de um mtodo, bem simples, para incluir uma nova linha no modelo.
view plainprint?

1. public void addRow( String [] dadosLinha){ 2. getLinhas().add(dadosLinha); 3. // Informa a jtable de que houve linhas incluidas no modelo 4. // COmo adicionamos no final, pegamos o tamanho total do modelo 5. // menos 1 para obter a linha incluida. 6. int linha = getLinhas().size()-1; 7. fireTableRowsInserted(linha,linha); 8. return; 9. }

Exclusao de linhas existentes Assim como a incluso de linhas, a excluso delas feita diretamente pelo modelo dos dados da jtable. E funciona assim como na incluso. Devemos remover a linha passada pelo parmetro. Usando um ArrayList, podemos excluir diretamente pelo indice dele. Ou, podemos esperar um campo contido na linha, fazemos um looping nos dados para verificar o contedo. Abaixo, veremos esses dois exemplos de

excluso. Um problema que devemos tomar cuidado que, se informado uma linha que no existe no modelo, ento o mtodo remove do ArrayList ir disparar um IndexOutOfBound, ou seja, no existe indice informado dentro do array. Voc pode tratar isso verificando se o parmetro informado ir passar dos limites do array ( se ele negativo e se maior ou igual ao tamanho total do array ).
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.

public void removeRow(int row){ getLinhas().remove(0); // informa a jtable que houve dados deletados passando a // linha reovida fireTableRowsDeleted(row,row); }

/** * Remove a linha pelo valor da coluna informada * @param val * @param col * @return */ public boolean removeRow(String val, int col){ // obtem o iterator Iterator i = getLinhas().iterator(); int linha = 0; // Faz um looping em cima das linhas while(i.hasNext()){ // Obtem as colunas da linha atual String[] linhaCorrente = (String[])i.next(); linha++; // compara o conteudo String da linha atual na coluna desejada // com o valor informado if( linhaCorrente[col].equals(val) ){ getLinhas().remove(linha); // informa a jtable que houve dados deletados passando a // linha removida fireTableRowsDeleted(linha,linha); return true; } } // Nao encontrou nada return false; }

Retornando o Titulo da Coluna Este mtodo retorna uma String com o titulo da coluna. A JTable ir chamar este mtodo para obter o titulo da coluna e colocar no Header, quando suas colunas forem criadas automaticamente a partir do seu modelo.
view plainprint?

1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

// Implementao do getColumnName /** * Retorna o nome da coluna. * @see javax.swing.table.TableModel#getColumnName(int) */ public String getColumnName(int col){ return getColunas()[col]; }

Para evitar que a JTable crie as colunas nela automaticamente, devemos setar a propriedade AutoCreateColumnsFromModel para false. Neste caso, devemos criar as colunas na mo. Concluso Tenha em mente uma coisa: dentro do modelo, no importa como voc armazene seus dados. No interessa para a JTable se voc usou a classe mais avanada, se buscou na hora direto do seu banco, ou se est tudo em um array. O importante fornecer o valor atraves dos mtodos, e informar das alteraes ocorridas no seu modelo. Assim, voc poder implementar de diversas formas o seu modelo. Futuramente iremos trabalhar usando os Renderers e Editors. Com eles, poderemos utilizar qualquer classe para exibir ou armazenar e logo veremos a vantagem de se implementar o seu prprio modelo. No proximo tutorial, iremos ver como criar as colunas direto na JTable, sem deixar que elas sejam criadas automaticamente pelo modelo. Tambem iremos ver como criar nossos prprios renderers e editors para usar na tabela. Aguardem! Abraos e at o proximo tutorial!