• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Question about deleting rows from a table

 
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

I have a table, which has three rows. This has been verified by using
getValueAt each of the three rows.

The table has the middle row removed from the TableModel from it's Hashmap.

After this I still observe all three rows using getValueAt(). The first and last rows
are intact in the table from before as expected. The middle row has it's values
represented as nulls.

The table after the delete physically shows the first row, then a blank second row
and does not show the third row (which was not deleted)

I thought that I would see the first and last row only with the middle row
removed. Can anyone tell me why this happens? This happens whether I do
a model.fireTableRowsDeleted or if I don't.

Thank you,

Ken
 
Author
Posts: 986
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ken Rubin:
I have a table, which has three rows. This has been verified by using
getValueAt each of the three rows.

The table has the middle row removed from the TableModel from it's Hashmap.

After this I still observe all three rows using getValueAt(). The first and last rows
are intact in the table from before as expected. The middle row has it's values
represented as nulls.

The table after the delete physically shows the first row, then a blank second row
and does not show the third row (which was not deleted)

I thought that I would see the first and last row only with the middle row
removed. Can anyone tell me why this happens? This happens whether I do
a model.fireTableRowsDeleted or if I don't.



I'm not sure I understand how you want it to work. Do you want three
rows to be shown with nulls/blanks for the middle row, or do you want
only two rows to be shown where the third row slides down to be second?

If the latter, then model.fireTableRowsDeleted() should do the trick.
If it's not then perhaps you should show us the implementation of your
table model for nitpicking.

If the former, then you shouldn't call model.fireTableRowsDeleted() since
(from the JTable's point of view) one row has changed its values but no
row has been deleted. You would call model.fireTableRowsUpdated() instead.

[edit: oops -- got my former/latter mixed up]
[ April 11, 2008: Message edited by: Brian Cole ]
 
Ken Rubin
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Brian, (Or anyone who may wish to reply)

Thank you for taking the time to read my post and I have found your Java Swing book to be very helpful! I feel priviledged!

My goal is to start with three rows in a table and delete the middle one, so only two show.

ie. showing only the first column in my numismatic table, I wish to delete the middle row.

Before
184O-0 ...
1849-O ...
1852-O ...

After (my goal)
184O-0 ...
1852-O ...

I actually see now
1840-O ...
blank


My TableModel is:

class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"Date",
"Denomination",
"Variety",
"Surviving Count",
"Summary"};

private HashMap theData;




MyTableModel()
{
theData = new HashMap();

}
public HashMap getTheData()
{
return theData;
}
public int getColumnCount() {
return columnNames.length;
}

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

public String getColumnName(int col) {
return columnNames[col];
}

public Object getValueAt(int row, int col) {
Integer tmpKey= new Integer(row);
//tmpKey.append(row);
Entry value = (Entry) theData.get(tmpKey);
if(value == null)
return null;
if(col == 0)
{
return value.getDate();
}
else if(col == 1)
{
return value.getDenomination();
}
else if(col == 2)
{
return value.getVariety();
}
else if(col == 3)
{
return value.getSurvivingCount();
}
else if(col == 4)
{

return value.getSummary();

}
else
return null;

}

/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,
* then the last column would contain text ("true"/"false"),
* rather than a check box.
*/
/*public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}*/

/*
* Don't need to implement this method unless your table's
* editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.

return true;

}

/*
* Don't need to implement this method unless your table's
* data can change.
*/
public void setValueAt(Object value, int row, int col) {

//StringBuffer tmpKey=new StringBuffer();
Integer tmpKey = new Integer(row);
//tmpKey.append(row);
Object tmpObject = theData.get(tmpKey);
if (tmpObject == null)
return;
Entry tmpEntry = (Entry) tmpObject;
if(col == 0)
{
tmpEntry.setDate((String) value);
}
else if(col == 1)
{
tmpEntry.setDenomination((String) value);
}
else if(col == 2)
{
tmpEntry.setVariety((String)value);
}
else if(col == 3)
{
tmpEntry.setSurvivingCount((Integer)value);
}

theData.put(tmpKey, tmpEntry);

fireTableCellUpdated(row, col);

return;
}

}

The table is in the following class (TheTable) with excerpts from it:

public class TheTable extends JPanel implements TableModelListener,ListSelectionListener{
private boolean DEBUG = false;
private MyTableModel model;
private AdminPanel adminPanel;
ListSelectionModel listSelectionModel;

int[] indices;
public TheTable() {
super(new GridLayout(2,1));
model = new MyTableModel();
adminPanel = new AdminPanel();
adminPanel.setModel(model);
adminPanel.setTable(this);
JTable table = new JTable(model);

model.addTableModelListener(this);
listSelectionModel = table.getSelectionModel();
listSelectionModel.addListSelectionListener(this);

table.setPreferredScrollableViewportSize(new Dimension(500, 140));
//table.setFillsViewportHeight(true);
//table.setAutoCreateRowSorter(true);

//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);

//Add the scroll pane to this panel.
add(scrollPane);
add(adminPanel);

}

... (TheTable Class continued)

public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel)e.getSource();

