|
/* |
|
* Table with numeric input and length checks. |
|
* Şamil Korkmaz, June 2022 |
|
*/ |
|
package tablewithnumericinput; |
|
|
|
import java.awt.Color; |
|
import java.awt.event.KeyEvent; |
|
import java.awt.event.KeyListener; |
|
import javax.swing.DefaultCellEditor; |
|
import javax.swing.InputVerifier; |
|
import javax.swing.JButton; |
|
import javax.swing.JComponent; |
|
import javax.swing.JFrame; |
|
import javax.swing.JOptionPane; |
|
import javax.swing.JScrollPane; |
|
import javax.swing.JTable; |
|
import javax.swing.JTextField; |
|
import javax.swing.table.DefaultTableModel; |
|
|
|
public class TableWithNumericInput { |
|
|
|
static private JTextField jtfForNumericFields; |
|
|
|
static class MyKeyListener implements KeyListener { |
|
|
|
@Override |
|
public void keyTyped(KeyEvent ke) { |
|
if (ke.getKeyCode() != KeyEvent.VK_BACK_SPACE && ke.getKeyCode() != KeyEvent.VK_DELETE) { |
|
char c = ke.getKeyChar(); |
|
System.out.println("c = " + c); |
|
System.out.println("Inside keyTyped()"); |
|
if (ke.getSource() instanceof JTextField) { //When user first double clicks on table and then presses a key, jtf will be the key event source |
|
System.out.println("Key event source is text field"); |
|
} else if (ke.getSource() instanceof JTable) { //When table has focus but user has not double clicked on it, table will be the key event source |
|
System.out.println("Key event source is table"); |
|
} |
|
try { |
|
Double.parseDouble(jtfForNumericFields.getText() + c); //getText() returns text before keypress, we have to add pressed key char to get full text |
|
if (c == 'd' || c == 'f') { //parseDouble accepts 'd' and 'f' at the end of text |
|
ke.consume(); //ignore key press |
|
} else { |
|
if (!jtfForNumericFields.getInputVerifier().verify(jtfForNumericFields)) { //check if text exceeds max nb of characters |
|
ke.consume(); //ignore key press |
|
} |
|
} |
|
} catch (NumberFormatException e) { //text is not a number |
|
ke.consume(); //ignore key press |
|
} |
|
} |
|
} |
|
|
|
@Override |
|
public void keyPressed(KeyEvent ke) { |
|
} |
|
|
|
@Override |
|
public void keyReleased(KeyEvent ke) { |
|
} |
|
} |
|
|
|
static class MyTable extends JTable { |
|
|
|
public MyTable() { |
|
putClientProperty("terminateEditOnFocusLost", true); //To make sure that setValue() is called when user clicks on another component, e.g. a button. |
|
} |
|
|
|
@Override |
|
public void setValueAt(Object value, int iRow, int iColumn) { |
|
if (value != null && ((String)value).length() > 0) { |
|
if (iColumn > 0) { |
|
double doubleValue = Double.parseDouble((String)value); |
|
super.setValueAt(doubleValue, iRow, iColumn); |
|
} else { |
|
super.setValueAt(value, iRow, iColumn); |
|
} |
|
|
|
} |
|
} |
|
} |
|
|
|
public static void main(String[] args) { |
|
JFrame jf = new JFrame(); |
|
jf.setTitle("Table with numeric input checks"); |
|
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
|
jf.getContentPane().setLayout(new javax.swing.BoxLayout(jf.getContentPane(), javax.swing.BoxLayout.PAGE_AXIS)); |
|
JTable jt = new MyTable(); |
|
jf.add(new JScrollPane(jt)); //to show table column headers |
|
JButton jb = new JButton("OK"); |
|
jb.addActionListener((java.awt.event.ActionEvent evt) -> { |
|
JOptionPane.showMessageDialog(jf, "Table contents: " + jt.getValueAt(0, 0) + ", " + jt.getValueAt(0, 1)); |
|
}); |
|
jf.add(jb); |
|
jf.setBounds(100, 100, 400, 150); |
|
|
|
jt.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLACK)); |
|
DefaultTableModel model = new DefaultTableModel() { |
|
Class[] types = new Class[]{String.class, Double.class}; |
|
|
|
@Override |
|
public Class getColumnClass(int iCol) { |
|
return types[iCol]; |
|
} |
|
}; |
|
jt.setModel(model); |
|
model.addColumn("ID"); |
|
model.addColumn("Double Value"); |
|
|
|
model.addRow(new Object[]{}); |
|
final int PANEL_WIDTH = 200; |
|
final int TABLE_HEIGHT = 3 * jt.getRowHeight(); |
|
jt.setBounds(0, jt.getRowHeight(), PANEL_WIDTH, TABLE_HEIGHT); |
|
jt.getTableHeader().setBounds(0, 0, PANEL_WIDTH, jt.getRowHeight()); |
|
|
|
jtfForNumericFields = new JTextField(); |
|
jtfForNumericFields.setInputVerifier(new InputVerifier() { |
|
@Override |
|
public boolean verify(JComponent jc) { |
|
JTextField jtf = (JTextField) jc; |
|
String text = jtf.getText(); |
|
System.out.println("Text: " + text); |
|
final int maxLength = 9; |
|
if (text.length() > (maxLength - 1)) { |
|
System.out.println("length > " + maxLength); |
|
return false; |
|
} |
|
return true; |
|
} |
|
}); |
|
//Note that we have to add key listener to both table and text field because when |
|
//table column 1 has focus and user presses a key, editing will start and table will catch |
|
//key events. If user double click on column 1, then text field will catch key events: |
|
jt.addKeyListener(new MyKeyListener()); |
|
jtfForNumericFields.addKeyListener(new MyKeyListener()); |
|
//Use numeric text field as editor for column 1 (second column): |
|
jt.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(jtfForNumericFields)); |
|
|
|
jf.setVisible(true); |
|
} |
|
|
|
} |