jTable

23 respostas
S

Olá, pode ser uma pergunta meio tosca mas não estou conseguindo mesmo, acho que nem entendendo, mas...

Tenho uma tabela onde tem 3 colunas e duas linhas, consigo selecionar campo a campo e visualizar, mas não consigo selecionar a linha toda e visualizar todos os dados dela.

import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;

public class ExemploJTable extends JFrame implements ActionListener {
	JTable tabela;
	DefaultTableModel modelo;
	JButton btn;
        
	public ExemploJTable() {
			String colunas[] = {"Nome", "Endereço", "Telefone"};
			String dados[][] = { {"João", "Rua Tal", "4444"}, {"Maria", "Av Tal", "3333"} };
			modelo = new DefaultTableModel(dados, colunas);
			tabela = new JTable(modelo);
			JScrollPane sp = new JScrollPane(tabela);
			add(sp, "Center");
		
			btn = new JButton("Mostrar");
			btn.addActionListener(this);
			add(btn, "South");
			pack();
			setVisible(true);
	}
        
public void actionPerformed(ActionEvent evt) {
    
                int linha = tabela.getSelectedRow();
		int coluna = tabela.getSelectedColumn();
		if (linha != -1 && coluna != -1) {
			String dado = (String) tabela.getValueAt(linha, coluna);
			JOptionPane.showMessageDialog(this, dado);
		} else {
			JOptionPane.showMessageDialog(this, "Nenhuma célula selecionada");
		}

	}

	public static void main(String[] args) {
		new ExemploJTable();
	}
}
Se clicar na primeira linha e na primeira coluna, visualizo o que tem dentro desta celula, mas não consigo visualizar todas as celulas desta coluna, alguém pode me dar uma luz, por favor.

Obrigada desde já.

Sandra.

23 Respostas

thiagofesta

É que você pegou a linha selecionada e a coluna selecionada…
falça assim:

public void actionPerformed(ActionEvent evt) { int linha = tabela.getSelectedRow(); if (linha != -1) { String dado = (String) tabela.getValueAt(linha, 0) + " - " ; dado += (String) tabela.getValueAt(linha, 1) + " - "; dado += (String) tabela.getValueAt(linha, 2); JOptionPane.showMessageDialog(this, dado); } else { JOptionPane.showMessageDialog(this, "Nenhuma célula selecionada"); } }

S

Muito obrigada.

Você é um anjo.

É isso mesmo que estava precisando, mas tem outra coisa, e se eu precisar selecionar as duas linha ao mesmo tempo, tem como?

int total = 0.0;
        for (int row = 0; row < this.jTable.getRowCount(); row++) {
            int product = 1;
            for (int col = 0; col < this.jTable.getColumnCount(); col++) {
                int value = ((int) this.jTable.getValueAt(row, col));
                product = (product * value);
            }
            total += product;
            System.out.println(total);
        }
              
        this.totalCube.setText();
}
mas não deu certo, dá um erro enorme.
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        at Tabela.Tabela.jButtonCalcularActionPerformed(Tabela.java:195)
        at Tabela.Tabela.access$000(Tabela.java:16)
        at Tabela.Tabela$1.actionPerformed(Tabela.java:69)
        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:6038)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3260)
        at java.awt.Component.processEvent(Component.java:5803)
        at java.awt.Container.processEvent(Container.java:2058)
        at java.awt.Component.dispatchEventImpl(Component.java:4410)
        at java.awt.Container.dispatchEventImpl(Container.java:2116)
        at java.awt.Component.dispatchEvent(Component.java:4240)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
        at java.awt.Container.dispatchEventImpl(Container.java:2102)
        at java.awt.Window.dispatchEventImpl(Window.java:2429)
        at java.awt.Component.dispatchEvent(Component.java:4240)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
não sei o que significa isso.

Obrigada novamente.

Sandra.

thiagofesta

Aqui está…

public void actionPerformed(ActionEvent evt) { int linha[] = tabela.getSelectedRows(); if (linha != null) { String dado = ""; for(int i = 0; i < linha.length; i++) { dado += (String) tabela.getValueAt(linha[i], 0) + " - " ; dado += (String) tabela.getValueAt(linha[i], 1) + " - "; dado += (String) tabela.getValueAt(linha[i], 2) + "\n"; } JOptionPane.showMessageDialog(this, dado); } else { JOptionPane.showMessageDialog(this, "Nenhuma célula selecionada"); } }

ViniGodoy

Seu código está ficando muito mais complicado, difícil de entender, redundante e ineficiente por um motivo bem simples: Você está usando o DefaultTableModel.

Não faça isso.

No lugar, aprenda como o JTable funciona e crie o seu próprio model. Abaixo, segue um model de exemplo:
http://www.guj.com.br/posts/list/98452.java

E aqui, dois artigos ótimos sobre o assunto:
http://www.informit.com/articles/article.aspx?p=332278
http://www.informit.com/articles/article.aspx?p=333472

ViniGodoy
thiagofesta:
Aqui está...
public void actionPerformed(ActionEvent evt) {
    int linha[] = tabela.getSelectedRows();
    if (linha != null) {
        String dado = "";
        for(int i = 0; i < linha.length; i++)
        {
            dado += (String) tabela.getValueAt(linha[i], 0) + " - " ;
            dado += (String) tabela.getValueAt(linha[i], 1) + " - ";
            dado += (String) tabela.getValueAt(linha[i], 2) + "\n";
        }
        JOptionPane.showMessageDialog(this, dado);
    } else {
        JOptionPane.showMessageDialog(this, "Nenhuma célula selecionada");
    }
}

Alguns comentários:
1. O getSelectedRows() nunca retorna null, se nenhuma linha for selecionada, ele retornará um array vazio. Isto está escrito no próprio javadoc;
2. É mais fácil usar um for each;
3. Não concatene strings dentro de um loop com a classe String direto. Use um StringBuilder.
4. É mais fácil testar pela exceção da regra antes (code guard), e evitar aninhamento de ifs.
5. Não é correto fazer cast para String do valor retornado pelo getValueAt. O método permite o retorno de qualquer objeto e, dessa forma, você tem chances de obter um ClassCastException. No lugar use o toString(). O que já é feito automaticamente, em cada concatenação.
6. Se um TableModel próprio fosse implementado, você poderia obter o objeto que está em cada linha, ao invés de ler coluna por coluna e obter strings separadas.

O código ajustado (mas infelizmente sem o TableModel) fica assim:

