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. Dando sequência, o desafio de hoje é
conseguir carregar os dados de uma tabela e
mostrar na interface gráfica.
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. Eu vi que o Swing possui um controle
gráfico, chamado JTable. Mas como
faço para utilizá-lo ?
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. 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. Contudo, as tabelas podem ser
dinâmicas e acessando diferentes
fontes de dados (datasources).
Precisando ser mais versátil.
10. O Swing consegue isso
implementando o Jtable como um
componente MVC.
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. Entendi, basta carregar os dados do
banco, convertê-los para array, e
construir um DefaultTableModel.
17. Calma, no caso de banco de dados
esta não é a melhor solução.
18. Ao invés disso construímos nossa
própria classe TableModel. Vamos ver
melhor a camada modelo.
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. 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. 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. 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. • 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
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
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. 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. 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.
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. 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. 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. 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. Observe que o código não faz
nenhuma alteração no banco de
dados.
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. 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
44. Sim. Veja o seguinte exemplo.
Adicione a coluna “grupo” a tabela
contato.
alter table contato add grupo
varchar(50);
45. Modifique as classes Contato,
ContatoDAO e ContatoTableModel para
incluir mais uma coluna.
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. Legal. Mas se a tabela
tivesse outros tipos de
dados, por exemplo,
boolean.
48. alter table contato add
ativo boolean;
Adicione a coluna ativo a tabela contato
e modifique as classes Contato,
ContatoDAO ....
49. Mas a coluna ativo
mostra o valor false. Esse
não é um valor esperado
pelo usuário.
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. O método getColumnClass faz a JTable associar
automaticamente um TableCellRenderer
específico para campos booleanos.
Por exemplo, booleano é renderizado como um
checkbox.
53. Queria usar um banco de dados
mais simples, tipo o Access, ou
seja, que não precise de um
servidor.
54. De fato, nem sempre precisamos de um
banco de dados robusto em pequenas
aplicações para desktop.
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.
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. Porém, para salvar no banco de dados,
precisamos adicioná-lo também ao banco.
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. 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. Depois, basta adicionar o evento action com
a seguinte codificação
btNovo.addActionListener( new ActionListener () {
@Override
public void actionPerformed (ActionEvent ev){
tm.addContato();
}
});