JTable com célula não editavel e célula editavel[RESOLVIDO]

Olá a todos…

Puxa, depois que comecei a estagiar em JAVA nunca perguntei tanto… :smiley: Ainda bem que tenho vcs pra me ajudar…

Novamente, venho perguntar sobre um problema tenso:

Tenho uma JTable não editável. Eu preciso de:

1° Colocar botões para visualizar os campos da tabela em outra página, além de exclui-lá e atualizá-la;

2° Preciso que a JTable não permita seleção múltipla, de maneira nenhuma…

Eu tenho um código que insere botões na JTable, mas não posso ativá-los com a tabela não editável…

Se puderem me ajudar…

Tópico movido para o fórum de interface gráfica.

Você precisa criar um TableCellEditor com o botão. Associa-lo a sua tabela vinculado a um tipo de dado (como JButton.class) e, em seguida, alterar no seu model as colunas de botão para retornarem JButton.class no getValueAt;

Use o método
JTable.setSelectionMode/url);

Faça seu model retornar false no método setEditable apenas para as colunas que não são botões.

Se você não sabe direito o que é esse model que estou falando (e não é o DefaultTableModel), dê uma lida nos links da minha assinatura, em especial, ao lado do texto em vermelho. Se quer fazer tabelas mais poderosas, é essencial que você saiba mexer corretamente num TableModel.

Olá, ViniGodoy,

1° Foi mal pelo post em local errado, tinha certeza de que era no Java básico… :oops:

2° Não tenho a menor idéia de como usar AbstractTableModel, e eu vi os artigos aqui do fórum e não entendi!!! Vou dar

uma olhada, e peço que me ajude com o que precisar!!!

Tente e poste as dúvidas.

Porque o DefaultTableModel é beeem mais difícil que o Abstract. Não se deixe assustar pelo tamanho dos códigos. Aquele é todo código necessário para fazer uma tabela editável. E ele fica concentrado em um lugar só.

No Default, você acaba com muito mais código do que aquilo, espalhado pela sua classe de interface gráfica. Sem falar em vários casts inseguros, na necessidade de duplicar dados e de muitas vezes expor colunas desnecessárias ao usuário (como as de ID).

Tem algum exemplo de AbstractTan]bleModel com banco de dados ?

Eu num entendi muito bem a parte de inserir os dados na tabela…

O TableModel trabalha com um ArrayList de dados da sua classe de negócio.
Quem faz a carga e salva esse ArrayList no banco são as classes DAO (Data Access Objects).

Você não tem classes de negócio para suas entidades?

Se vc ta falando de uma classe desse tipo:

public class Usuario {

	private String	nome;
	private String login;
	private String senha;
	private String confirm;
	private int perfil;
	private int situacao;
	
	// nome
	
	/**
	 * @return the nome
	 */
	public String getNome() {
		return nome;
	}
	/**
	 * @param nome the nome to set
	 */
	public void setNome(String nome) {
		this.nome = nome;
	}
	
	// login
	
	/**
	 * @return the login
	 */
	public String getLogin() {
		return login;
	}
	/**
	 * @param login the login to set
	 */
	public void setLogin(String login) {
		this.login = login;
	}
	
	// senha
	
	/**
	 * @return the senha
	 */
	public String getSenha() {
		return senha;
	}
	/**
	 * @param senha the senha to set
	 */
	public void setSenha(String senha) {
		this.senha = senha;
	}
	
	// confirm
	
	/**
	 * @return the confirm
	 */
	public String getConfirm() {
		return confirm;
	}
	/**
	 * @param confirm the confirm to set
	 */
	public void setConfirm(String confirm) {
		this.confirm = confirm;
	}
	
	// perfil
	
	/**
	 * @return the perfil
	 */
	public int getPerfil() {
		return perfil;
	}
	/**
	 * @param perfil the perfil to set
	 */
	public void setPerfil(int perfil) {
		this.perfil = perfil;
	}
	
	/**
	 * @return the situacao
	 */
	public int getSituacao() {
		return situacao;
	}
	/**
	 * @param situacao the situacao to set
	 */
	public void setSituacao(int situacao) {
		this.situacao = situacao;
	}
	
	
}

Não tinha, mas desenvolvi uma agora…

Legal. A classe DAO é aquele que transforma os dados do banco, num List de uma classe desse tipo:

public class UsuarioDao { public List<Usuario> carregarUsuarios() { //Aqui vc faz a consulta SQL e carrega a lista } }

O TableModel então desenha a lista de usuários.

Sinto muito ficar perguntando toda hora, mas num entendo como setar estes valores na tabela… como eu insiro esses dados no List e como faço para desenhá-los na tabela… Eu to tentando, mesmo, mas ta complicado…

Você sabe usar banco de dados?

De onde estão vindo os valores que atualmente estão na sua tabela?

Acho melhor postar o código do geito q tava antes:

[code]import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;

@SuppressWarnings({ “serial”})
public class Con_Usuario extends JPanel{

@SuppressWarnings("unused")
private JLabel lblNome, lblLogin,lblSenha, lblConfirm, lblPerfil, lblSituacao,
	lblPesquisa;

@SuppressWarnings("unused")
private JTextField txtNome, txtLogin, txtPesquisa;
private JPasswordField pswSenha, pswConfirm;
private JComboBox cmbPerfil;

JTable tabela;
DefaultTableModel modelo;
JScrollPane barra;

public PreparedStatement pstmt;

String colunas[] = {"Código","Nome","Login","Perfil de Acesso","Situação"};
String dados[][];
JPanel panelCon;

FiltraUsuario filt; 
public Con_Usuario() {  
	     
    setLayout(null); 
    initComponents();
	
}

public void initComponents(){  
	filt = new FiltraUsuario();
    add(getMyLabel());
    add(getMyText());
    add(getMyTabela());
   }  
   
public JLabel getMyLabel(){  
    if(lblPesquisa == null){  
      //instancia sua label aqui 
    	lblPesquisa = new JLabel("Pesquisa por nome: ");
        lblPesquisa.setBounds(25, 25, 140, 25);
        add(lblPesquisa);
     }  
     return lblPesquisa;  
} 
public JTextField getMyText(){  
    if(txtPesquisa == null){  
      //instancia seu text aqui 
    	txtPesquisa = new JTextField();
        txtPesquisa.setBounds(160, 25, 160, 25);
        txtPesquisa.addKeyListener(filt);
        add(txtPesquisa); 
     }  
     return txtPesquisa;  
}
public JScrollPane getMyTabela(){  
    if(barra == null){  
      //instancia seu text aqui 
    	modelo = new DefaultTableModel(dados, colunas){
        	public boolean isCellEditable(int rowIndex, int mColIndex){
        		return false;
        	}
        	@SuppressWarnings("unused")
        	public boolean isColumnSelected(int mColIndex){
        		return false;
        	}	
        };
        
        tabela = new JTable(modelo);
        tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        
        tabela.getColumnModel().getColumn(0).setPreferredWidth(200);
        tabela.getColumnModel().getColumn(1).setPreferredWidth(130);
        tabela.getColumnModel().getColumn(2).setPreferredWidth(120);
        tabela.getColumnModel().getColumn(3).setPreferredWidth(100);
        
        carregarTabela();

        barra = new JScrollPane(tabela);
        barra.setBorder(BorderFactory.createLineBorder(Color.black, 1));
        barra.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        barra.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS );
        barra.setBounds(100,100,600,200);
        add(barra);
    	
     }  
     return barra;  
}

   
public void carregarTabela(){
	modelo.setNumRows(0); 
	Conexao.Conecta();
	try{
       
		// procedimentos para obter os dados de uma tabela
		String SQL = "SELECT * FROM usuario";
		pstmt = Conexao.connection.prepareStatement(SQL);
		ResultSet rs = pstmt.executeQuery(); 
  
		while(rs.next()){ 
			String cod = rs.getString("id");
			String nome = rs.getString("nome");
			String login= rs.getString("usuario");
			String perf = rs.getString("perfil_acesso");
			String situ = rs.getString("situacao"); 
			
			modelo.addRow(new Object[]{cod, nome, login, perf, situ});
		}
		rs.close(); 

		tabela.removeColumn(tabela.getColumn("Código"));
  } 
		
  
  catch(SQLException ex){
       
	   System.out.println("SQLException: " + ex.getMessage());
       System.out.println("SQLState: " + ex.getSQLState());
       System.out.println("VendorError: " + ex.getErrorCode());
           
  }
 
  Conexao.Fecha(); 

}

class FiltraUsuario implements KeyListener{

