How to Mark Jtable Cell Input as Invalid

How to mark JTable cell input as invalid?

The private static class JTable.GenericEditor uses introspection to catch exceptions raised by constructing specific Number subclasses with invalid String values. If you don't need such generic behavior, consider creating PositiveIntegerCellEditor as a subclass of DefaultCellEditor. Your stopCellEditing() method would be correspondingly simpler.

Addendum: Updated to use RIGHT alignment and common error code.

Addendum: See also Using an Editor to Validate User-Entered Text.

Sample Image

    private static class PositiveIntegerCellEditor extends DefaultCellEditor {

private static final Border red = new LineBorder(Color.red);
private static final Border black = new LineBorder(Color.black);
private JTextField textField;

public PositiveIntegerCellEditor(JTextField textField) {
super(textField);
this.textField = textField;
this.textField.setHorizontalAlignment(JTextField.RIGHT);
}

@Override
public boolean stopCellEditing() {
try {
int v = Integer.valueOf(textField.getText());
if (v < 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
textField.setBorder(red);
return false;
}
return super.stopCellEditing();
}

@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
textField.setBorder(black);
return super.getTableCellEditorComponent(
table, value, isSelected, row, column);
}
}

Validating and highlighting JTable Cell

@kleopatra and @mKorbel are correct. Your fragment is incomplete, but it appears as if you are trying to solve editor and model problems in the renderer.

You can validate entered values in a custom TableCellEditor, as shown in this example. You can handle dependent columns in the TableModel, as shown in this example.

In a comment you say, "If I am not wrong, prepareRenderer() needs looping of all the rows, right?"

No, JTable "internal implementations always use this method to prepare renderers so that this default behavior can be safely overridden by a subclass." Overriding prepareRenderer() is most useful when changes must be be selectively applied to all renderers.

See Concepts: Editors and Renderers for more details.

Simple Edittable JTable With Input Validation

I know that to get the formatting correct, I have to subclass DefaultTableCellRenderer however I am not really sure of exactly what I need in the getTableCellRendererComponent() method.

See Table Format Rendering for the easy way to do this. This approach simply overrides the setValue(...) method of the renderer.

I am pretty sure I will have to subclass DefaultCellEditor to get the editing and error checking to work properly.

Here is some old code I found on a forum somewhere that creates a custom IntegerEditor. The first column uses the default Integer editor and the second column uses the custom editor.

import java.awt.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.text.*;
import java.text.*;
import java.awt.event.*;
public class TableIntegerEditor
{
static class IntegerEditor extends DefaultCellEditor
{
JFormattedTextField ftf;
NumberFormat integerFormat;
private Integer minimum, maximum;
private boolean DEBUG = false;

public IntegerEditor(int min, int max)
{
super(new JFormattedTextField());

setClickCountToStart(2);

ftf = (JFormattedTextField)getComponent();
ftf.setBorder(new LineBorder(Color.BLACK));
minimum = new Integer(min);
maximum = new Integer(max);

//Set up the editor for the integer cells.
integerFormat = NumberFormat.getIntegerInstance();
NumberFormatter intFormatter = new NumberFormatter(integerFormat);
intFormatter.setFormat(integerFormat);
intFormatter.setMinimum(minimum);
intFormatter.setMaximum(maximum);

ftf.setFormatterFactory(new DefaultFormatterFactory(intFormatter));
ftf.setValue(minimum);
ftf.setHorizontalAlignment(JTextField.TRAILING);
ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);

//React when the user presses Enter while the editor is
//active. (Tab is handled as specified by
//JFormattedTextField's focusLostBehavior property.)
ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check");

ftf.getActionMap().put("check", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if (!ftf.isEditValid()) //The text is invalid.
{
if (userSaysRevert())
{
ftf.postActionEvent(); //inform the editor
}
}
else
try
{
ftf.commitEdit(); //so use it.
ftf.postActionEvent(); //stop editing
}
catch (java.text.ParseException exc) { }
}
});
}

@Override
public boolean isCellEditable(EventObject event)
{
JTable table = (JTable)event.getSource();
return true;
}

//Override to invoke setValue on the formatted text field.
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
JFormattedTextField ftf = (JFormattedTextField)super.getTableCellEditorComponent(
table, value, isSelected, row, column);
ftf.setValue(value);

return ftf;
}