public void actionPerformed(ActionEvent evt) {
   int linhas[] = tabela.getSelectedRows();
   if (linhas.length == 0) {
      JOptionPane.showMessageDialog(this, "Nenhuma célula selecionada");
      return;
   }

   StringBuilder dado = "";
   for(int linha : linhas) {
      dado.append(tabela.getValueAt(linha, 0).append(" - ");
      dado.append(tabela.getValueAt(linha, 1).append(" - ");
      dado.append(tabela.getValueAt(linha, 2)).append("\n");
   }
   JOptionPane.showMessageDialog(this, dado.toString());
}
thiagofesta

ViniGodoy:
Bah, altas coisas que tu disse que eu nem sabia hehe…
Obrigado, contribuiu muito para mim.

Poderia me explicar o motivo disso?

ViniGodoy

Sim. Já expliquei isso há alguns dias atrás.

Dá uma lida nesse tópico:
http://www.guj.com.br/posts/list/107461.java#579994

S

Obrigada a todos.

Ainda não consegui resolver mas antes vou dar uma olhada nos links que vocês me passaram.

Agradeço mesmo desde já.

Tenho é que entender melhor jTable antes para poder resolver.

Obrigada novamente.

Sandra.

S

ViniGodoy,
desculpe a ignorância mas não entendi muito bem o que o Sr. Marcus Zarra quiz dizer, na verdade complicou tudo, o que tinha de conceito em relação a JTable foi pro beleleu.
Estou perdidona no conceito de JTable.
Obrigada.
Sandra Haine.

ViniGodoy

Você conseguiu ler os dois artigos? Viu o exemplo ali?

É… no começo é um choque mesmo.

Você só precisa entender que a JTable só mostra dados e o TableModel diz a table que dados são esses.

S

ViniGodoy,
sim li os dois artigos, mas não entendi muito bem, vou lê-lo com mais calma e bastante atenção, também não sou muito boa em inglês e o entendimento acaba ficando confuso.
Mas obrigada pela sua paciência.
Sandra Haine.

ViniGodoy

Eu perguntei porque um deles estava fora do ar. Não pq tenha desconfiado de você.

Bem, há artigos no GUJ sobre TableModel também. Eu não gosto muito deles, pois não mostram uma situação de uso muito real, mas podem facilitar o seu entendimento inicial e facilitar o seu aprendizado posterior, nos artigos que te mandei.

Estou pensando seriamente em escrever novos artigos para cá, pois esse é um tópico muito frequente e eu já perdi as contas de quantas vezes implorei para o pessoal largar o DefaultTableModel por aqui.

S

Posso ter me expressado mau, desculpe. Todos estão no ar. E em relação ao tópico sobre jTable, acho que seria uma boa, tem vários dias que estou tentando resolver esse meu problema e não consigo, cada forum que entro mais confusa fico, cada explicação vejo que tenho que aprender mais, ler somente não tá dando, fazer os exercícios já fiz vários mas nada de soluções, e compreender respostas sem ao menos saber do que estão falando também não dá.
Acho que você não se lembra de mim, a aguns meses atrás lhe enviei um e-mail particular sobre o mesmo assunto sem sucesso, pediu para que eu postasse a dúvida, antes quiz tentar sozinha mas infeliz da minha parte, realmente não consegui. Tive que pedir ajuda, meus professores não estão me ajudando muito por não ser matéria da faculdade então tô mesmo perdidona.
Mas agradeço se fizer mesmo um tópico explicando em detalhes o que realmente serve, funciona e faz o bendito jTable.
Obrigada novamente.
Sandra Haine.

ViniGodoy

Pois é, o link do outro tópico que eu postei ali em cima, já foi uma resposta bem mais completa que eu dei para outro usuário, que tinha o mesmo problema com o JTable.

Mas fique tranquila. Esse é mesmo um dos mais complexos componentes do Swing. É o preço que se paga por ele ser tão poderoso e flexível.

ViniGodoy

Para facilitar o seu entendimento, montei exatamente o mesmo exemplo que você tentou criar ali em cima, mas usando o TableModel de maneira correta.

Não se assuste com o tamanho do código. Está super comentado.

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

//Primeiro passo, definimos a nossa classe de negócio. No seu caso, Cliente

class Cliente {
    private String nome;
    private String endereco;
    private String telefone;

    public Cliente(String nome, String endereco, String telefone) {
        this.nome = nome;
        this.telefone = telefone;
        this.endereco = endereco;
    }

    public String getNome() {
        return nome;
    }

    public String getEndereco() {
        return endereco;
    }

    public String getTelefone() {
        return telefone;
    }
}

// Segundo passo, criamos um TableModel, que diz ao Swing como essa classe
// deve aparecer numa JTable.

// Note que essa classe apenas descreve para o Swing como os dados, da classe de
// cima, devem ser mostrados. Até agora, nada foi desenhado na tela ainda.
class ClienteTableModel extends AbstractTableModel {

    // Esse model mostrará uma lista de clientes, em forma de tabela.
    // Aqui está nossa lista:
    private List&lt;Cliente&gt; clientes;

    /**
     * Esse construtor inicializa a lista que será exibida com uma lista
     * externa.
     */
    public ClienteTableModel(List&lt;Cliente&gt; clientes) {
        this.clientes = new ArrayList&lt;Cliente&gt;(clientes);
    }

    /**
     * Nesse método, retornamos o número de colunas que a tabela terá. Neste
     * caso, são 3: Nome, endereço e telefone
     * */
    @Override
    public int getColumnCount() {
        return 3;
    }

    /**
     * Aqui, dizemos para o swing o título de cada coluna. Nossa coluna 0 terá o
     * título Nome. A 1 o Endereço e a 2 o Telefone.
     */
    @Override
    public String getColumnName(int column) {
        return new String[] { "Nome", "Endereço", "Telefone" }[column];
    }

    /**
     * Nossa tabela terá uma linha para cada cliente na lista. Por isso, a
     * quantidade de linhas será idêntica ao tamanho da lista de clientes que
     * estamos exibindo.
     */
    @Override
    public int getRowCount() {
        return clientes.size();
    }

    /**
     * Nesse método, o swing nos indica uma linha e uma coluna da tabela, e
     * devemos retornar o valor que queremos naquela linha/coluna.
     */
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        // Aqui, devolveremos o nome, endereço o telefone de acordo com a coluna
        // informada em columnIndex. A linha será correspondente a linha do
        // cliente na lista.
        if (columnIndex == 0) // Coluna 0 é a de Nome
            return clientes.get(rowIndex).getNome();
        else if (columnIndex == 1) // Coluna 1 é a de Endereço
            return clientes.get(rowIndex).getEndereco();
        else if (columnIndex == 2) // Coluna 2 é a de Telefone
            return clientes.get(rowIndex).getNome();

        // Essa exceção nunca irá ocorrer.
        throw new IllegalArgumentException("Linha " + rowIndex + " e coluna "
                + columnIndex + " não são válidas!");
    }

    // Criamos um método conveniente para retornar um cliente baseado na linha.
    public Cliente get(int linha) {
        return clientes.get(linha);
    }
}

/**
 * Exatamente o mesmo JFrame que você montou. Note que, como temos um model
 * próprio, aqui só trabalhamos com nossa classe de negócios, Cliente. Não
 * usamos aqui listas de strings, arrays de objetos ou qualquer outra coisa
 * tenebrosa do gênero.
 * <p>
 * Embora esse código pareça mais longo e difícil que o seu, saiba que na
 * prática, você terá mesmo que criar uma classe Cliente, provavelmente já terá
 * a lista de clientes vinda de algum lugar (como um banco de dados). E a única
 * coisa que será refeita será o model, que poderá ser reaproveitado em todas as
 * telas que tiverem uma tabela de clientes.
 */
public class ExemploJTable extends JFrame {
    private JTable tabela;
    private ClienteTableModel model;
    private JButton btn;

    public ExemploJTable() {
        List&lt;Cliente&gt; clientes = new ArrayList&lt;Cliente&gt;();
        clientes.add(new Cliente("João", "Rua Tal", "4444"));
        clientes.add(new Cliente("Maria", "Av Tal", "3333"));

        model = new ClienteTableModel(clientes);
        tabela = new JTable(model);
        JScrollPane sp = new JScrollPane(tabela);
        add(sp, "Center");

        btn = new JButton("Mostrar");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                mostrarSelecionado();
            }
        });
        add(btn, "South");
        setSize(600, 600);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    protected void mostrarSelecionado() {
        // Mostra o nome e o telefone dos clientes selecionados.
        for (int linha : tabela.getSelectedRows()) {
            Cliente selecionado = model.get(linha);
            JOptionPane.showMessageDialog(null, selecionado.getNome() + " - "
                    + selecionado.getTelefone());
        }
    }
    
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run() {
                new ExemploJTable().setVisible(true);
            }
        });
    }
}
S

