Remover linhas de JTable dinamicamente

Galera,
tenho uma JTable com seu DefautTableModel (dtm). Através de uma pesquisa em banco, o dtm é preenchido legal. Porém eu desejo dar a opção ao usuário de escolher linhas para remover, por exemplo, as linhas cujo valores da 1ª coluna sejam iguais a 10, quando ele pressionar um dado botão. Então, o vetor de dados deve ser varrido em busca do valor 10 na 1ª coluna, em todas as linhas. No actionPerformed do botão, pensei neste código:

Vector rs = dtm.getDataVector();
java.util.Iterator it = rs.iterator();
    
while(it.hasNext()) {
  Vector r = (Vector) it.next();
  
  if(r.elementAt(0).equals(10)) {
    it.remove();
  }
};
    
dtm.setDataVector(rs, columns);
//columns: vector de nomes das colunas.

Funciona ok, MENOS QUANDO A TABELA ESTÁ ROLADA ATÉ O FIM… no momento do clique, se houver linhas pra remover elas são removidas, e a tabela se deforma rapidamente voltando ao normal.
Isso não atrapalha em nada, porém não fica bem esteticamente essa rápida deformada da tabela.
Isto é:

Quando se remove linhas com toda a tabela visível ou a barra de rolagem não está no final, as linhas são removidas perfeitamente:

mas quando a barra de rolagem está no final, …

… e linhas são removidas, a %&#@! da tabela se deforma por um pequeno intervalo de tempo: …

… até voltar ao normal:

Alguém teria um outro código? :?

Qual a versão do seu JDK / JRE?
Estranho.

tentar dar um repaint() ou um revalidate() an sua JTable depois de tudo isso. E tenta fazer um scroll ateh a primeira linha da sua JTable. Deve parar de deformar sua JTable.

[quote]Qual a versão do seu JDK / JRE?
Estranho. [/quote]
É o Tiger 5.0 …

Bem, o repaint() e o ravalidate() não funcionaram… como “scrollar” para a 1ª linha?

http://www.guj.com.br/posts/list/20108.java#106295

Tem jeito não, brlima… aqui não deu certo. :frowning:

Olha isso aqui, ele adiciona 50 linhas. E no Botao remove algumas. E funciona sem problemas. Eu fico com o scroll no final e nada.

Ve-se te ajuda em alguam coisa…

/* 
 * Criado por Bruno R. Lima em 16/02/2005
 */
package com.sample;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 * 
 * @author Bruno Rios Lima
 */
public class TableSmaple {

    static DefaultTableModel md = new DefaultTableModel();
    
    public static void main(String[] args) {
        
        JTable table = new JTable();
        JScrollPane pane = new JScrollPane(table);
        JFrame fr = new JFrame();
        JButton bt = new JButton("Enter");
        bt.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                md.removeRow(20);
                md.removeRow(21);
                md.removeRow(23);
                md.removeRow(25);
            }
        });
        
        md.addColumn("Column1");
        md.addColumn("Column2");
        md.addColumn("Column3");
        
        Vector v = new Vector();
        for( int x=0; x< 50; x++){
	        v = new Vector();
	        v.add(x+".1");v.add(x+".2");v.add(x+".3");
	        md.addRow(v);
        }
        table.setModel(md);
        fr.getContentPane().add(pane, BorderLayout.CENTER);
        fr.getContentPane().add(bt, BorderLayout.SOUTH);
        fr.setSize(200,200);
        fr.setVisible(true);
        
    }
}

Alias, acho melhor vc usar no seu codigo

rs.remove(it); no lugar de

Talvez possa ser isso…

flw!

O caso é. O Vector “avisa” o model que foi alterado?

verdade daniel. acgo que é por isso. tem que pedir pro model excluir a linha, e não excluir direto pelo vector, pois o mesmo nao avisa das alterações :smiley:

Tenta assim:

