Reputation: 7744
I wrote a custom DefaultCellEditor
so that when I type in the length
column of the example JTable
I can not enter anything but numbers in it.
To do this I added a KeyListener
to the JTextField
that is used as the editor component. Whilst this works great if you double click on the cell to edit the value, it does not work if you click on the cell once and then start typing.
How can I prevent the user from being able to edit the cell if they click on the cell once and then start typing, whilst still allowing the user to double click on the cell to start editing it?
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.lang.reflect.Constructor;
import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
@SuppressWarnings("serial")
public class JTableTest extends JFrame {
private JTableTest() {
super("JTable Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
createPanel();
pack();
setVisible(true);
}
JPanel panel = new JPanel(new GridLayout(1, 1));
JScrollPane scroll;
private void createPanel() {
Object[] headers = {"Length", "Title"};
Object[][] sampleData = {{"673", "Bat Outta Hell"},
{"358", "Spanish Train"},
{"673", "Bat Outta Hell"}};
JTable table = new JTable(sampleData, headers);
table.setDefaultEditor(Object.class, new NumEditor());
scroll = new JScrollPane(table);
panel.add(scroll);
getContentPane().add(panel);
}
private class NumEditor extends DefaultCellEditor {
Class<?>[] argTypes = new Class<?>[]{String.class};
Constructor<?> constructor;
Object value;
public NumEditor() {
super(new JTextField());
getComponent().setName("Table.editor");
}
public boolean stopCellEditing() {
String s = (String)super.getCellEditorValue();
try {
if ("".equals(s)) {
if (constructor.getDeclaringClass() == String.class) {
value = s;
}
return super.stopCellEditing();
}
value = constructor.newInstance(new Object[]{s});
}
catch (Exception e) {
((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
return false;
}
return super.stopCellEditing();
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.value = null;
((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
try {
Class<?> type = table.getColumnClass(column);
if (type == Object.class) {
type = String.class;
}
KeyListener kL = new KeyListener() {
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if(Character.isDigit(c)){
} else {
e.consume();
}
}
};
if(column == 0)
((JComponent)getComponent()).addKeyListener(kL);
else
((JComponent)getComponent()).removeKeyListener(kL);
constructor = type.getConstructor(argTypes);
}
catch (Exception e) {
return null;
}
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
public Object getCellEditorValue() {
return value;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new JTableTest());
}
}
Upvotes: 1
Views: 205
Reputation: 324207
Stop JTable being editable only when focussed and key pressed
Well, this is the default behaviour when you edit a cell with string data.
Why should it be any different when you try to enter numeric data?
I wrote a custom DefaultCellEditor so that when I type in the length column of the example JTable I can not enter anything but numbers in it.
No need to write a custom editor. Just use a JFormattedTextField
as the editor instead of a JTextField:
Something like.
MaskFormatter format = new MaskFormatter("######");
JFormattedTextField ftf = new JFormattedTextField( format );
DefaultCellEditor dce = new DefaultCellEditor( ftf );
table.getColumnModel().getColumn(2).setCellEditor(dce);
Upvotes: 3
Reputation: 7744
Referring to TT.'s answer and using a DefaultCellEditor
like the original question does it is as simple as adding this method in your DefaultCellEditor
.
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
}
return false;
}
Upvotes: 1
Reputation: 16144
Take a look at CellEditor.isCellEditable( EventObject anEvent )
. AbstractCellEditor
and DefaultCellEditor
implement the CellEditor
interface.
You can override this method to return false in case the EventObject
is instance of type KeyEvent
. Otherwise return super.isCellEditable( anEvent )
.
Upvotes: 2