//Override to ensure that the value remains an Integer.
public Object getCellEditorValue()
{
JFormattedTextField ftf = (JFormattedTextField)getComponent();
Object o = ftf.getValue();
if (o instanceof Integer)
{
return o;
}
else if (o instanceof Number)
{
return new Integer(((Number)o).intValue());
}
else
{
try
{
return integerFormat.parseObject(o.toString());
}
catch (ParseException exc)
{
System.err.println("getCellEditorValue: can't parse o: " + o);
return null;
}
}
}

//Override to check whether the edit is valid,
//setting the value if it is and complaining if
//it isn't. If it's OK for the editor to go
//away, we need to invoke the superclass's version
//of this method so that everything gets cleaned up.
public boolean stopCellEditing()
{
JFormattedTextField ftf = (JFormattedTextField)getComponent();

if (ftf.isEditValid())
{
try
{
ftf.commitEdit();
}
catch (java.text.ParseException exc) { }

}
else
{
if (!userSaysRevert()) //user wants to edit
{
return false; //don't let the editor go away
}
}

return super.stopCellEditing();
}

/**
* Lets the user know that the text they entered is
* bad. Returns true if the user elects to revert to
* the last good value. Otherwise, returns false,
* indicating that the user wants to continue editing.
*/
protected boolean userSaysRevert() {
Toolkit.getDefaultToolkit().beep();
ftf.selectAll();
Object[] options = {"Edit",
"Revert"};
int answer = JOptionPane.showOptionDialog(
SwingUtilities.getWindowAncestor(ftf),
"The value must be an integer between "
+ minimum + " and "
+ maximum + ".\n"
+ "You can either continue editing "
+ "or revert to the last valid value.",
"Invalid Text Entered",
JOptionPane.YES_NO_OPTION,
JOptionPane.ERROR_MESSAGE,
null,
options,
options[1]);

if (answer == 1) { //Revert!
ftf.setValue(ftf.getValue());
return true;
}
return false;
}

}

private static void createAndShowGUI()
{
String[] columnNames = {"String", "Integer", "Integer2"};
Object[][] data =
{
{"a", new Integer(1), new Integer(10)},
{"b", new Integer(2), new Integer(20)},
{"c", new Integer(3), new Integer(30)}
};

JTable table = new JTable(data, columnNames)
{
public Class getColumnClass(int column)
{
if (column == 0)
return String.class;
else
return Integer.class;
}

};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );

table.getColumnModel().getColumn(2).setCellEditor( new IntegerEditor(0, 200) );

DefaultCellEditor editor = (DefaultCellEditor)table.getDefaultEditor(Integer.class);
JComponent border = (JComponent)editor.getComponent();
border.setBorder( BorderFactory.createLineBorder( Color.RED ) );

JFrame frame = new JFrame("Integer Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}

public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}

}

If you just want to use the default Double editor, then you just need to change the column class to be Double.class for your column. If you need special editing then you will need to customize the IntegerEditor for your double requirements.

How to add an input value listener to a JTable?

As shown in How to Use Tables, you can make every cell editable by choosing how you construct your TableModel. For control of individual cells, override isCellEditable() in your TableModel. If you still have problems, please edit your question to include an sscce that shows your chosen approach.

Addendum: I just was curious if there is a "Input" listener.

You may be looking for a TableCellEditor, seen here and here.

validate a table's cell using editors

Override stopCellEditing() and implement the condition inside it.

 class PasswordEditor extends DefaultCellEditor 
{

TextBox m_passWord = new TextBox();
public PasswordEditor() {
super(new TextBox());
}

@Override
public boolean stopCellEditing()
{
if(getCellEditorValue().toString().length() < 8)
{
JOptionPane.showMessageDialog(UsmUserView.this.m_Parent, "Password Must Be 8 Bytes Long !! Please Check");
return false;
}
fireEditingStopped();
return true;
}

@Override
public Object getCellEditorValue() {

return this.m_passWord.getText();
}

@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {

Object fieldValue = value;
if(null == fieldValue)
fieldValue = Constants.EMPTY_STRING;

this.m_passWord.setEditable(true);
this.m_passWord.setText(fieldValue.toString());
return this.m_passWord;
}

}

how to force cell editor in jtable to accept edits

You can manually call:

JTable table;
table.getCellEditor().stopCellEditing();

This should cause the table to stop editing at that cell. By overriding the stopCellEditing() method of your TableCellEditor and returning false under certain circumstances, you can indicate that the cell's value is currently invalid and thus editing cannot be stopped at that time.



Related Topics



Leave a reply



Submit