int firstIndex = e.getFirstIndex();
int lastIndex = e.getLastIndex();
boolean isAdjusting = e.getValueIsAdjusting();
JButton delete = adminPanel.getDeleteButton();

if (lsm.isSelectionEmpty()) {
if(delete.isEnabled())
{
delete.setEnabled(false);
}
;
} else {
// Enable Delete button if not enabled.
if(!delete.isEnabled())
{
delete.setEnabled(true);
}
// Find out which indexes are selected.
int minIndex = lsm.getMinSelectionIndex();
int maxIndex = lsm.getMaxSelectionIndex();
indices = new int[maxIndex - minIndex + 1];
int j = 0;
for (int i = minIndex; i <= maxIndex; i++) {
if (lsm.isSelectedIndex(i)) {
indices[j++] = i;
}
}
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TheTable");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//Create and set up the content pane.
TheTable newContentPane = new TheTable();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
Entry row1 = new Entry("1843-o","25 Cents",
"Large O", new Integer(80));
MyTableModel theModel = newContentPane.getModel();


HashMap map = theModel.getTheData();
map.put(new Integer(0), row1);


Entry row2 = new Entry("1849-o","25 Cents",
"Large O", new Integer(80));
map.put(new Integer(1), row2);


Entry row3 = new Entry("1852-o","25 Cents",
"Large O", new Integer(80));
map.put(new Integer(2), row3);

theModel.fireTableRowsInserted(0, 2);

//Display the window.
frame.pack();
frame.setVisible(true);


}
Another class has a listener which actually deletes the data:

public void actionPerformed(ActionEvent e)
{
HashMap map;
map = model.getTheData();
if (DELETE.equals(e.getActionCommand())) {
int[] indices = table.getIndices();
for(int i=indices.length-1;i >= 0;i--)
{
model.getTheData().remove(new Integer(indices[i]));
model.fireTableRowsDeleted(indices[i], indices[i]);

}
}
else if (ADD.equals(e.getActionCommand())) {
...
}
}

Sorry for all the code. Any suggestions would be greatly appreciated.

Thank you,

Ken
 
Brian Cole
Author
Posts: 986
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ken Rubin:

My goal is to start with three rows in a table and delete the middle one, so only two show.

ie. showing only the first column in my numismatic table, I wish to delete the middle row.

Before
184O-0 ...
1849-O ...
1852-O ...

After (my goal)
184O-0 ...
1852-O ...

I actually see now
1840-O ...
blank


My TableModel is:


//Another class has a listener which actually deletes the data:
...
model.getTheData().remove(new Integer(indices[j]));
model.fireTableRowsDeleted(indices[j], indices[j]);



Is there a reason you're using a HashMap to store the table rows?

It can be ok to do that, but in this case you are using the row numbers
as the keys into the HashMap, which is weird. If you want to index
something by consecutive integers, that's what ArrayList is designed
for, right?

In fact, if you used an ArrayList I think your troubles would go away,
because calling yourArrayList.remove(1) would result in the data
formerly at index #2 "sliding down" and being located at index #1.
This is exactly what you want.

With your current HashMap implementation, removing the entry with
key #1 will cause size() and getRowCount() to return 2, but the two
remaining entries will remain at key #0 and key #2. When the JTable
asks your model for data in row #0 it finds it and it displays fine, but
when the JTable asks your model for data in row #1 it returns null
because there is no HashMap entry for key #1. The JTable will never
ask your model for data in row#2 because getRowCount() returns 2.

If you really want to use HashMap, you should rewrite getRowCount()
to do something likeand in this case call fireTableRowsUpdated() instead of fireTableDeleted().



Two other things while I'm here:

(1) Your code would be easier to read if you used code tags. In fact,
you could edit your post (click on pencil-on-paper icon) and put them
in right now. Then your indentation would stick.

(2) Instead of the separate class's ActionListener doing
model.getTheData().remove(new Integer(indices[j]));
model.fireTableRowsDeleted(indices[j], indices[j]);

I would prefer to see it call something like
model.removeRow(indices[j]);
where removeRow() is a method you have added to your table model that
deletes the entry from the HashMap/ArrayList and calls fireTableRowsXxxx().
Don't you think that's better from a modularity standpoint?
[ April 11, 2008: Message edited by: Brian Cole ]
 
Ken Rubin
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Brian,

Thank you so much for spending the time to review my code and explaining the problem issues so clearly and adding value by the modularity observation.

The Hashmap was not appropriate for this application.

Best Wishes,

Ken
reply
    Bookmark Topic Watch Topic
  • New Topic