Exibir Dados

24 respostas
T

Olá
Sou iniciante em JAVA, atualmente programo em Delphi, então, pretendo aprender essa linguagem fantástica, porém estou encontrando dificuldades no que se refere a exibir os registros num grid ou tabela, no Delphi é muito simples, mas no JAVA, pra quem não conhece nada, é meio complicadinho…
Então para iniciar os meus estudos criei um banco em MySQL com uma tabela, banco ESTUDO, tabela cliente com dois campos
Tabela Cliente:
Codigo INT
Nome VARCHAR

Gostaria de saber como posso fazer para mostrar os dados dessa tabela dinamicamente, como eu já recebi algumas dicas aqui no próprio fórum, é desaconselhado o uso de DefaultTableModel, então pretendo aprender da forma correta, porém, com os exemplos encontrados, não consegui sair do lugar…

Pretendo fazer essa tabela aparecer através do NetBeans, mas, se for mais eficiente para meu aprendizado, pode ser no JCreator.

Se os colegas de fórum puderem me dar uma luz, ficarei muito agradecido…

Abraço…

24 Respostas

Eric_Yuzo

http://www.guj.com.br/posts/list/30/147521.java#799170

http://www.guj.com.br/posts/list/132698.java#714736

http://www.guj.com.br/posts/list/225793.java

Eis alguns exemplos comentados.

Pode usar o ObjectTableModel do Marky.Vasconcelos. Mas se não sabe como funciona um table model, é interessante aprender como funciona para depois usar o ObjectTableModel.

Você pode criar a tela no netbeans sem problemas. Mas ao invés de usar o Default, deve setar seu modelo com:

table.setModel(new SeuTableModel());
T

Olá
Tentei fazer pelo método do primeiro link
http://www.guj.com.br/posts/list/30/147521.java#799170
mas está dando erro na linha do bloco:

public String getColumnName(int columnIndex){ if(columnIndex == CODIGO)return "Código"; if(columnIndex == NOME) return "Nome"; }
dá a mensagem:
missing return statement

o que estaria faltando nesse caso?

Eric_Yuzo

Retorne uma string vazia no final.

public String getColumnName(int columnIndex){ if(columnIndex == CODIGO)return "Código"; if(columnIndex == NOME) return "Nome"; return ""; }O que ocorre é o seguinte, se a coluna for a do código, retorna “Código”, se for a do nome, retorna “Nome”, e se não for nenhum deles, não está retornando nada. Por isso que o compilador está reclamando.

T
Antes de mais nada, obrigado pela atenção Eric. Bom, aquele erro não ocorre mais, criei 3 arquivos de classes, baseados no exemplo seu que tem disponível no link que você sugeriu, bem, ficou dessa forma: Arquivo Tabelas.java
import javax.swing.*;
 import javax.swing.table.TableModel;
 import javax.swing.table.AbstractTableModel;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.*;


public class Tabelas extends AbstractTableModel{

	private static final int CODIGO = 0;
	private static final int NOME = 0;

	private List<Cliente>valores;


    public Tabelas(Collection<Cliente> valores) {
    	this.valores = new ArrayList<Cliente>(valores);
    }

    public int getRowCount(){
    	return valores.size();
    }

    public int getColumnCount(){
    	return 5;
    }

    public String getColumnName(int columnIndex){
    	if(columnIndex == CODIGO)return "Código";
    	if(columnIndex == NOME) return "Nome";
    	return "";
    }

    public Object getValueAt(int row, int column){

    	Cliente cli = valores.get(row);
    	if(column == CODIGO) cli.getCodigo();
    	if(column == NOME) cli.getNome();
    	return "";
    }

    public Class getColumnClass(int columnIndex){
    	if(columnIndex == CODIGO)return Integer.class;
    	if(columnIndex == NOME)return String.class;
		return String.class;
    }

    public void add(Cliente cliente){
    	valores.add(cliente);
    	fireTableRowsInserted(valores.size()-1, valores.size()-1);
    }

    public List<Cliente> getClientes(){
    	return Collections.unmodifiableList(valores);
    }
}
Arquivo Cliente.java
public class Cliente {

	private Integer codigo;
	private String nome;

    public Integer getCodigo(){
    	return codigo;
    }

    public void setCodigo(Integer codigo){
    	this.codigo = codigo;
    }

    public String getNome(){
    	return nome;
    }

    public void setNome(String nome){
    	this.nome = nome;
    }
}
Arquivo Principal.java -> é neste que pretendo mostrar a tabela:
import java.awt.*;
 import javax.swing.*;
 import java.util.*;


public class Principal extends JFrame {

	private JTable tabela;

    public Principal() {
    	super("Teste de Tabela");
    	initialize();
    }

    private void initialize(){
    	setSize(600, 400);
    	setDefaultCloseOperation(EXIT_ON_CLOSE);
    	getContentPane().add(new JScrollPane(getTbltabela()));
    }

    private JTable getTbltabela(){
    	if(tabela == null){
    		tabela = new JTable();
    		tabela.setModel(new Tabelas());
    	}
    	return tabela;
    }

    private Tabelas getModel(){
    	if(model == null){
    		model = (Tabelas) getTbltabela().getModel();
    	}
    	return model;
    }
}

Bom, pretendo pegar os dados do meu banco estudo e da tabela Cliente qe tem 2 campos: codigo e nome, que são feitos em mysql, sem querer ser muito abusado, o que está faltando neste último arquivo, e, qual seria o próximo passo para exibir os dados da minha tabela do banco nesta JTable?
Realmente, não sei como prosseguir neste momento, estou fazendo com o JCreator o meu pequeno Form.
Se for possível, verificar o meu código e dizer o que estou errando ou o que poderia ser melhorado.. :D

Abraço...

Eric_Yuzo

A única coisa que pode causar um efeito indesejado é o método getColumnCount, que está retornando 5, quando seu cliente tem apenas código e nome. Neste caso o correto é que retorne 2, caso contrário você terá uma tabela com código, nome e mais três colunas vazias.

E por convenção é interessante nomear o TableModel como ClientesTableModel, assim fica claro para qualquer um que veja suas classes, que ela se trata de um table model próprio para clientes. Do jeito que está, não fica claro que a classe Tabelas seja um table model, ainda mais de clientes.

O próximo passo é carregar um objeto do tipo Cliente com as informações do banco de dados e passá-lo para o table model pelo método add do seu table model.

T
Olá, alterei agora, seguindo a idéia do seu exemplo: [url]http://www.guj.com.br/java/225793-exemplo-de-tablemodel[/url] ficou assim:
import java.awt.*;
 import javax.swing.*;
 import java.util.*;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import java.sql.*;

public class Principal extends JFrame {
	private static final long serialVersionUID = 1L;

	private JTable tblCliente;
	private ClienteTableModel model;


	public Principal(){
		super("Teste com JTable");
		initialize();
	}

	private void initialize(){
		setSize(800, 600);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		getContentPane().add(new JScrollPane(getTblClientes()));
	}

	private JTable getTblClientes(){
		if(tblCliente == null){
			tblCliente = new JTable();
			tblCliente.setModel(new ClienteTableModel());
		}
		return tblCliente;
	}

	private ClienteTableModel getModel(){
		if(model == null){
			model = (ClienteTableModel) getTblClientes().getModel();
		}
		return model;
	}

	private Cliente getCliente(){
		Cliente cliente = new Cliente();
		cliente.setCodigo(1);
		cliente.setNome("Teste");
		return cliente;
	}

	private void addCliente(){
		getModel().addCliente(getCliente());
	}

	public static void main(String[] args){
		EventQueue.invokeLater(new Runnable(){
			@Override
			public void run(){
			new Principal().setVisible(true);
			}
		});
	}
}

Mas, não consegui encontrar uma maneira de fazer um select e jogar para a tabela...e a minha tabelinha de estudos tem apenas dois campos...

Eric_Yuzo

taraciuk:
Mas, não consegui encontrar uma maneira de fazer um select e jogar para a tabela…e a minha tabelinha de estudos tem apenas dois campos…

Se você não sabe como fazer a conexão com o banco de dados, faça uma pesquisa sobre JDBC. Aqui no GUJ tem alguns artigos e vários tópicos sobre o assunto: http://www.guj.com.br/articles/7

Se já souber trabalhar com JDBC e o problema está em como carregar os resultado da consulta na JTable. Você pode carregar um objeto Cliente com o resultado da pesquisa e passar para o table model pelo método add, que recebe um cliente.

Edit: Achei um exemplo que carrega um objeto “Usuario” para cada resultado da consulta e retorna uma lista: http://www.guj.com.br/java/225388-coletando-dados-de-um-select#1154746
Se quiser pode até criar um método em seu table model para adicionar a lista de clientes de uma vez só.

T

E, assim, como eu jogo o resultado do select do exemplo que você citou no último post para a JTable que criei baseado na que vc fez como exemplo ?

Ainda nao consegui me encontrar no código…
Talvez seja o efeito de ter aprendido a programar em Delphi antes…

Eric_Yuzo

No seu table model, o responsável por adicionar um cliente na tabela é o método “add(Cliente)”. Então bastaria carregar os dados do banco em um objeto cliente e adicionar ao model por este método.

tableModel.add(clienteRecuperado);

Como a consulta no banco pode retornar vários resultados, você pode implementar um método que recebe uma lista de clientes, para evitar de ficar escrevendo laços para adicioná-los:

// Seu table model public void addAll(List<Cliente> clientes) { int oldSize = getRowCount(); valores.addAll(clientes); fireTableRowsInserted(oldSize, getRowCount() - 1); }Assim pode passar a lista toda para o método addAll.

T

Cara, acho que estou te enchendo já…rsrssr
Tentei montar seguindo os exemplos, mas não consegui sozinho não.

Se puder me dar uma luz, dizer onde estou errando.

Abraço…

Eric_Yuzo

Para facilitar a adição dos clientes no seu table model, crie o método que recebe uma lista:

Eu mesmo:
public void addAll(List<Cliente> clientes) { int oldSize = getRowCount(); valores.addAll(clientes); fireTableRowsInserted(oldSize, getRowCount() - 1); }

Em sua classe principal, tem o método “listarClientes”, que retorna uma lista de clientes, que é exatamente o que o método acima recebe por parâmetro. Para passá-los para a tabela, você vai fazer algo mais ou menos assim:

getModel().addAll(listarClientes()); // "getModel" retorna o seu table model, "addAll" vai adicionar ao model a lista de clientes que será retornada pelo método "listarClientes".Onde este método vai ser chamado depende de sua necessidade. Pode ser por exemplo a partir da ação de um botão.

Quanto a conexão, procure fechar o statement e a conexão quando não for usar mais. Você pode criar, também, uma classe para trabalhar com a conexão: http://download.oracle.com/javase/tutorial/jdbc/basics/index.html.

T

Cara, agora apareceu algo, mas, apareceu somente a primeira linha de dados da tabela, deu a msg:
Comprimento inválido de cadeia de caracteres ou de buffer

Acho que é no while, o que pode ser feito neste caso?

public List<Cliente> listCliente(){
		List<Cliente>linhas = new ArrayList<Cliente>();

		try{
			String url = "jdbc:odbc:estudo";
			String usuario = "root";
			String senha = "root";
			Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
			Connection con;
			con = DriverManager.getConnection(url, usuario, senha);
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery("Select CodCliente, NomeCliente from Cliente");

			while(rs.next()){
				Cliente cli = new Cliente();
				cli.setCodigo(rs.getInt("CodCliente"));
				cli.setNome(rs.getString("NomeCliente"));
				linhas.add(cli);

			}
		}
			catch(Exception e){
				JOptionPane.showMessageDialog(null,e,"Mensagem",JOptionPane.ERROR_MESSAGE);
			}
			return linhas;
	}
Eric_Yuzo

Por esta mensagem não sei te dizer de onde vem o erro. Coloca um printStackTrace no catch para poder ver qual é a exceção.

catch(Exception e){ e.printStackTrace(); JOptionPane.showMessageDialog(null,e,"Mensagem",JOptionPane.ERROR_MESSAGE); }

T

Na saída do JCreator saiu isso:

<blockquote>java.sql.SQLException: [Microsoft][ODBC Driver Manager] Comprimento inválido de cadeia de caracteres ou de buffer

at sun.jdbc.odbc.JdbcOdbc.createSQLException(JdbcOdbc.java:6957)

at sun.jdbc.odbc.JdbcOdbc.standardError(JdbcOdbc.java:7114)

at sun.jdbc.odbc.JdbcOdbc.SQLGetDataString(JdbcOdbc.java:3907)

at sun.jdbc.odbc.JdbcOdbcResultSet.getDataString(JdbcOdbcResultSet.java:5698)

at sun.jdbc.odbc.JdbcOdbcResultSet.getString(JdbcOdbcResultSet.java:354)

at sun.jdbc.odbc.JdbcOdbcResultSet.getString(JdbcOdbcResultSet.java:411)

at Principal.listCliente(Principal.java:99)

at Principal.addAll(Principal.java:71)

at Principal.access$000(Principal.java:27)

at Principal$2.actionPerformed(Principal.java:119)

at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)

at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)

at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)

at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)

at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)

at java.awt.Component.processMouseEvent(Component.java:6267)

at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)

at java.awt.Component.processEvent(Component.java:6032)

at java.awt.Container.processEvent(Container.java:2041)

at java.awt.Component.dispatchEventImpl(Component.java:4630)

at java.awt.Container.dispatchEventImpl(Container.java:2099)

at java.awt.Component.dispatchEvent(Component.java:4460)

at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)

at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)

at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)

at java.awt.Container.dispatchEventImpl(Container.java:2085)

at java.awt.Window.dispatchEventImpl(Window.java:2478)

at java.awt.Component.dispatchEvent(Component.java:4460)

at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)

at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)

at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)

at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)</blockquote>

Era isso ?

Eric_Yuzo

Tenta ver o tamanho do campo no BD, pode ser que o registro esteja além dos limites especificados. Apesar que você só está tentando recuperar algo já cadastrado.

Copia a primeira linha do erro e cola no google pra ver se não acha ninguém que teve o mesmo problema.

T

No Banco o tamanho dos campos é inteiro(10), varchar(45).
Agora, se eu coloco assim:

while(rs.next()){
			Cliente cli = new Cliente();
			[color=red]Cliente nome = new Cliente();[/color]
			cli.setCodigo(rs.getInt("CodCliente"));
			cli.setNome(rs.getString("NomeCliente"));
			linhas.add(cli);

		}

Adicionando essa linha em vermelho no while, os dados aparecem e não ocorre o erro.
Pesquisando no google, encontrei uma pesquisa exatamente com o meu erro, mas nao mostra a solução, apenas diz que conseguiu resolver:
http://www.guj.com.br/java/221519-formulario-e-sql

Tem idéia do que poderia ser?

Cara, obrigado pela tua paciência e atenção às minhas dúvidas.

adriano_si

Estranho… porque essa linha em vermelho não fez nada demais… Qual BD é esse que estás usando ??? Pela URL não consegui identificar…

Tenta alterar os nomes das Colunas… Ao que tudo indica é infra, teu código está correto…

Eric_Yuzo

Sinceramente não sei te dizer qual poderia ser o problema.

E entendi menos ainda porque criar outro cliente na memória e não fazer nada com ele tenha resolvido o problema.

Já tentou debugar o código?

T

Estou utilizando o MySQL 5
Sim, foi o que imaginei, que esta linha não está fazendo nada no meio do while, mas, se eu tiro ela, apresenta o erro que postei.

java.sql.SQLException: [Microsoft][ODBC Driver Manager] Comprimento inválido de cadeia de caracteres ou de buffer

Levando em conta que o meu banco tem somente uma tabela e com dois campinhos somente…pois estou tentando aprender JAVA.

Estou utilizando o JCreator, pra debugar teria que ser pelo NetBeans?
Comecei pelo JCreator porque achei que o aprendizado se torna mais facil, fazendo tudo na mão, depois, passo a utilizar o NetBeans ou outra IDE.

adriano_si

to achando estranha essa URL de conexão do MySQL

String url = "jdbc:mysql://localhost:3306/teubd";   
String usuario = "root";   
String senha = "root";   
Class.forName("com.mysql.jdbc.Driver");

tenta colocar isso na tua conexão…

Eric_Yuzo

Nunca usei o JCreator, mas imagino que ele permita que seja feito debug no código sim.

Pensei que você estivesse usando Access. Se está usando MySQL, não precisa usar o driver ODBC, pode usar o Driver do próprio MySQL: http://www.mysql.com/products/connector/.

Baixe o jar do MySQL Connector e adicione ao seu classpath. A diferença no código fica apenas para a url e o driver:

String url = "jdbc:mysql://localhost:3306/estudo"; String usuario = "root"; String senha = "root"; Class.forName("com.mysql.jdbc.Driver");

T

Deu certo… era a string de conexão, instalando o JConnector e colocando como sugerido funcionou…
Finalmente consegui ver uma JTable que não seja DefaultTableModel mostrar os dados na tabelinha.

Eric Yuzo e adriano_si obrigado pela ajuda, sozinho eu não conseguiria…

Bem, o que vocês recomendariam para eu dar continuidade nos meus estudos ?
Quero aprender a fazer uma telinha de cadastro antes de voltar as aulas rsrsrsr.

Abraço!!!

Eric_Yuzo

Opa, não tem nada. Nós estamos aqui pra isso.

Quanto ao que estudar, acho que depende muito do que você já sabe. Se não estiver de bem com orientação a objetos, acho que é aí que deveria focar.

O que vou dizer agora não é a verdade absoluta para todos os casos, mas aconteceu comigo. Quando comecei a estudar java, eu o fiz em função do meu TCC do curso técnico, basicamente coloquei em mente o que fazer e fui correndo atrás apenas de como resolver os problemas no google. O resultado foi um TCC praticamente estruturado (mesmo feito em java), praticamente zero de OO e sem nenhum padrão, apesar de cumprir as funções que deveria. Tinha os erros de sempre, toda a lógica de negócio na classe visual, DefaultTableModel (como isso me deu trabalho). No começo estava tudo tranquilo, mas conforme tinha que mudar algo, era uma dor de cabeça desgraçada. Por isso agora no meio do ano resolvi meio que começar do zero, peguei as apostilas de OO e estrutura de dados da Caelum, li os livros “Head First - Java” da Kathy Sierra e o “Core Java I - Fundamentals” do Cay Horstmann (gostei muito deste livro). E agora nas férias da faculdade comecei a ler o livro de Design Patterns do Head First.

Esses são os únicos livros que posso comentar (e recomendo a leitura), pois são os únicos que li/estou lendo, hehe. Quanto aos assuntos, acho mais interessante aprender bem os conceitos e, claro, não deixar de praticar no código também, fazer a telinha de cadastro e tal, mas sempre trabalhando os conceitos aprendidos. O importante é se divertir. :smiley:

Bom, falei tudo que falei apenas para mostrar os erros que cometi, que é o mesmo erro de muitos iniciantes. Agora respondendo a sua pergunta, como você disse no primeiro post que é novo em java, mas já programa, indico que avalie o nível que você considera estar e procurar referência de livros para este nível. É bem melhor que aprender as coisas aleatoriamente.

Boa sorte e bons estudos…

adriano_si

Faço minhas as palavras do Eric… por conta de trabalho da facul, atropelei os estudos de conceitos fundamentais em Java…

Como você veio do Delphi, a lógica e a sequencia de estruturas em Programação você já deve ter… Estude bastante OO e os Padrões de Projeto, esqueça um pouco a parte gráfica do Java e parta pra códigos puros mesmo, a fim de praticar os conceitos do que vai aprendendo…

Meu amigo, isso MUITO IMPORTANTE, não atropele seus estudos, senão podes sentir os efeitos mais na frente, eu tô correndo atrás do Prejuízo, assim como Eric…

Abs [] e bons estudos…

Criado 13 de dezembro de 2010
Ultima resposta 29 de dez. de 2010
Respostas 24
Participantes 3