ViniGodoy, então independentemente se vou ou não acessar o banco de dados tenho que ter uma classeVO (Value Object), é por que o que eu quero não pega nada do banco de dados e sim os elementos digitados nas linhas e colunas da tabela e fazer calculos com esses dados e o resultado final só que vai para o banco de dados.
Explicando melhor…
Tenho que fazer um cálculo com os dados que é Quantidade X Comprimento X Largura X Altura independente da quantidade de linhas inserida pelo usuário, o que vai para o banco de dados será só o cálculo total da cubagem. E o que não estou conseguindo fazer é pegar os dados das linhas e fazer esse cálculo.
Espero que tenha entendido.
Obrigada pela paciência.
Sandra Haine.

Marky.Vasconcelos

Tudo isso resolveria se voce criasse seu proprio TableModel que por exemplo teria um Objeto Medidas que com um simples getCubagem Linha voce pegaria essa Medida e calcularia.

PS: Eu já fiz dois sitemas pra transportes e tem um sistema de cubagem também… e os dois clientes queriam que essas medidas fossem armazenadas em algum lugar para serem vistas depois para edição.
É bom voce pensar em criar um tableModel para as Medidas e armazena-las em algum lugar também.

S

Mark,
não entendi muito bem o que você quiz dizer.
Obrigada.
Sandra Haine

