Save JTable data on Resize
Good afternoon all.
I have several panels in my JFrame wndow, each with a JTable.
Whenever the user is editing a cell, and drastically resizes the window without the cell exiting edit mode, the cell loses its contents.
Is there any way to retain the contents of the cell on a resize, maybe stopping edit mode?
Thanks,
Jonathan
When you create the table try using:table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
Thanks for your input.
I actually have that for when users click on another table while leaving the previous editor in edit mode. It works for that situation. But it doesn't work in this situation.
For some reason, clicking on the window edge to resize doesn't take away focus from the cell.
It seems like the entire contentPane is refreshing everything.
Message was edited by:
bvarianlvr
it *should* work. here's a piece of JTable code responsible for handling editing state when the table looses focus:
class CellEditorRemover implements PropertyChangeListener {
KeyboardFocusManager focusManager;
public CellEditorRemover(KeyboardFocusManager fm) {
this.focusManager = fm;
}
public void propertyChange(PropertyChangeEvent ev) {
if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
return;
}
Component c = focusManager.getPermanentFocusOwner();
while (c != null) {
if (c == JTable.this) {
// focus remains inside the table
return;
} else if ((c instanceof Window) ||
(c instanceof Applet && c.getParent() == null)) {
if (c == SwingUtilities.getRoot(JTable.this)) {
if (!getCellEditor().stopCellEditing()) {
getCellEditor().cancelCellEditing();
}
}
break;
}
c = c.getParent();
}
}
}
as you can see, cancelCellEditing() is only called if stopCellEditing() fails.
Could you write a short self-contained program exhibiting this behavior?
There's a lot of code everywhere, and I don't subclass JTable like the code snippet seems to imply I might be doing.
I basically have such:
ipTable = new JTable();
IPTableModel ipModel = new IPTableModel(userID);
ipTable.setModel(ipModel);
ipScroll = new JScrollPane();
ipScroll.getViewport().add(ipTable);
ipPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ipPanel.add(ipl);
ipPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ipPanel.add(ipScroll);
ipPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ipTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
ipTable.addPropertyChangeListener()
ipTable.addMouseListener(new java.awt.event.MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
webmine.db_search.gui.MainGUIFrame.interruptEvent();
}
public void mouseReleased(MouseEvent e)
{
tableSelected((JTable)e.getSource());
}
});
final JTable t = ipTable;
ipTable.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(KeyEvent e) {
webmine.db_search.gui.MainGUIFrame.interruptEvent();
tableKeyTyped(t, e);
}
});
refreshTable(ipTable);
code for refreshTable() is:
private void refreshTable(JTable table)
{
// start rkd changes
JTextField tf = new JTextField();
tf.setBackground(Color.lightGray);
tf.setFont(new java.awt.Font("Arial", 0, 11));
DefaultCellEditor dtce = new DefaultCellEditor(tf);
dtce.setClickCountToStart(2); // must double-click to start editing-
// one click is just row selection
table.setDefaultEditor(String.class, dtce);
table.setCellEditor(dtce);
final JTable t = table;
table.setToolTipText("Double Click to Modify");
tf.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(KeyEvent e) {
tableKeyTyped(t, e);
}
});
tf.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(FocusEvent e) {
aText_focusGained(e);
}
});
}
So, where would I put the previous poster's code?
Just checked some of my table examples and none of them have a problem.
Your code doesn't provide much help, although I do see you have some Mouse and Key listeners. So maybe you need to add the following code to the methods they invoke:
if ( table.isEditing() )
{
table.getCellEditor().stopCellEditing();
}
If you need further help then you need to create a [url http://homepage1.nifty.com/algafield/sscce.html]Short, Self Contained, Compilable and Executable, Example Program[/url] (SSCCE) that demonstrates the incorrect behaviour, because I can't guess exactly what you are doing based on the information provided.
And don't forget to use the [url http://forum.java.sun.com/help.jspa?sec=formatting]Code Formatting Tags[/url] so the code retains its original formatting.
>
>
> Your code doesn't provide much help, although I do
> see you have some Mouse and Key listeners.
That's the thing. I'm not doing anything special with my JTables. Just adding them to a JScrollPane, and adding the JScrollPane to a JPanel.
Here's the entire method with 1 panel holding 2 panels, etc:
private void createCommentPanel() {
// holds both panels
ciPanel = new JPanel();
ciPanel.setLayout(new BoxLayout(ciPanel, BoxLayout.X_AXIS));
ciPanel.setPreferredSize(new Dimension(width - 10, height / 10));
ipPanel = new JPanel();
ipPanel.setLayout(new BoxLayout(ipPanel, BoxLayout.X_AXIS));
ipPanel.setSize(new Dimension(((width-10) / 4)-6, height/10));
ipPanel.setBorder(new TitledBorder(BorderFactory
.createLineBorder(Color.gray), "Enter an IP Address"));
JLabel ipl = new JLabel("IP: ");
ipTable = new JTable();
IPTableModel ipModel = new IPTableModel(userID);
ipTable.setModel(ipModel);
ipScroll = new JScrollPane();
ipScroll.getViewport().add(ipTable);
ipPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ipPanel.add(ipl);
ipPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ipPanel.add(ipScroll);
ipPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ipTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
//ipTable.addPropertyChangeListener()
ipTable.addMouseListener(new java.awt.event.MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
webmine.db_search.gui.MainGUIFrame.interruptEvent();
//tblAddress_mouseClicked(e);
}
public void mouseReleased(MouseEvent e)
{
tableSelected((JTable)e.getSource());
}
});
final JTable t = ipTable;
ipTable.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(KeyEvent e) {
webmine.db_search.gui.MainGUIFrame.interruptEvent();
tableKeyTyped(t, e);
}
});
refreshTable(ipTable);
commentPanel = new JPanel();
commentPanel.setSize(new Dimension((((width-10)/4)*3-6), height / 10));
commentPanel.setBorder(new TitledBorder(BorderFactory
.createLineBorder(Color.gray), "Enter a Comment"));
commentLabel.setText("Comment:");
// gCommentArea.setPreferredSize(new Dimension(width/2, height/10));
gCommentScroll.getViewport().add(gCommentArea, null);
gCommentScroll.setPreferredSize(new Dimension(width / 2, height / 10));
gCommentScroll.setMinimumSize(new Dimension(width / 2, height / 10));
gCommentScroll.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
webmine.db_search.gui.MainGUIFrame.interruptEvent();
}
});
commentPanel.setLayout(new BoxLayout(commentPanel, BoxLayout.X_AXIS));
commentPanel.add(Box.createRigidArea(new Dimension(10, 5)));
commentPanel.add(commentLabel, null);
commentPanel.add(Box.createRigidArea(new Dimension(10, 5)));
commentPanel.add(gCommentScroll, null);
commentPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ciPanel.add(ipPanel);
ciPanel.add(Box.createRigidArea(new Dimension(10, 5)));
ciPanel.add(commentPanel);
}
And the IPTableModel:
public class IPTableModel extends AbstractTableModel
{
private Vector dataVector;// hold profile_tb info
private Vector headingVector; // heading
public IPTableModel(String userId)
{
try
{
initHeader();
//default to 6 rows for now
for (int i = 0; i < 7; i++)
{
addEmptyRow();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void initHeader() throws Exception
{
headingVector = new Vector();
headingVector.addElement("IP Address");
dataVector = new Vector();
}
/**
* get isRowDirty value for the incoming row
*/
private String getIsRowDirty(int row)
{
return getValueAt(row, 0).toString();
}
/**
* deleteRow:
*/
public void deleteRow(int row)
{
dataVector.removeElementAt(row);
fireTableDataChanged();
}
/**
* addEmptyRow: Add an empty row for entering more addresses
*/
public void addEmptyRow()
{
Vector vt = new Vector();
vt.addElement("");
dataVector.addElement(vt);
fireTableDataChanged ();
}
// The following three methods always need to be implemented.
public int getColumnCount()
{
return headingVector.size();
}
public int getRowCount()
{
return dataVector.size();
}
public Object getValueAt(int row, int col)
{
Vector rowVector = (Vector)dataVector.elementAt(row);
return rowVector.elementAt(col);
}
// The default implementations of these four methods in
// AbstractTableModel would work, but we can refine them.
public String getColumnName(int column) {
return headingVector.elementAt(column).toString();
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/**
* isCellEditable: Set column profile name to editable.
*/
public boolean isCellEditable(int row, int col)
{
return true;
}
/**
* setValueAt: This is where values are changing.
* 1. Insert a new address
* 2. Update a address.
*/
public void setValueAt(Object aValue, int row, int col)
{
((Vector)dataVector.elementAt(row)).setElementAt(aValue, col);
fireTableCellUpdated(row, col);
} // end setValueAt
}
As you can see, nothing special. I'm hoping there's some type of property to set so that the cell will either remain in edit state when the window is resized, or stop editing and retain the information entered.
When the cell loses its information and goes to non-edit state, it looks as if the entire contentPane has refreshed, there's a flicker.
Thanks.
Fascinating, there are 6 tables in the window, each in it's own panel. But only 2 exhibit the behavior I'm writing about. I'll do more research and see why some do that and some don't. I'm starting to suspect the layout managers, or maybe something like a minimum or maximum size.
I asked for a SSCCE. The code you posted isn't compileable or executable.
> That's the thing. I'm not doing anything special with my JTables.
Then why is your posted code so long? There is no need to post a custom TableModel (I don't even know why you create one in the first place since the DefaultTableModel will do what you want). It only takes 3 lines of code to create a table add it to a scrollpane:
JTable table = new JTable(5, 10);
JScrollPane scrollPane = new JScrollPane( table );
getContentPane().add( scrollPane );
So get you code working in a simple SSCCE, then make it a little more complex until it resembles you current program. Then when it stops working you will know what change you made to cause the problem.
Seems its the layout managers that cause the problem. Both BorderLayout and BoxLayout exhibit the issues that I'm having trouble with.
package webmine.db_search.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableModel;
public class TableTestFrame extends JFrame
{
JPanel contentPane = null;
JPanel ipPanel = null;
JTable ipTable = null;
JScrollPane ipScroll = null;
public TableTestFrame()
{
initialize();
}
private void initialize()
{
contentPane = new JPanel();
contentPane.setBackground(Color.black);
contentPane.setPreferredSize(new Dimension(250,150));
//contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS));
contentPane.setLayout(new BorderLayout());
setContentPane(contentPane);
ipPanel = new JPanel();
ipPanel.setBorder(new TitledBorder(BorderFactory
.createLineBorder(Color.gray), "Enter an IP Address"));
ipPanel.setLayout(new BoxLayout(ipPanel, BoxLayout.X_AXIS));
ipPanel.setBackground(Color.pink);
//ipPanel.setPreferredSize(new Dimension(500, 450));
String[] header = {"IP"};
DefaultTableModel dtm = new DefaultTableModel(header, 4);
ipTable = new JTable(dtm);
ipTable.setPreferredSize(new Dimension(500, 450));
ipScroll = new JScrollPane(ipTable);
//ipScroll.setPreferredSize(new Dimension(500, 450));
ipPanel.add(ipScroll);
contentPane.add(ipTable);
pack();
show();
}
public static void main(String[] args) {
TableTestFrame ttf = new TableTestFrame();
}
}
The following seems to work:
ipTable = new JTable(dtm)
{
public void columnMarginChanged(ChangeEvent e)
{
if ( isEditing() )
{
getCellEditor().stopCellEditing();
}
super.columnMarginChanged(e);
}
};
You rock, dude! I wish I had some duke dollars to dispense. That sure saved my neck. Thanks man!