DefaultTableModel model = (DefaultTableModel ) seuJTable.getModel(); Vector v = model.getDataVector(); Iterator it = v.iterator(); for( int i=0; it.hasNext(); i++ ) { Vector r = (Vector) it.next(); if(r.elementAt(0).equals(10)) { model.removeRow( i ); } }

Ficou um lixo, mas blz!

[quote=brlima]Alias, acho melhor vc usar no seu codigo

rs.remove(it); no lugar de

Talvez possa ser isso…

flw![/quote]
Nada ocorre, lima!

Quanto ao seu código, vejo que já se sabe quais linhas se quer remover. O problema é que devem ser removidas linhas com alguma característica, como por exemplo, “todas as linhas onde o elemento da 1ª coluna é 10”… creio que a JTable deve ser varrida em busca de tais linhas. E por isso usei o Iterator, o qual está dando este pequeno erro chato!

Quanto ao código do daniel_destro: funciona, A MENOS QUE A LINHA A SER REMOVIDA SEJA A PENÚLTIMA!!

Além do mais…

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
    at java.util.AbstractList$Itr.next(AbstractList.java:420)
    at gui.my.NewJFrame.removeButtonActionPerformed(NewJFrame.java:103)
    at gui.my.NewJFrame.access$100(NewJFrame.java:17)
    at gui.my.NewJFrame$2.actionPerformed(NewJFrame.java:71)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1849)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2169)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:234)
    at java.awt.Component.processMouseEvent(Component.java:5488)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3093)
    at java.awt.Component.processEvent(Component.java:5253)
    at java.awt.Container.processEvent(Container.java:1966)
    at java.awt.Component.dispatchEventImpl(Component.java:3955)
    at java.awt.Container.dispatchEventImpl(Container.java:2024)
    at java.awt.Component.dispatchEvent(Component.java:3803)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3892)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
    at java.awt.Container.dispatchEventImpl(Container.java:2010)
    at java.awt.Window.dispatchEventImpl(Window.java:1766)
    at java.awt.Component.dispatchEvent(Component.java:3803)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
    at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:234)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

Esta exceção é disparada.

O código que estou usando é o abaixo.

// NewJFrame.java

import javax.swing.table.DefaultTableModel;
import java.util.Vector;

/**
 *
 * @author  Antonioni de Araújo Rocha
 */
public class NewJFrame extends javax.swing.JFrame {
  
  private DefaultTableModel dtm;
  private Vector columnIdentifiers;
  private Vector dataVector;
  
  /** Creates new form NewJFrame */
  public NewJFrame() {
    initComponents();
    
    columnIdentifiers = new Vector(1, 1);
    columnIdentifiers.add("coluna1");
    columnIdentifiers.add("coluna2");
    columnIdentifiers.add("coluna3");
    dataVector = new Vector(1, 1);
    dtm = new DefaultTableModel(dataVector, columnIdentifiers);
    table.setModel(dtm);
  }
  
