Pessoal, já cansei de ver aqui sobre: Não Use DefaultTableModel. É o seguinte, minha dúvida é bem básica, só para ter certeza mesmo. Estou estudando pelo livro Java como programar 8° edição e no cap. sobre banco de dados, onde ele explica a JTable, AbstractTableModel eu não o vi usar esse DefaultTableModel. Ele cria uma classe que estende AbstractTableModel, em momento nenhum vi o DefaultTableModel. A minha pergunta é: o livro já está ensinando da melhor maneira? É correto isso que ele está fazendo? Isso é a minha própria implementação do AbstractTableModel e está no padrão MVC ainda por cima?
Vou até digitar o enunciado aqui para vocês terem noção.
[color=blue]28.8.2 Consultando o banco de dados books[/color]
O próximo exemplo( figuras 28.25 e 28,28 ) permite ao usuário inserir qualquer consulta no programa. O exemplo exibe o resultado de uma consulta em uma JTable, usando um objeto TableModel para fornecer os dados de ResultSet para a JTable. Um JTable é um componente Swing que pode ser vinculado a um banco de dados para exibir os resultados de uma consulta. A classe ResultSetTableModel( Figura 28.25 ) realiza a conexão com o banco de dados via uma TableModel e mantém o ResultSet. A classe DisplayQueryResults( Figura 28.28 ) cria a GUI e especifica uma instância da classe ResultSetTableModel para fornecer dados a JTable.
[color=blue]Classe ResultSetTableModel[/color]
A classe ResultSetTableModel estende a classe AbstractTableModel, que implementa a interface TableModel. ResultSetTableModel sobrescreve os métodos TableModel getColumnClass, getColumnCount, getColumnName, getRowCount e getValueAt. As implementações padrão dos métodos TableModel isCellEditable e setValueAt( fornecidas por AbstractTableModel ) não são sobrescritas, porque esse exemplo não suporta a edição de células JTable. As implemetações padrão dos métodos addTableModelListener e removeTableModelListener( fornecidos por AbstractTableModel ) não são sobrescritas, porque as implementações desses métodos em AbstractTableModel adicionam e removem adequadamente os ouvintes( listeners ) de evento.
[color=red]
Além dessa dúvida, tenho outra, que é, se na interface temos que sobrescrever todos os métodos nas implementações dela, menos naquelas que são Adapter que a gente pode escolher o que implementar, mesmo com a explicação do livro, eu não entendi porque ele não sobrescreveu os métodos: isCellEditable e setValueAt e addTableModelListener e removeTableModelListener. Alguém poderia me explicar com OUTRAS PALAVRAS( Não explique exatamente igual ao livro senão vou continuar a ficar sem entender por favor ). Obrigado[/color]
Aqui segue o código da classe do exemplo do livro:
/* #######################################################################################################################################
* Nome do Aplicativo: ##
* Nome do Arquivo: ResultSetTableModel.java ##
* Nome do Projeto: ##
* Plataforma: ##
* Função do Aplicativo: Um Table Model que fornece dados ResultSet a uma JTable. Linhas e colunas do ResultSet sao contadas a partir ##
* de 1 linhas e colunas. JTable são contadas a partir de 0. Ao processar linhas ou colunas de ResultSet para utilização em uma JTable, ##
* é necessário adicionar 1 ao número de linha ou coluna para manipular a coluna apropriada de ResultSet( isto é, coluna 0 de JTable é ##
* a coluna de ResultSet 1 e a linha de JTable 0 é a linha de ResultSet 1 ). ##
* @author Lucas Santos ##
* Criado em 17/06/2012, 12:37:18 ##
* #######################################################################################################################################
*/
import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import javax.swing.table.AbstractTableModel;
public class ResultSetTableModel extends AbstractTableModel {
private Connection connection;
private Statement statement;
private ResultSet resultSet;
private ResultSetMetaData metaDados;
private int numeroDeLinhas;
/** * Monitora o status da conexão de banco de dados */
private boolean conectadoAoDB = false;
/** * Construtor inicializa resultSet e obtém seu objeto de metaDados; Determina o número de linhas */
public ResultSetTableModel( String url, String username, String password, String query ) throws SQLException {
/** * Conecta-se ao banco de dados */
connection = DriverManager.getConnection( url, username, password );
/** * Cria Statement para enviar instruções de SQL ao DB */
statement = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
/** * Atualiza status de conexão de banco de dados */
conectadoAoDB = true;
/** * Configura consulta e a executa */
setQuery( query );
} // fim do Construtor
/** * Obtém a classe que representa o tipo de coluna */
public Class getColumnClass( int coluna ) throws IllegalStateException {
/** * Assegura que o banco de dados conexão está disponível */
if( !conectadoAoDB ) {
throw new IllegalStateException( "Não está conectado ao Banco de Dados" );
}
/** * Determina a classe Java de coluna */
try {
String nomeClasse = metaDados.getColumnClassName( coluna + 1 );
/** * Retorna objeto Class que representa a nomeClasse */
return Class.forName( nomeClasse );
}
catch( Exception e ) {
e.printStackTrace();
}
/** * Se ocorrerem os problemas acima, assume tipo Object */
return Object.class;
} // fim do método getColumnClass
/** * Obtém o número de colunas em ResultSet */
public int getColumnCount() throws IllegalStateException {
/** * Assegura que o banco de dados conexão está disponível */
if( !conectadoAoDB ) {
throw new IllegalStateException( "Não está conectado ao Banco de Dados" );
}
try {
return metaDados.getColumnCount();
}
catch( SQLException sqlE ) {
sqlE.printStackTrace();
}
/** * Se ocorrerem os problemas acima, retorna 0 para o número de colunas */
return 0;
} // fim do método getColumnCount
/** * Obtém o nome de uma coluna particular em ResultSet */
public String getColumnName( int column ) throws IllegalStateException {
/** * Assegura que o banco de dados conexão está disponível */
if( !conectadoAoDB ) {
throw new IllegalStateException( "Não está conectado ao Banco de Dados" );
}
try {
return metaDados.getColumnName( column + 1 );
}
catch( SQLException sqlE ) {
sqlE.printStackTrace();
}
/** * Se ocorrerem os problemas acima, retorna string vazia para nome de coluna */
return "";
} // fim do método getColumnName
/** * Retorna o número de linhas em ResultSet */
public int getRowCount() throws IllegalStateException {
/** * Assegura que o banco de dados conexão está disponível */
if( !conectadoAoDB ) {
throw new IllegalStateException( "Não está conectado ao Banco de Dados" );
}
return numeroDeLinhas;
} // fim do método getRowCount
/** * Obtém o valor na linha e coluna especificadas */
public Object getValueAt( int row, int column ) throws IllegalStateException {
/** * Assegura que o banco de dados conexão está disponível */
if( !conectadoAoDB ) {
throw new IllegalStateException( "Não está conectado ao Banco de Dados" );
}
/** * Obtém o valor na linha e na coluna especificadas do ResultSet */
try {
resultSet.absolute( row + 1);
return resultSet.getObject( column + 1 );
}
catch( SQLException sqlE ) {
sqlE.printStackTrace();
}
/** * Se ocorrerem os problemas acima, retorna objeto string vazio */
return "";
} // fim do método getValueAt
/** * Configura a nova string de consulta de banco de dados */
public void setQuery( String query ) throws SQLException, IllegalStateException {
/** * Assegura que o banco de dados conexão está disponível */
if( !conectadoAoDB ) {
throw new IllegalStateException( "Não está conectado ao Banco de Dados" );
}
/** * Especifica a consulta e a executa */
resultSet = statement.executeQuery( query );
/** * Obtém os metadados para o ResultSet */
metaDados = resultSet.getMetaData();
/** * Determina o número de linhas em ResultSet */
resultSet.last(); // move para a última linha
numeroDeLinhas = resultSet.getRow(); // obtém o número de linha
/** * Notifica a JTable de que modelo foi alterado */
fireTableStructureChanged();
} // fim do método setQuery
/** * Fecha Statemente e Connection */
public void disconectaDoDB() {
if( conectadoAoDB ) {
/** * Fecha Statement e Connection */
try {
resultSet.close();
statement.close();
connection.close();
}
catch( SQLException sqlE ) {
sqlE.printStackTrace();
}
finally { // atualiza status de conexão de banco de dados
conectadoAoDB = false;
}
}
}
}
/* ####################################################
* Nome do Aplicativo: Tabela
* Nome do Arquivo: ExibeResultadoConsultas.java
* Nome do Projeto: Consutlando Banco de Dados Books
* Plataforma: Windows, Linux, Mac
* Função do Aplicativo: Exibe o conteúdo da tabela Authors no banco de dados de livros
* @author Lucas Santos
* Criado em 17/06/2012, 23:06:02
* ####################################################
*/
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.sql.SQLException;
import java.util.regex.PatternSyntaxException;
import javax.swing.*;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class ExibeResultadoConsultas extends JFrame {
/** * URL de banco de dados, nome de usuário e senha */
static final String DATABASE_URL = "jdbc:mysql://localhost/books";
static final String USERNAME = "root";
static final String PASSWORD = "";
/** * A consulta padrão recupera todos os dados da tabela Authors */
static final String DEFAULT_QUERY = "SELECT * FROM Authors";
private ResultSetTableModel tableModel;
private JTextArea queryArea;
/** * Cria o ResultSetTableModel e GUI */
public ExibeResultadoConsultas() {
super( "Exibindo Resultado de Consultas" );
/** * Cria o ResultSetTableModel e exibe a tabela de banco de dados */
try {
/** * Cria o TableModel para resultados da consulta SELECT * FROM Authors */
tableModel = new ResultSetTableModel( DATABASE_URL, USERNAME, PASSWORD, DEFAULT_QUERY );
/** * Configura JTextArea em que o usuário digita consultas */
queryArea = new JTextArea( DEFAULT_QUERY, 3, 100 );
queryArea.setWrapStyleWord( true );
queryArea.setLineWrap( true );
JScrollPane scrollPane = new JScrollPane( queryArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
/** * Configura o JButton para enviar consulta */
JButton botaoEnviar = new JButton( "Enviar Consulta" );
/** * Cria o Box para gerenciar o posicionamento da queryArea e do botaoEnviar na GUI */
Box boxNorte = Box.createHorizontalBox();
boxNorte.add( scrollPane );
boxNorte.add( botaoEnviar );
/** * Cria JTAble com base no tableModel */
JTable resultTable = new JTable( tableModel );
JLabel lblFiltro = new JLabel( "Filtros:" );
final JTextField textoFiltro = new JTextField();
JButton botaoFiltro = new JButton( "Aplicar Filtro" );
Box boxSul = Box.createHorizontalBox();
boxSul.add( lblFiltro );
boxSul.add( textoFiltro );
boxSul.add( botaoFiltro );
/** * Posiciona os componentes GUI no painel de conteúdo */
add( boxNorte, BorderLayout.NORTH );
add( new JScrollPane( resultTable ), BorderLayout.CENTER );
add( boxSul, BorderLayout.SOUTH );
/** * Cria evento ouvinte para botaoEnviar */
botaoEnviar.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
/** * Passa consulta para modelo de tabela */
try {
/** * Realiza uma nova consulta */
tableModel.setQuery( queryArea.getText() );
}
catch( SQLException sqlE ) {
JOptionPane.showMessageDialog( null, sqlE.getMessage() , "Erro no Banco de Dados", JOptionPane.ERROR_MESSAGE );
/** * Tenta recuperar a partir da consulta de usuário inválida executando consulta padrão */
try {
tableModel.setQuery( DEFAULT_QUERY );
queryArea.setText( DEFAULT_QUERY );
}
catch( SQLException sqlE2 ) {
JOptionPane.showMessageDialog( null, sqlE2.getMessage() , "Erro no Banco de Dados", JOptionPane.ERROR_MESSAGE );
/** * Assegura que a conexão d ebanco de dados está fechada */
tableModel.disconectaDoDB();
System.exit( 1 ); // termina o aplicativo
} // fim do catch interno
} // fim do catch externo
} // fim do método actionPerformed
} ); // fim do método addActionListener e da classe interna
final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>( tableModel );
resultTable.setRowSorter( sorter );
setSize( 500, 250 );
setVisible( true );
/** * Cria ouvinte para botaoFiltro */
botaoFiltro.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
/** * Passa o texto do filtro para o ouvinte */
String texto = textoFiltro.getText();
if( texto.length() == 0 )
sorter.setRowFilter( null );
else {
try {
sorter.setRowFilter( RowFilter.regexFilter( texto ) );
}
catch( PatternSyntaxException psE ) {
JOptionPane.showMessageDialog( null, "Regex Pattern Ruim" , "Regex Pattern Ruim", JOptionPane.ERROR_MESSAGE );
}
} // fim do else
} // fim do método actionPerformed
} ); // fim do método addActionListener e da classe interna
}
catch( SQLException sqlE ) {
JOptionPane.showMessageDialog( null, sqlE.getMessage() , "Erro no Banco de Dados", JOptionPane.ERROR_MESSAGE );
/** * Assegura que a conexão d ebanco de dados está fechada */
tableModel.disconectaDoDB();
System.exit( 1 ); // termina o aplicativo
}
/** * Dispõe da janela quando o usuário fecha o apicativo( isso sobresvreve o padrão de HIDE_ON_CLOSE */
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
/** * Assegura que a conexão de banco de dados é fechada quando usuário fecha o apicativo */
addWindowListener( new WindowAdapter() {
/** * Desconecta-se do banco de dados e sai quando a janela for fechada */
public void windowClosed( WindowEvent event ) {
tableModel.disconectaDoDB();
System.exit( 0 );
} // fim do método windowClosed
} ); // fim do método addWindowListener e da classe interna
} // fim do construtor
public static void main( String[] args ) {
new ExibeResultadoConsultas();
}
}
), vou tentar respondê-las.