Olá pessoal, tudo bom?
Vamos continuar a criação de uma JTable em Java Swing. Na parte 1 deste post, foi apresentado o que era uma JTable e como não era possível criar um relacionamento de uma classe da camada Model com uma filha da AbstractTableModel, que é a classe que o componente JTable utiliza para apresentar dados ao usuário.
Para resolver esse problema foi criada uma classe abstrata chamada ViewAbstractTableModel, a qual codificava vários aspectos até então inexistentes dentro da classe AbstractTable, entre eles a entrega de uma instância de List contendo várias instâncias de uma determinada classe de um pacote Model.
Agora será necessário deixar de ser absolutamente genérico e partir para uma abordagem mais específica. Assim continuando com o nosso objetivo de apresentar uma JTable para uma lista de Endereco, vamos criar uma classe chamada EnderecoTableModel.
Criando uma DataTable especializada!
Agora é hora de criar uma DataTable especializada. Aproveitando a classe Endereco mostrada na Parte 1 deste post, vamos criar uma classe chamada EnderecoTableModel. Essa classe deverá ser filha de ViewAbstractTableModel, e dessa forma pela herança passar a classe Endereco no Wildcard da classe, parte de Generics, e criar um construtor que receba uma lista de Endereco, para a qual iremos chamar o construtor da classe super, ViewAbstractTableModel, passando a lista. Vamos ver como fica o código inicial desta classe
1 2 3 4 5 6 7 8 9 10 |
package br.com.mauda.view.model; import br.com.mauda.model.Endereco; public class EnderecoTableModel extends ViewAbstractTableModel<Endereco>{ public EnderecoTableModel(List<Endereco> rows) { super(rows); } } |
Além disso outro ponto que não possível de ser realizado na classe ViewAbstractTableModel era a inicialização dos nomes das colunas. Assim o melhor momento de realizar a inicialização desta é no construtor da classe. Nós teremos 7 colunuas dispostas da seguinte maneira:
- Coluna 0: “Rua”
- Coluna 1: “Numero”
- Coluna 2: “Complemento”
- Coluna 3: “Bairro”
- Coluna 4: “Cidade”
- Coluna 5: “Estado”
- Coluna 6: “Pais”
Vamos ver como ficará a inicialização dos títulos das colunas no nosso código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package br.com.mauda.view.model; import br.com.mauda.model.Endereco; public class EnderecoTableModel extends ViewAbstractTableModel<Endereco>{ public EnderecoTableModel(List<Endereco> rows) { super(rows); columns = new String[]{ "Rua", //[0] "Numero", //[1] "Complemento", //[2] "Bairro", //[3] "Cidade", //[4] "Estado", //[5] "Pais"}; //[6] }//fim do construtor } |
O último ponto desta classe é que deverá ser feito o override do método Object getValueAt(int row, int col), indicando o que irá retornar para cada row e column. Ou seja, caso esse método for chamado da seguinte forma getValueAt(1,1), significa que devemos recuperar a celula que se encontra na row 1, column 1. A implementação então deverá recuperar o objeto que se encontra na posição 1 da lista, linhas.get(1) e depois recuperar a informação que se encontra na coluna 1, no caso o número do endereço. Vamos ver no código como ficará esse ponto:
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 37 38 39 40 41 42 |
package br.com.mauda.view.model; import br.com.mauda.model.Endereco; public class EnderecoTableModel extends ViewAbstractTableModel<Endereco>{ public EnderecoTableModel(List<Endereco> rows) { super(rows); columns = new String[]{ "Rua", //[0] "Numero", //[1] "Complemento", //[2] "Bairro", //[3] "Cidade", //[4] "Estado", //[5] "Pais"}; //[6] }//fim do construtor @Override public Object getValueAt(int row, int col) { Endereco end = rows.get(row); switch (col) { case 0: return end.getRua(); case 1: return end.getNumero(); case 2: return end.getComplemento(); case 3: return end.getBairro(); case 4: return end.getCidade(); case 5: return end.getEstado(); case 6: return end.getPais(); default: return null; } } } |
Assim está terminada a implementação da classe EnderecoTableModel. O código se torna bem mais compacto e direto aproveitando-se dos conceitos de Herança e do reuso de código. Como essa classe é filha da classe TableModel, podemos adicionar a um componente JTable, para que este exiba a informação existente dentro da classe. O próximo passo agora é implementar a parte gráfica para exibir as informações de uma lista de Endereços recuperadas de um banco de dados por exemplo.
Criando a Parte Gráfica
Como toda interface gráfica em Java Swing é necessário que seja criada uma “casca básica” para adicionar os componentes gráficos que estão codificados dentro da biblioteca. Essa casca é chamada de JPanel. Nossa tela será chamada de ListaEnderecosView, representando uma tela que exibe uma lista de Endereços. Essa classe, a fim de ficar mais fácil a explicação, estenderá a classe JFrame. Vamos então criar esse primeiro código que representa uma tela básica em Java Swing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package br.com.mauda.javaSwing.view; import javax.swing.JFrame; import javax.swing.JPanel; public class ListaEnderecosView extends JFrame { private static final long serialVersionUID = 1L; public ListaEnderecosView() { //Criacao da tela basica Java Swing super("Lista Enderecos"); this.setSize(800,150); JPanel jpanel = new JPanel(); this.setContentPane(jpanel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }//Fim do construtor } |
Para rodar a classe ListaEnderecoView é necessário criar uma outra classe, MainListaEnderecoView, que contenha um método main; Dentro desse método será necessário dar um new na classe ListaEnderecoView e chamar o método setVisible(true) para exibir a tela. O código ficará da seguinte forma:
1 2 3 4 5 6 7 8 9 10 11 |
package br.com.mauda.javaSwing.view.main; import br.com.mauda.javaSwing.view.ListaEnderecosView; public class MainListaEnderecosView { public static void main(String[] args) { ListaEnderecosView tela = new ListaEnderecosView(); tela.setVisible(true); } } |
Caso o método main seja rodado, exibirá a seguinte tela, Figura 01:
Voltando para a classe ListaEnderecosView, agora é hora de mudar a classe para que receba uma lista de Endereços em seu construtor e depois criar uma nova instância de EnderecoTableModel para futuramente adicionar na JTable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package br.com.mauda.javaSwing.view; import javax.swing.JFrame; import javax.swing.JPanel; import br.com.mauda.javaSwing.model.Endereco; import br.com.mauda.javaSwing.view.model.EnderecoTableModel; public class ListaEnderecosView extends JFrame { private static final long serialVersionUID = 1L; public ListaEnderecosView(List<Endereco> enderecos) { //Criacao da tela basica Java Swing super("Lista Enderecos"); this.setSize(800,150); JPanel jpanel = new JPanel(); this.setContentPane(jpanel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Criacao da TableModel e JTable EnderecoTableModel etm = new EnderecoTableModel(enderecos); }//Fim do construtor } |
Agora será necessário adicionar o código para a criação da JTable. Esse código receberá a instância de EnderecoTableModel. Além disso deverá setar a dimensão básica para a JTable e adicionar ela no JPanel da tela:
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 |
package br.com.mauda.javaSwing.view; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import br.com.mauda.javaSwing.model.Endereco; import br.com.mauda.javaSwing.view.model.EnderecoTableModel; public class ListaEnderecosView extends JFrame { private static final long serialVersionUID = 1L; public ListaEnderecosView(List<Endereco> enderecos) { //Criacao da tela basica Java Swing super("Lista Enderecos"); this.setSize(800,150); JPanel jpanel = new JPanel(); this.setContentPane(jpanel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Criacao da TableModel e JTable EnderecoTableModel etm = new EnderecoTableModel(enderecos); JTable jTable = new JTable(etm); jTable.setPreferredScrollableViewportSize(new Dimension(700, 48)); jpanel.add(new JScrollPane(jTable)); }//Fim do construtor } |
Ao final vamos criar ainda uma classe Listerner para trabalhar com eventos sobre a JTable, como seleção de linhas. Esse listener, chamado RowListener, deverá implementar a interface javax.swing.event.ListSelectionListener e com isso implementar o método valueChanged(ListSelectionEvent event). Dentro desse método será obtida qual foi a linha selecionada pelo usuário e vamos imprimí-la no console.
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 37 38 39 40 41 42 43 44 45 46 |
package br.com.mauda.javaSwing.view; import java.awt.Dimension; import javax.swing.DefaultListSelectionModel; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import br.com.mauda.javaSwing.model.Endereco; import br.com.mauda.javaSwing.view.model.EnderecoTableModel; public class ListaEnderecosView extends JFrame { private static final long serialVersionUID = 1L; public ListaEnderecosView(List<Endereco> enderecos) { //Criacao da tela basica Java Swing super("Lista Enderecos"); this.setSize(800,150); JPanel jpanel = new JPanel(); this.setContentPane(jpanel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Criacao da TableModel e JTable EnderecoTableModel etm = new EnderecoTableModel(enderecos); JTable jTable = new JTable(etm); jTable.setPreferredScrollableViewportSize(new Dimension(700, 48)); jpanel.add(new JScrollPane(jTable)); }//Fim do construtor } /** * Classe para o Listener * */ class RowListener implements ListSelectionListener{ public void valueChanged(ListSelectionEvent event){ DefaultListSelectionModel jTable = (DefaultListSelectionModel) event.getSource(); System.out.println("Linha: " + jTable.getLeadSelectionIndex()); }//fim do metodo valueChanged }//fim da classe |
Pronto a classe View está criada. Vamos agora voltar para o método main e fazer as alterações necessárias para receber uma lista de endereços. Além disso vamos criar algumas instâncias de endereço para que possamos emular uma tabela com informações. Veja o código abaixo com essas alterações:
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 37 38 39 40 41 42 43 44 45 46 |
package br.com.mauda.javaSwing.view.main; import br.com.mauda.javaSwing.view.ListaEnderecosView; public class MainListaEnderecosView { public static void main(String[] args) { List<Endereco> enderecos = new ArrayList<Endereco>(); Endereco endereco = new Endereco(); endereco.setBairro("AF"); endereco.setCidade("SJP"); endereco.setComplemento("CASA 1c"); endereco.setEstado("PR"); endereco.setNumero(253); endereco.setPais("BR"); endereco.setRua("Afonso camargo"); enderecos.add(endereco); endereco = new Endereco(); endereco.setBairro("AP"); endereco.setCidade("CTBA"); endereco.setComplemento(""); endereco.setEstado("PR"); endereco.setNumero(156); endereco.setPais("BR"); endereco.setRua("Alfred Siemensem"); enderecos.add(endereco); endereco = new Endereco(); endereco.setBairro("SDF"); endereco.setCidade("SP"); endereco.setComplemento(""); endereco.setEstado("SP"); endereco.setNumero(44555); endereco.setPais("BR"); endereco.setRua("Paulus Rotvols"); enderecos.add(endereco); ListaEnderecosView tela = new ListaEnderecosView(enderecos); tela.setVisible(true); } } |
Criado esse código, vamos rodar e ver como ficou a tela final, Figura 02.
finally{
Com esse post nós passamos a entender como adicionar uma JTable a uma tela JavaSwing a partir de uma Lista de Endereços.
Mais importante ainda é perceber que nenhuma implementação final de uma biblioteca é imutável; Ela pode ser melhorada, obtendo novos conceitos e formas de reuso de código.
Existia a necessidade da reescrita de código sempre que havia a necessidade de exibição de uma Lista de entidades em uma JTable.
Esse código DE-PARA foi escrito de uma forma reutilizável agora, tornando o código fácil para o desenvolvedor, bastando se preocupar em uma implementação especifica para a Table, caso da classe EnderecoTableModel, e a adição dessas informações em uma Tela JavaSwing a partir de uma JTable.
Dúvidas? Deixe nos comentários abaixo, ou mande um email.
Semana que vem tem mais post!
Até lá!
Marcos Vieira says
Parabéns pelo artigo. É muito didático, mas tenho uma dúvida:
Como popular esta tabela com uma lista vinda do Banco de Dados através de uma consulta via Criteria do Hibernate????
Mauda says
Olá Marcos, tudo bom?
Obrigado pelo feedback!
Como está vindo esta lista? Por exemplo, se vc observar no código eu crio um parâmetro no construtor da classe filha que é do tipo List< Endereco >. Vamos supor que sua Criteria retorne uma List< Carro >, dessa forma no construtor você terá que usar um List< Carro >. Assim todo o resto do código deverá ser adaptado para o que você irá mostrar na tabela, buscando as informações que você necessita.
Espero ter ajudado. Se ficou duvidas faça mais perguntas!
Obrigado.
Mauda
Jonilson Canedo says
Primeiramente quero te agradecer! Estou fazendo um trabalho na faculdade e sua aula me ajudou muito, encontrei a solução do meu problema aqui. Mas preciso que a tabela apareça em um JFrame com JPanel já criando. Quando eu apertar um botão, é preciso que a tabela apareça na mesma janela do botão. Como fazer isso? Por favor me ajude, pois tentei de tudo o que sei mas não obtive sucesso! Aguardo amigo, abçs!
Mauda says
Olá Jonilson, tudo bom?
Primeiramente se você criar a JTable conforme o artigo facilita. Depois você precisa repintar a JTable. Veja se esse question te ajuda:
http://stackoverflow.com/questions/3179136/jtable-how-to-refresh-table-model-after-insert-delete-or-update-the-data
Duvidas a disposição.
Obrigado pelo Feedback!