  /** This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
  private void initComponents() {
    buttonPanel = new javax.swing.JPanel();
    addButton = new javax.swing.JButton();
    removeButton = new javax.swing.JButton();
    tablePanel = new javax.swing.JPanel();
    dtmTablePanel = new javax.swing.JPanel();
    dtmScrollPane = new javax.swing.JScrollPane();
    table = new javax.swing.JTable();
    table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
    table.getTableHeader().setReorderingAllowed(false);

    getContentPane().setLayout(new java.awt.BorderLayout(0, 10));

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    buttonPanel.setLayout(new java.awt.GridLayout(1, 4, 5, 0));

    buttonPanel.setPreferredSize(new java.awt.Dimension(50, 50));
    addButton.setText("Add");
    addButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        addButtonActionPerformed(evt);
      }
    });

    buttonPanel.add(addButton);

    removeButton.setText("Remove");
    removeButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        removeButtonActionPerformed(evt);
      }
    });

    buttonPanel.add(removeButton);

    getContentPane().add(buttonPanel, java.awt.BorderLayout.SOUTH);

    tablePanel.setLayout(new java.awt.GridLayout(1, 1, 0, 5));

    dtmTablePanel.setLayout(new java.awt.GridLayout(1, 1));

    dtmTablePanel.setBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED));
    dtmScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    dtmScrollPane.setViewportView(table);

    dtmTablePanel.add(dtmScrollPane);

    tablePanel.add(dtmTablePanel);

    getContentPane().add(tablePanel, java.awt.BorderLayout.CENTER);

    java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
    setBounds((screenSize.width-500)/2, (screenSize.height-200)/2, 500, 200);
  }

  private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Vector rs = dtm.getDataVector();
    java.util.Iterator it = rs.iterator();    
    
    for(int i=0; it.hasNext(); i++) {
      Vector r = (Vector) it.next();
      
      if(r.elementAt(0).equals(10)) {
        dtm.removeRow(i);
      }
    };
    
    dtm.setDataVector(rs, columnIdentifiers);
  }

  private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Vector row = new Vector(1, 1);
    row.add(table.getRowCount());
    row.add(table.getRowCount());
    row.add(table.getRowCount());
    dataVector.add(row);
    dtm.setDataVector(dataVector, columnIdentifiers);
  }
  
  /**
   * @param args the command line arguments
   */
  public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        new NewJFrame().setVisible(true);
      }
    });
  }
  
  // Variables declaration - do not modify
  private javax.swing.JButton addButton;
  private javax.swing.JPanel buttonPanel;
  private javax.swing.JScrollPane dtmScrollPane;
  private javax.swing.JPanel dtmTablePanel;
  private javax.swing.JButton removeButton;
  private javax.swing.JTable table;
  private javax.swing.JPanel tablePanel;
  // End of variables declaration
  
}

Ô troço complicado!

tenta começar do fim a remover as linhas, tipo começar debaixo.

Faz uma alteraçãosinha rapida no codigo, na ação do botão, para excluir somente as linhas selecionadas:

int [] rows = table.getSelectedRows();
                for( int x=rows.length-1;x>=0; x-- ){
                    md.removeRow(rows[x]);
                }

e altere a propriedade da JTable logo depois de setar o modelo para

table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

Desse mode vc pode excluir as linhas selecionadas. Eu inverti , estou excluindo de baixo pra cima. e funcionou bacana.

[quote=brlima]Faz uma alteraçãosinha rapida no codigo, na ação do botão, para excluir somente as linhas selecionadas:

int [] rows = table.getSelectedRows();
                for( int x=rows.length-1;x>=0; x-- ){
                    md.removeRow(rows[x]);
                }

e altere a propriedade da JTable logo depois de setar o modelo para

table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

Desse mode vc pode excluir as linhas selecionadas. Eu inverti , estou excluindo de baixo pra cima. e funcionou bacana.[/quote]
Este código é legal… embora, no meu caso, as linhas não são selecionadas pelo usuário, e sim dependentes de um valor booleano na 1ª coluna: quero remover as linhas cujos valores em “table.getValueAt(?, 0)” sejam “TRUE”, entende?

Neste caso, é preciso um “for” para varrer a tabela em busca das linhas, inserindo seus índices num int[]; só depois iria para o laço “for(int x=…) {}”, diminuindo ligeiramente o desempenho!

Mas tudo bem, se as outras formas mais simples e elegantes não funcionam… valeu!

Eu acho que necessariamente vc nao precisa fazer dois looping distintos… No primeiro loop em busca dos dados, ao inves de adicionar num int[] , remove direto pelo modelo. So faz o looping começando do fim.

É vero, lima, foi mal…!

E acabei de resolver o problema também com o loop normal:

int i = 0;
while(i < table.getRowCount()) {
  if(Integer.parseInt(String.valueOf(table.getValueAt(i, 0)))%2 == 0)
    dtm.removeRow(i);
  else
    i++;
}

Este loop remove todas as linhas que têm como elemento na 1ª coluna um número par! Funciona sem a $%&@# da deformação!

Bem, valeu mesmo, cara! :smiley: