Fala pessoal, eu estou tentando fazer uma tela de consulta de usuários(uso java), porém eu gostaria de no campo de pesquisa tenha um auto-complete, se a pessoas digitar 4 letras o campo vai dar sugestões ou atualizar a tabela para apenas mostrar dados que contenham aquilo digitado, semelhante a um filtro, mas atualizado na hora em que o usuário esta digitando. Eu gostaria de saber se isso é possível, e se alguém teria alguns artigos sobre isso, eu procurei um dia todo e não achei nada que pudesse ajudar. Desde já agradeço!
Basicamente você tem que ter um TableModel
próprio que renderize sua coleção de objetos.
Aí, a medida que você vai preenchendo aquele campo, você filtra essa coleção de objetos e manda o TableModel
redesenhar o conteúdo da JTable
com o método fireTableDataChanged
Eu acho que mais ou menos entendi, mas to tendo problema na hora de listar meus dados na tabela, to utilizando o hibernate e AbstractTableModel, segue abaixo os codigos
public class UsuarioTableModel extends AbstractTableModel {
private final static long serialVersionUID = 1L;
private static final int CODIGO = 0;
private static final int NOME = 1;
private static final int CPF = 2;
private int row = 0;
private List<Usuario> valores;
public UsuarioTableModel(List<Usuario> valores) {
this.valores = new ArrayList<>(valores);
fireTableStructureChanged();
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public String getColumnName(int column) {
if (column == CODIGO)
return "Código";
if (column == NOME)
return "Nome";
if (column == CPF)
return "CPF/Cnpj";
throw new IllegalArgumentException("Coluna não existe.");
}
@Override
public int getRowCount() {
return valores.size();
}
/** Retorna o número da linha selecionada */
public int getSelectedRow() {
return row;
}
@Override
public Object getValueAt(int row, int column) {
this.row = row; // Recebe o numero da linha selecionada
Usuario testeUsuario = valores.get(row);
if (testeUsuario == null)
return null;
switch (column) {
case CODIGO:
return testeUsuario.getUsuId();
case NOME:
return testeUsuario.getUsuDesc();
case CPF:
return testeUsuario.getTipo();
}
throw new IllegalArgumentException("Coluna não existe.");
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) { // imutável
throw new UnsupportedOperationException("Edição não é suportada.");
}
void addAll(Collection<Usuario> usuario) {
valores.addAll(usuario);
fireTableDataChanged();
}
void clear() {
valores.clear();
fireTableDataChanged();
}
Usuario get(int row) {
return valores.get(row);
}
}
E esse é o modo como estou tentando popular, consigo só pegar o nome e quantidade de campos(o model no caso), mas nenhum dado
private JTable getTableCliente() {
if (tableUsuario == null) {
tableUsuario = new JTable();
tableUsuario.setAutoCreateRowSorter(true);
tableUsuario.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tableUsuario.setModel(new UsuarioTableModel(new ArrayList<Usuario>()));
tableUsuario.getColumnModel().getColumn(0).setPreferredWidth(20);
tableUsuario.getColumnModel().getColumn(1).setPreferredWidth(150);
tableUsuario.getColumnModel().getColumn(2).setPreferredWidth(40);
}
return tableUsuario;
}
tentei desta outra forma também mas da erro
private void populaTabel(JTable table) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("fca");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
TypedQuery<Usuario> query = em.createQuery("SELECT u FROM Usuario u", Usuario.class);
List<Usuario> usuarios = query.getResultList();
for(Usuario usuario: usuarios) {
table.getValueAt(usuario.getTipo(), 1);
}
}
Não crie uma nova lista, use a lista passada por parâmetro e no constutor não precisa chamar o método fireTableStructureChanged()
.
Deixe o construtor do UsuarioTableModel
assim:
public UsuarioTableModel(List<Usuario> valores) {
this.valores = valores; // não cria uma nova lista, usa o mesmo objeto
}
Adiciona o seguinte método ao UsuarioTableModel
:
public void atualizar(List<Usuario> valores) {
this.valores = valores; // não cria uma nova lista, usa o mesmo objeto
fireTableDataChanged();
}
Modifica o seu método populaTabel
dessa forma:
private void populaTabel(JTable table) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("fca");
EntityManager em = emf.createEntityManager();
TypedQuery<Usuario> query = em.createQuery("SELECT u FROM Usuario u", Usuario.class);
List<Usuario> usuarios = query.getResultList();
UsuarioTableModel model = (UsuarioTableModel) table.getModel();
model.atualizar(usuarios);
}
Caraca, deu certo! Onde exatamente tava o meu erro? e por que essa simples modificação fez funcionar? eu sou meio iniciante no java e sempre tive problemas pra entender a JTable, mas agradeço muito a sua ajuda!!
O maior erro estava aqui:
List<Usuario> usuarios = query.getResultList();
for(Usuario usuario: usuarios) {
table.getValueAt(usuario.getTipo(), 1);
}
Você só estava chamando o getValueAt passando uma linha e coluna.
Não faz sentido.
Esse método é chamado pela JTable a medida que ela vai desenhando as células visíveis na tela.
E a outra mancada era essa:
this.valores = new ArrayList<>(valores);
Pra que criar uma nova lista de você já está recebendo a lista por parâmetro?
É desperdício de memória criar outra copiando o conteúdo.
Entendi, consegui aplicar aqui e com mais algumas alterações funcionou como eu estava precisando, eu só continuo com o problema do auto-refresh enquanto o usuário digita, a ideia era não ter um botao de pesquisar, e sim a medida q fosse sendo digitado fosse sendo filtrado e já atualizando a tabela, mas não consegui implementar isso ainda, segue uma das minhas tentativas:
//Metodo principal onde popula as tabelas
public <T> ConsultasSql(JTable table, Class<T> classe, String className, String search, JComboBox<?> box,JTextField field) {
logger.info("Populando a tabela");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("fca");
EntityManager em = emf.createEntityManager();
List<T> classes;
if(field.getText().trim().equals("")) {
TypedQuery<T> queryAll = em.createQuery("SELECT u FROM "+className+" u", classe);
classes = queryAll.getResultList();
}else {
TypedQuery<T> queryLike = em.createQuery("SELECT u FROM "+className+" u WHERE "+box.getSelectedItem().toString().trim().toLowerCase()+" LIKE '%"+search+"%'", classe);
classes = queryLike.getResultList();
}
if(classe == Usuario.class) {
UsuarioTableModel model = (UsuarioTableModel) table.getModel();
model.atualizar(classes);
} else if(classe == Vendedor.class) {
VendedorTableModel model = (VendedorTableModel) table.getModel();
// model.atualizar(classes);
} else if(classe == Produto.class) {
ProdutoTableModel model = (ProdutoTableModel) table.getModel();
// model.atualizar(classes);
} else if(classe == Municipio.class) {
MunicipioTableModel model = (MunicipioTableModel) table.getModel();
// model.atualizar(classes);
}
}
//Este método pegaria o evento do click no teclado, mas não consegui achar uma lógica que pudesse fazer sentido
private static void teclasPressionadas(JTextField field) {
field.addKeyListener(new KeyAdapter() {
});
}