Search code examples
javaswingjtabledefaulttablemodeltablerowsorter

JTable model update not visible while TableRowSorter is filtering


I have a color editing JDialog where the user can add/delete/edit a color. The colors are showed in a Jtable which is populated from a DB. The UI contains a txtField which allows filtering thanks to a TableRowSorter. The Jtable uses a defaultTableModel and after the user choses to delete a row for example I do a model.removeRow(tableau.getSelectedRow()) to refresh the model.

My problem is the following : when the user doesn't use the sorter and clicks on delete everything goes fine and the JTable is updated immediately to represent this action, that is the corresponding row is removed from the JTable, but when he does the same thing with a filter entered (the TableRowSorter does its filtering), the visual feedback in the Jtable does not occur, that is the deleted row is still visible.

1) No filtering : I choose row with FooColor7

enter image description here

2) Then I hit the delete button : row with FooColor7 is deleted and JTable shows that.

enter image description here

Now the "buggy" behaviour:

3) Filtering on : I choose row with FooColor3

enter image description here

4) Then I hit the delete button : no change in UI even if the row is properly deleted from the DB...

enter image description here

And here is a sort of SSCCE (sort of because not working without dependencies which would be too long to put here) :

public class DialogEditColors extends JDialog implements ActionListener, KeyListener
{
 final TableRowSorter<TableModel> sorter;
 private JTable                table        = null;
 private DefaultTableModel     model        = null;
 private JPanel                panelBoutons = null;
 private JTextField            txtFieldSearch;
 private JLabel                lblTitle;
 private JButton               btnAdd   , btnDelete, btnEdit;
 private JButton               btnCancel, btnSave;
 private JScrollPane           scroller;
 private ColorDao              colorDao= new ColorDao(Share.connection);

 public DialogEditColors()
 {
  super();
  setSize(439, 313);
  setTitle("  Edition couleurs");
  getContentPane().setLayout(null);
  setModal(true);
  setResizable(false);
  setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
  setLocationRelativeTo(null);

  btnSave = new JButton("Enregistrer");
  btnSave.setBounds(317, 247, 89, 26);
  btnSave.addActionListener(this);

  btnCancel = new JButton("Annuler");
  btnCancel.setBounds(214, 247, 89, 26);
  btnCancel.addActionListener(this);

  btnAdd = new JButton("");
  btnAdd.setBounds(new Rectangle(10, 8, 33, 26));
  btnAdd.addActionListener(this);

  btnDelete = new JButton("");
  btnDelete.setBounds(new Rectangle(53, 8, 33, 26));
  btnDelete.addActionListener(this);

  btnEdit = new JButton("");
  btnEdit.setBounds(new Rectangle(96, 8, 33, 26));
  btnEdit.addActionListener(this);

  panelBoutons = new JPanel();
  panelBoutons.setBorder(new LineBorder(Color.GRAY));
  panelBoutons.setBounds(27, 11, 378, 43);
  panelBoutons.setLayout(null);

  txtFieldSearch = new JTextField("", 10);
  txtFieldSearch.setBounds(193, 9, 175, 24);
  panelBoutons.add(txtFieldSearch);
  txtFieldSearch.addKeyListener(this);

  Object[][] data = new Object[colorDao.findAll().size()][2];
  String[] title = { "Couleur", "Description" };

  int i = 0;
  for (Couleur coul : colorDao.findAll())
   {
      data[i][0] = coul.getNom();
      data[i][1] = coul.getDescription();
      i++;
   }

  model = new DefaultTableModel(data, title);
  table = new JTable(model)
  {//THIS ALLOWS TO ALTERNATE THE BACKGROUND COLOR OF ROWS
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
    {
      Component returnComp = super.prepareRenderer(renderer, row, column);
      Color alternateColor = new Color(242, 242, 242);
      Color whiteColor = Color.WHITE;
      if ( !returnComp.getBackground().equals(getSelectionBackground()) )
      {
        Color bg = (row % 2 == 0 ? alternateColor : whiteColor);
        returnComp.setBackground(bg);
        bg = null;
      }
      return returnComp;
     };
   };

  table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  table.setCellSelectionEnabled(true);
  table.setColumnSelectionAllowed(true);
  sorter = new TableRowSorter<TableModel>(model);
  table.setRowSorter(sorter);

  scroller = new JScrollPane(table);
  scroller.setBounds(27, 65, 378, 171);
  addComponents();
  setVisible(true);
  }//END OF CONSTRUCTOR

  private void addComponents()
  {
   getContentPane().add(scroller);
   getContentPane().add(btnSave);
   getContentPane().add(btnCancel);
   panelBoutons.add(btnAdd);
   panelBoutons.add(btnDelete);
   panelBoutons.add(btnEdit);
   getContentPane().add(panelBoutons);
  }////END OF METHOD

  public void actionPerformed(ActionEvent e)
  {
   if ( e.getSource() == btnDelete )
   {
    if ( table.getSelectedRowCount() != 0 ) 
    {//THERE IS A CHOSEN ROW IN JTABLE
      String selectedColor = (table.getValueAt(table.getSelectedRow(),     table.getSelectedColumn())).toString();
      //TEST THE READONLY ATTRIBUTE OF THE COLOR
      if ( colorDao.findByNom(selectedColor).get(0).getReadOnly() == true )
      {//THE COLOR'S READONLY ATTRIBUTE IS TRUE
       JOptionPane.showMessageDialog(this, "This item is readOnly: impossible to delete it!");
      }
      else
      {//THE COLOR'S READONLY ATTRIBUTE IS FALSE
       int response = JOptionPane.showConfirmDialog(this, "Are you sure you
       want to delete this color?", "Confirmation", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);

       if ( response == 0 ) //CONFIRMED
       {//FIRST DELETE THE COLOR FROM DB
        colorDao.delete(colorDao.findByNom(selectedColor).get(0));
        //THEN REFRESH JTABLE TO TAKE DELETION INTO ACCOUNT
        model.removeRow(table.getSelectedRow());
        table.repaint();
       }
     }
    }
    else
    {//NO CHOSEN COLOR
      JOptionPane.showMessageDialog(this, "No chosen color!");
    }
   }

   else if ( e.getSource() == btnCancel )
   {
    this.dispose();
   }
  }//END OF METHOD

  public void keyReleased(KeyEvent e)
  {
   if ( e.getSource() == txtFieldSearch )
   {
     String text = txtFieldSearch.getText();
     if ( text.length() == 0 )
     {
      sorter.setRowFilter(null);
     }
     else
     {
      sorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
     }
     ((AbstractTableModel) table.getModel()).fireTableDataChanged();
   }
  }//END OF METHOD
}////END OF CLASS

Any idea ?


Solution

  • model.removeRow(table.getSelectedRow()); table.repaint();

    1. there is no need for the repaint. The TableModel will notify the table when the data is changed and the table will repaint itself

    2. Since you are sorting your data you may be deleting the wrong row from the TableModel. You first need to convert the view index to the model index:

    For example:

    int modelIndex = table.convertRowIndexToModel( table.getSelectedIndex() );
    model.removeRow( modelIndex );