Marky.Vasconcelos

Voce precisa de conhecer o TableModel melhor pra isso… mas é mais ou menos assim o que eu falei.

Imagine que voce tem a classe Medida com os atributos qtd, alt, lag, comp

Na sua TableModel voce adicionaria mais ou menos assim um novo objeto:

Medidas m =new Medidas(1,0.2,0.5,1.2);//No construtor os args são quantidade, alt, lag e com.
tableModel.add(m);

Assim voce passa direto um objeto medida

e para pegar o valor da linha selecionado seria algo assim:

Medidas selecionada = tableModel.get(table.getSelectedRow());

Seria mais fáçil trabalhar com essa Medidas que já é uma representação da linha inteira.

Dai iamgina nessa classe Medidas ainda voce pode ter o método getCubagem que seria algo assim:

public double getCubagem(){
return qtd * alt * lag * comp * 300;
}
P

Bom dia!

Estou aproveitando este tópico para tirar uma dúvida

Tenho este código e,

private void fillObjects() {
        //Cleanig JTable(s)
        ((DefaultTableModel) this.tblMostraDados.getModel()).setNumRows(0);

        //
        Vector&lt;Object&gt; vctRows2 = new Vector&lt;Object&gt;();
        Vector&lt;Object&gt; vctCols2 = new Vector&lt;Object&gt;();

        vctRows2.addElement(new String("1"));
        vctRows2.addElement(new String("2"));
        vctRows2.addElement(new String("3"));
        vctRows2.addElement(new String("4"));
        vctRows2.addElement(new String("5"));

        vctCols2.addElement(new String("A"));

        //Common JTable(s)
        this.tblMostraDados.setModel(new DefaultTableModel(vctRows2, vctCols2));
    }

recebo este erro?

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Vector
        at javax.swing.table.DefaultTableModel.justifyRows(DefaultTableModel.java:251)
        at javax.swing.table.DefaultTableModel.setDataVector(DefaultTableModel.java:207)
        at javax.swing.table.DefaultTableModel.&lt;init&gt;(DefaultTableModel.java:142)
        ...

Tive examinando isto

public DefaultTableModel(Vector data, Vector columnNames) {
        setDataVector(data, columnNames);
    }

    public void setDataVector(Vector dataVector, Vector columnIdentifiers) {
        this.dataVector = nonNullVector(dataVector);
        this.columnIdentifiers = nonNullVector(columnIdentifiers); 
	justifyRows(0, getRowCount()); 
        fireTableStructureChanged();
    }

    private void justifyRows(int from, int to) { 
	// Sometimes the DefaultTableModel is subclassed 
	// instead of the AbstractTableModel by mistake. 
	// Set the number of rows for the case when getRowCount 
	// is overridden. 
	dataVector.setSize(getRowCount()); 

        for (int i = from; i &lt; to; i++) { 
	    if (dataVector.elementAt(i) == null) { 
		dataVector.setElementAt(new Vector(), i); 
	    }
	    ((Vector)dataVector.elementAt(i)).setSize(getColumnCount());
	}
    }

Pra mim, isso é um BUG do JAVA!

O Construtor me dz que aceita um Vector e não sabe o que fazer direito com ele.

Muito estranho.

Vinny,
Por favor pode me ajudar?

Obrigado cara!

Se que sacas paca de JTable e seus derivados.

Marky.Vasconcelos

Isso não é um bug do java

O DefaultTableModel só deve ser usado quando voce precisa fazer um prototipo tipo em 5 min para ter algun resultado, mas em um programa em produção não tem nenhum sentido usa-lo e ficar trabalhando com Arrays de Strings… estude AbstractTableModel que nunca tera mais problemas assim (A não ser que voce deiar algo assim)

Marky.Vasconcelos

Respondendo a pergunta:
Ali o que acontece é que seu vetor de dados deve ser um vetor de vetores.
Algo assim:

Vector data = new Vector<Vector<Object>>();

e no data voce vai adicionando os Vectors que representam as linhas.

P

Como então converto um Array de Strings em um Vector?

Criado 28 de outubro de 2008
Ultima resposta 6 de nov. de 2008
Respostas 23
Participantes 5