JTableView - Swing

17.290 visualizações

Publicada em

12 comentários
10 gostaram
Estatísticas
Notas
Sem downloads
Visualizações
Visualizações totais
17.290
No SlideShare
0
A partir de incorporações
0
Número de incorporações
84
Ações
Compartilhamentos
0
Downloads
1.119
Comentários
12
Gostaram
10
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

JTableView - Swing

  1. 1. Prof: Sérgio Souza Costa JTableView e MVC
  2. 2. Sobre mim Sérgio Souza Costa Professor - UFMA Doutor em Computação Aplicada (INPE) prof.sergio.costa@gmail.com https://sites.google.com/site/profsergiocosta/home https://twitter.com/profsergiocosta http://gplus.to/sergiosouzacosta http://www.slideshare.net/skosta/presentations?order=popular
  3. 3. Dando sequência, o desafio de hoje é conseguir carregar os dados de uma tabela e mostrar na interface gráfica.
  4. 4. public List<Contato> recupera () { String sql = "select * from contato"; List<Contato> contatos = new ArrayList<Contato>(); try { PreparedStatement stmt = connection.prepareStatement(sql); ResultSet rs = stmt.executeQuery(); while (rs.next()) { Contato contato = new Contato(); contato.setNome(rs.getString("nome")); contato.setTelefone(rs.getString("telefone")); contato.setEmail(rs.getString("email")); contatos.add(contato); } stmt.close(); } catch (SQLException u) { throw new RuntimeException(u); } return contatos; } Antes de começarmos, vamos precisar ter o método “recupera” na classe ContatoDAO que retorna a lista de contatos do banco de dados.
  5. 5. Eu vi que o Swing possui um controle gráfico, chamado JTable. Mas como faço para utilizá-lo ?
  6. 6. O Jtable apresenta uma grade multidimensional de objetos.
  7. 7. Por exemplo, é possível construir tabelas simples através de um array bidimensional de objetos. JTable(Object[][] dados, Object[] nomeColunas) //dados : as células da tabela //nomesColunas : os títulos da coluna
  8. 8. Object[][] data = { {"João", "Carlos", “Natação", new Integer(5)}, {"Francisco", "Silva", "Remo", new Integer(3)}, {"Fernando", "Cardoso","Montanismo", new Integer(2)}, {"Luís Inácio", "Silva","Futebol", new Integer(20)}, {"Angela", "Maria","Rapel", new Integer(4)} }; String[] colunas = {"Nome","Sobrenome","Esporte", "Prática (ano)","Vegetariano"}; final JTable table = new JTable(data , colunas ); Exemplo usando array
  9. 9. Contudo, as tabelas podem ser dinâmicas e acessando diferentes fontes de dados (datasources). Precisando ser mais versátil.
  10. 10. O Swing consegue isso implementando o Jtable como um componente MVC.
  11. 11. Como assim ?
  12. 12. O modelo (dados) é separado da visualização. Model (TableModel) View (JTable) JTable(TableModel dm)
  13. 13. As principais classes são: ● JTable -- view ● TableModel -- Interface (getValueAt(), setValueAt, getRowCount(), getColumnCount(), ... ● TableModelListener -- Interface ( tableChanged()) ● AbstractTableModel -- implementa alguns métodos não diretamente relacionadas ao armazenamento addTableModelListener(), removeTableModelListener(), ● DefaultTableModel -- classe concreta usando array
  14. 14. Então, o DefaultTableModel pode ser usado quando seus dados são estáticos.
  15. 15. Lembra do código do slide 9 ? O código abaixo é equivalente. Nele mostro o uso explícito do DefaultTableModel Object[][] data = { {"João", "Carlos", "Natação", new Integer(5)}, {"Francisco", "Silva", "Remo", new Integer(3)}, }; String[] colunas = {"Nome","Sobrenome","Esporte", "Prática (ano)","Vegetariano"}; DefaultTableModel tm = new DefaultTableModel(data, colunas); JTable t = new JTable(tm );
  16. 16. Entendi, basta carregar os dados do banco, convertê-los para array, e construir um DefaultTableModel.
  17. 17. Calma, no caso de banco de dados esta não é a melhor solução.
  18. 18. Ao invés disso construímos nossa própria classe TableModel. Vamos ver melhor a camada modelo.
  19. 19. Camada Modelo A classe abstrata AbstractTableModel que implementa a interface TableModel fornece a maioria dos métodos exigidos. É necessário fornecer principalmente implementações para três métodos abaixo: public int getRowCount( ) public int getColumCount( ) public Object getValueAt(int linha, int coluna) – é responsável por fornecer os dados para a tabela, a qual requisitará os dados através do método getValueAt, informando a linha e a coluna
  20. 20. Camada Modelo • Alguns métodos definidos em AbstractTableModel oferecem um maior grau de controle: – public String getColumnName(int col) • Se não for fornecido nomes de colunas, o método getColumnName do modelo AbstractTableModel atribuíra os nome A, B, C, e assim por diante • Para mudar o nome das colunas é necessário substituir o método getColumnName – public boolean isCellEditable(int rowIndex, int columnIndex) • Não é obrigatório redefinir este método • O valor retornado por padrão é false
  21. 21. Camada de Modelo public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } A redefinição deste método fornece mais informações sobre o tipo da coluna, pois retorna a classe que representa o objeto Exibidores padrão: 21 Tipo Exibe como Imagem imagem Boolean checkBox (caixa de seleção) Object String
  22. 22. Visualização e Controle Camada de Visualização (View): É a parte que cuida da apresentação – É implementado pela interface CellRenderer. É como a apresentação é dada célula a célula na tabela Controlador: é a parte que controla a apresentação dos dados na view – É o JTable 22
  23. 23. • DefaultTableModel fornece todo o controle dos dados do JTable – getValueAt(): recupera o valor de uma determinada linha e coluna – setValueAt(): seta o valor em uma determinada linha e coluna – addRow(): adiciona uma nova linha no JTable. Recebe um array simples – addColumn(): adiciona uma nova coluna no modelo 23 DefaultTableModel
  24. 24. 24 String[][] dados = new String [][]{ {"SP","Sao Paulo"}, {"RJ","Rio de Janeiro"}, {"RN","Rio Grande do Norte"}, {"PR","Parana"} }; String[] colunas = new String []{"Estado","Cidade"}; // Adiciona os dados em um modelo DefaultTableModel modelo = new DefaultTableModel(dados, colunas); // e passamos o modelo para criar a jtable JTable jtable = new JTable( modelo ); DefaultTableModel
  25. 25. Vamos a prática
  26. 26. public class ContatoTableModel extends AbstractTableModel { private List<Contato> contatos; private List<String> colunas; private ContatoDAO dao; public ContatoTableModel (ContatoDAO dao){ this.dao = dao; this.contatos = dao.recupera(); colunas = Arrays.asList("Nome", "Email"); } public int getRowCount() { return contatos.size(); } public int getColumnCount() {return colunas.size(); } public String getColumnName(int i){ return colunas.get(i); } public Object getValueAt(int r, int c) { Contato contato = contatos.get(r); switch (c) { case 0 : return contato.getNome(); case 1 : return contato.getEmail(); } return null; } } Crie uma classe ContatoTableModel:
  27. 27. public class FrameTable extends JFrame { public FrameTable (){ super(”Contatos"); ContatoDAO dao = new ContatoDAO(); ContatoTableModel tm = new ContatoTableModel (dao); JTable t = new JTable (tm); JScrollPane scroll = new JScrollPane(); scroll.setViewportView(t); add(scroll); setSize(200, 180); } public static void main(String[] args) { FrameTable f = new FrameTable(); f.setVisible(true); } } Para vermos o resultado. Basta criar um frame com apenas um Jtable.
  28. 28. public class FrameTable extends JFrame { public FrameTable (){ super(”Contatos"); ContatoDAO dao = new ContatoDAO(); ContatoTableModel tm = new ContatoTableModel (dao); JTable t = new JTable (tm); JScrollPane scroll = new JScrollPane(); scroll.setViewportView(t); add(scroll); setSize(200, 180); } public static void main(String[] args) { FrameTable f = new FrameTable(); f.setVisible(true); } } Jtable não implementa as barras de rolagem. Para isso adicionamos o Jtable ao JScrollPane.
  29. 29. Este é o resultado do código anterior
  30. 30. Legal. Mas eu quero tornar o Jtable editável. Então, eu codifiquei o seguinte método para a classe “ContatoTableModel” @Override public boolean isCellEditable(int r, int c) { return true; }
  31. 31. Com este método Jtable passou me deixar alterar o valor, porém quando eu clico “enter” os valores não são alterados.
  32. 32. public void setValueAt(Object aValue, int r, int c) { // Pega o contato referente a linha especificada. Contato contato = contatos.get(r); switch (c) { case 0: contato.setNome((String) aValue); break; case 1: contato.setEmail((String) aValue); break; default: throw new IndexOutOfBoundsException( "columnIndex out of bounds"); } fireTableCellUpdated(r, c); // Notifica a atualização da célula } Faltou implementar o método setValueAt.
  33. 33. Sim. Porém, quando reiniciei minha aplicação, percebi que o Jtable voltou a mostrar os valores antigos. O banco de dados não foi atualizado ☹
  34. 34. Observe que o código não faz nenhuma alteração no banco de dados.
  35. 35. Qual operação SQL precisamos executar ?
  36. 36. A operação “Update ….” atualiza uma determinada linha de uma tabela.
  37. 37. Aonde está operação deve ser codificada ?
  38. 38. public void atualiza (Contato c) { String sql = "update contato set nome=?, email=? where id = ?"; try { PreparedStatement stmt = conn.prepareStatement(sql); stmt.setString(1, c.getNome()); stmt.setString(2, c.getEmail()); stmt.setLong(3, c.getId()); stmt.execute(); stmt.close(); } catch (SQLException u) { throw new RuntimeException(u); } } Inseri o método atualiza na classe ContatoDAO.
  39. 39. Mas como vou chamar esta operação ?
  40. 40. public class ContatoTableModel extends AbstractTableModel implements TableModelListener { private List<Contato> contatos; private List<String> colunas; private ContatoDAO dao; public ContatoTableModel(ContatoDAO dao){ this.dao = dao; this.contatos = dao.recupera(); colunas = Arrays.asList("Nome", "Email"); this.addTableModelListener(this); } …. } Precisamos tratar o evento “TableChange”. Para isso fazemos a seguinte modificação a classe ContatoTableModel
  41. 41. public void tableChanged(TableModelEvent event) { int i = event.getFirstRow(); Contato contato = contatos.get(i); System.out.println(i); dao.atualiza(contato); } Então codificamos o método tableChanged da classe ContatoTableModel
  42. 42. YES. Agora sim
  43. 43. Se eu quisesse incluir um combo box? É possível ?
  44. 44. Sim. Veja o seguinte exemplo. Adicione a coluna “grupo” a tabela contato. alter table contato add grupo varchar(50);
  45. 45. Modifique as classes Contato, ContatoDAO e ContatoTableModel para incluir mais uma coluna.
  46. 46. public FrameTable (){ super("Teste"); final ContatoDAO dao = new ContatoDAO(); ContatoTableModel tm = new ContatoTableModel (dao); JTable t = new JTable (tm); JComboBox comboBox = new JComboBox(); comboBox.addItem("Familia"); comboBox.addItem("Amigo"); comboBox.addItem("Conhecido"); t.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(comboBox)); JScrollPane scroll = new JScrollPane(); scroll.setViewportView(t); add(scroll); setSize(200, 180); } Crie a combo box e adicione-a na coluna.
  47. 47. Legal. Mas se a tabela tivesse outros tipos de dados, por exemplo, boolean.
  48. 48. alter table contato add ativo boolean; Adicione a coluna ativo a tabela contato e modifique as classes Contato, ContatoDAO ....
  49. 49. Mas a coluna ativo mostra o valor false. Esse não é um valor esperado pelo usuário.
  50. 50. A renderização padrão da tabela é string, se quisermos usar outra precisamos informar o tipo de dado ao Jtable com o método getColumnClass. @Override public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); }
  51. 51. O método getColumnClass faz a JTable associar automaticamente um TableCellRenderer específico para campos booleanos. Por exemplo, booleano é renderizado como um checkbox.
  52. 52. Se eu desejar adicionar ou remover uma linha ?
  53. 53. Queria usar um banco de dados mais simples, tipo o Access, ou seja, que não precise de um servidor.
  54. 54. De fato, nem sempre precisamos de um banco de dados robusto em pequenas aplicações para desktop.
  55. 55. Mesmo em aplicações mais complexas, é comum usar um banco de dados mais simples no inicio do desenvolvimento. Depois, com o JDBC, podemos facilmente mudar para um servidor de banco de dados, como o Oracle ou mesmo o MySQL.
  56. 56. Se eu desejar adicionar ou remover uma linha ?
  57. 57. Basta adicionar um novo contato a lista de contatos da ContatoTableModel e depois notificar esta mudança ao Jtable através do método: fireTableDataChanged.
  58. 58. Porém, para salvar no banco de dados, precisamos adicioná-lo também ao banco.
  59. 59. Então, fazemos assim, criamos um contato apenas com ID, e adicionamos a tabela. Então o usuário poderá atualiza-lo com as informações. Para isso criamos o seguinte método na classe ContatoTableModel. public void addContato(){ Contato c = new Contato () contatos.add(c); dao.adiciona(c); fireTableDataChanged(); }
  60. 60. No construtor da classe FrameTable adicione os botões adicionar e excluir: JPanel pan = new JPanel (); JButton btNovo = new JButton ("Novo"); JButton btExcluir = new JButton ("Excluir"); pan.add(btNovo, BorderLayout.EAST); pan.add(btExcluir, BorderLayout.EAST); add(pan, BorderLayout.SOUTH);
  61. 61. Depois, basta adicionar o evento action com a seguinte codificação btNovo.addActionListener( new ActionListener () { @Override public void actionPerformed (ActionEvent ev){ tm.addContato(); } });
  62. 62. Desafio: Codifiquem o botão excluir. Atividade

×