	@Override
	public void keyPressed(KeyEvent arg0) {
		// TODO Auto-generated method stub
					
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		modelo.setNumRows(0); 
		String text = txtPesquisa.getText();
		Conexao.Conecta();
		try{
           
			// procedimentos para obter os dados de uma tabela
			String SQL = "SELECT * FROM usuario WHERE nome LIKE '"+text+"%'";
			pstmt = Conexao.connection.prepareStatement(SQL);
			ResultSet rs = pstmt.executeQuery(); 
			
			while(rs.next()){ 
				
				String cod = rs.getString("id");
				String nome = rs.getString("nome");
				String login= rs.getString("usuario");
				String perf = rs.getString("perfil_acesso");
				String situ = rs.getString("situacao"); 
				modelo.addRow(new Object[]{cod, nome, login, perf, situ});
				
			}
			rs.close(); 
			
		} 
		catch(SQLException ex){
           
    	   System.out.println("SQLException: " + ex.getMessage());
           System.out.println("SQLState: " + ex.getSQLState());
           System.out.println("VendorError: " + ex.getErrorCode());
               
      }
		
		Conexao.Fecha();  
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

}

}
[/code]

Então sua classe UsuarioDao ficaria assim:

public class UsuarioDao { public List<Usuario> carregarUsuarios(String nome) { Conexao.Conecta(); try{ // procedimentos para obter os dados de uma tabela String SQL = "SELECT * FROM usuario WHERE nome LIKE ?" pstmt = Conexao.connection.prepareStatement(SQL); pstmt.setString(1, nome + "%"); ResultSet rs = pstmt.executeQuery(); List<Usuario> usuarios = new ArrayList<Usuario>(); while(rs.next()){ Usuario usuario = new Usuario(); usuario.setId(rs.getInt("id")); usuario.setNome(rs.getString("nome")); usuario.setLogin(rs.getString("usuario")); usuario.setPerfil(rs.getInt("perfil_acesso")); usuario.setSituacao(rs.getInt("situacao")); usuarios.add(usuario); } rs.close(); } catch(SQLException ex){ throw new RuntimeException(ex); } finally { Conexao.Fecha(); } }

E você usaria assim (no botão buscar):

UsuarioTableModel model = new UsuarioTableModel(new UsuarioDao.carregarUsuarios(nome)); suaTabela.setModel(model);

Ufa, finalmente consegui fazer funcionar o JTable com AbstractTableModel, mas so preciso compreender mais uma coisa:

Como eu seto a célula que desejo ser editável(Aquela que ficará o botão) ?

Se eu permitir edição, ele vai deixar Digitação ? abaixo a classe que implementa o botão na JTable

CLASSE ButtonColumn:

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;



public class ButtonColumn extends AbstractCellEditor
        implements TableCellRenderer, TableCellEditor, ActionListener
    {
        JTable table;
        JButton renderButton;
        JButton editButton;
        String text;
 
        public ButtonColumn(JTable table, int column)
        {
            super();
            this.table = table;
            renderButton = new JButton();
 
            editButton = new JButton();
            editButton.setFocusPainted( false );
            editButton.addActionListener( this );
 
            TableColumnModel columnModel = table.getColumnModel();
            columnModel.getColumn(column).setCellRenderer( this );
            columnModel.getColumn(column).setCellEditor( this );
        }
 
        public Component getTableCellRendererComponent(
            JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
        {
            if (hasFocus)
            {
                renderButton.setForeground(table.getForeground());
                renderButton.setBackground(UIManager.getColor("Button.background"));
            }
            else if (isSelected)
            {
                renderButton.setForeground(table.getSelectionForeground());
                 renderButton.setBackground(table.getSelectionBackground());
            }
            else
            {
                renderButton.setForeground(table.getForeground());
                renderButton.setBackground(UIManager.getColor("Button.background"));
            }
 
            renderButton.setText( (value == null) ? "" : value.toString() );
            return renderButton;
        }
 
        public Component getTableCellEditorComponent(
            JTable table, Object value, boolean isSelected, int row, int column)
        {
            text = (value == null) ? "" : value.toString();
            editButton.setText( text );
            return editButton;
        }
 
        public Object getCellEditorValue()
        {
            return text;
        }
 
        public void actionPerformed(ActionEvent e){
        	JOptionPane.showMessageDialog(null, "Teste");
        }

}

(EDIT) Também configurar essa classe do meu jeito, num entendi muito bem seu funcionameto!!!

Um dos métodos do AbstractTableModel que você pode implementar é o isCellEditable(int row, int column).

Basta retornar true quando a coluna for editável, e false quando não. Vamos supor que vc queira que todas as colunas menores que a 4ª não sejam editáveis:

public bool isCellEditable(int row, int col) { return col >= 4; }

Assim, basta implementar o isCellEditable corretamente, que a JTable probirá a digitação nas colunas que retornar false, mas permitirá o clique nos botões das colunas onde ele retorna true. :wink:

Valeu, ViniGodoy, vc me fez uma pessoa melhor com AbstractTableModel… :smiley:

Peço descupas por ser tão noob, mas faz pouco tempo que estou mexendo com JTable( menos de uma semana)…

Sou seu fã, cara e valeu por não me dieixar na mão… :smiley:

Não é à toa que eu iniciei a campanha de “Morte ao DefaultTableModel”.