Don't use a KeyListener
. What you can do instead is use a JTextField
for the TableCellEditor
and just add a DocumentFilter
to the JTextField
that allows only numbers.
Here's a running example
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;
public class JTableNumberColumn {
public JTableNumberColumn() {
JFrame frame = new JFrame();
JTextField field = createTextField();
frame.add(new JScrollPane(createTable(field)));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JTextField createTextField() {
JTextField field = new JTextField();
((AbstractDocument) field.getDocument()).setDocumentFilter(new DocumentFilter() {
@Override
public void insertString(FilterBypass fb, int off, String str, AttributeSet attr)
throws BadLocationException {
fb.insertString(off, str.replaceAll("\\D++", ""), attr); // remove non-digits
}
@Override
public void replace(FilterBypass fb, int off, int len, String str, AttributeSet attr)
throws BadLocationException {
fb.replace(off, len, str.replaceAll("\\D++", ""), attr); // remove non-digits
}
});
return field;
}
private JTable createTable(final JTextField field) {
String[] cols = {"Only Numbers", "Col 2", "Col 3"};
String[][] data = {{null, null, null}, {null, null, null}, {null, null, null}};
final TableCellEditor editor = new DefaultCellEditor(field);
JTable table = new JTable(data, cols) {
@Override
public TableCellEditor getCellEditor(int row, int column) {
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 0) {
return editor;
} else {
return super.getCellEditor(row, column);
}
}
};
return table;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTableNumberColumn();
}
});
}
}
EDIT 1
I may have misread your question. If you want to allow only one number. then you can use a JFormattedTextField
with a MaskFormatter
as the TableCellEditor
. Here's an example
import javax.swing.DefaultCellEditor;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
import javax.swing.text.MaskFormatter;
public class JTableNumberColumn {
public JTableNumberColumn() {
JFrame frame = new JFrame();
JFormattedTextField field = createFormattedTextField();
frame.add(new JScrollPane(createTable(field)));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JFormattedTextField createFormattedTextField() {
JFormattedTextField field = new JFormattedTextField(createFormatter("#"));
return field;
}
protected MaskFormatter createFormatter(String s) {
MaskFormatter formatter = null;
try {
formatter = new MaskFormatter(s);
} catch (java.text.ParseException exc) {
System.err.println("formatter is bad: " + exc.getMessage());
System.exit(-1);
}
return formatter;
}
private JTable createTable(final JFormattedTextField field) {
String[] cols = {"Only Numbers", "Col 2", "Col 3"};
String[][] data = {{null, null, null}, {null, null, null}, {null, null, null}};
final TableCellEditor editor = new DefaultCellEditor(field);
JTable table = new JTable(data, cols) {
@Override
public TableCellEditor getCellEditor(int row, int column) {
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 0) {
return editor;
} else {
return super.getCellEditor(row, column);
}
}
};
return table;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTableNumberColumn();
}
});
}
}
EDIT 2
It has been brought to my attention I also overlooked the fact that you only want 1-9 and not 0-9. In that case I would just stick with the first option of the JTextField
with DocumentFilter
, but in the filter, check the length of the input and change the regex to allow only 1-9.
Here's the example
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;
public class JTableNumberColumn {
public JTableNumberColumn() {
JFrame frame = new JFrame();
JTextField field1 = createTextField();
frame.add(new JScrollPane(createTable(field1)));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JTextField createTextField() {
final JTextField field = new JTextField();
((AbstractDocument) field.getDocument()).setDocumentFilter(new DocumentFilter() {
@Override
public void insertString(FilterBypass fb, int off, String str, AttributeSet attr)
throws BadLocationException {
int length = field.getDocument().getLength();
if (length + str.length() <= 1) {
fb.insertString(off, str.replaceAll("[^1-9]", ""), attr); // remove non-digits
}
}
@Override
public void replace(FilterBypass fb, int off, int len, String str, AttributeSet attr)
throws BadLocationException {
int length = field.getDocument().getLength();
if (length + str.length() <= 1) {
fb.replace(off, len, str.replaceAll("[^1-9]", ""), attr); // remove non-digits
}
}
});
return field;
}
private JTable createTable(final JTextField field) {
String[] cols = {"Only Numbers", "Col 2", "Col 3"};
String[][] data = {{null, null, null}, {null, null, null}, {null, null, null}};
final TableCellEditor editor = new DefaultCellEditor(field);
JTable table = new JTable(data, cols) {
@Override
public TableCellEditor getCellEditor(int row, int column) {
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 0) {
return editor;
} else {
return super.getCellEditor(row, column);
}
}
};
return table;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTableNumberColumn();
}
});
}
}