package kleurapplet.grnuminput; import java.awt.*; import java.awt.event.*; import java.text.DecimalFormat; import java.util.Vector; /** * Class NumOnlyField assist the main components of the grnuminput package. * It provides a TextField with number checking features. It tells its users of changes * using the NumberListener interface. */ class NumOnlyField extends TextField implements KeyListener, FocusListener { private double waarde; private double initw; // initial value private double minw; private double maxw; private int decimals; // number of decimals private long truncator; // intermediate when fixing decimals private double fact; // = Math.pow(10,decimals) private DecimalFormat df; private boolean enabled = true; private static Color enabledValueColor = Color.black; private static Color disabledValueColor = Color.gray; private Vector listeners; // too much, there will be only one public NumOnlyField(double mn, double mx, double val, int dec) { super(); addKeyListener(this); addFocusListener(this); listeners = new Vector(); setBackground(Color.white); setForeground(enabledValueColor); waarde = val; initw = val; minw = mn; maxw = mx; decimals = dec; fact = Math.pow(10,decimals); String dfstring; // create template-string for number formatting if ( dec == 0 ) { dfstring = "0"; } else { dfstring = "0."; for ( int i=0; i<dec; i++ ) // append zero for every decimal { dfstring = dfstring.concat("0"); } } df = new DecimalFormat(dfstring); int mnl = df.format(minw).length(); // determine width, will be the max of int mxl = df.format(maxw).length(); // lengths minw and maxw + 1 setColumns(Math.max(mnl, mxl)+1); setValue(val); // sets Text, needs df } public void addNumberListener(NumberListener l) { listeners.addElement(l); } private void tellListeners() // passes empty string name!!! { for ( int i=0; i<listeners.size(); i++ ) { ( (NumberListener)listeners.elementAt(i) ).numberChanged("", waarde); } } // Public methods: enable, set-, getValue.... public void setEnabled(boolean b) { enabled = b; setEditable(b); if ( b ) { setForeground(enabledValueColor); } else { setForeground(disabledValueColor); } } public void setValue(double newval) { if ( newval > maxw ) { waarde = maxw; } else if (newval < minw ) { waarde = minw; } else { waarde = setDecimals(newval); // truncate } setText( df.format(waarde) ); } public double getValue() { return waarde; } // private help methods: convert string to number, // truncate number to required number of decimals private double setDecimals(double val) // returns val, truncated to { truncator = Math.round( val*fact ); // required number of decimals return ((double)truncator) / fact; } private void processTextChange(String s) { try // no need to test 'enabled', user can't type then { Number f = df.parse( s.trim() ); double w = f.doubleValue(); if ( w < minw ) { throw new NumberFormatException("getal te klein"); } if ( w > maxw ) { throw new NumberFormatException("getal te groot"); } w = setDecimals(w); if ( w != waarde ) // only when value changed! { waarde = w; setText( df.format(waarde) ); tellListeners(); } } catch (Exception exc) { setText( df.format(waarde) ); // just reset previous input } } public void checkValue() { processTextChange( getText() ); } // Listeners, KeyListener (check out adapters later, compiler freeze on first try!!! public void keyReleased(KeyEvent e) { if ( e.getKeyCode() == KeyEvent.VK_ENTER ) // Is it 'virtual key' Enter? { processTextChange( getText() ); } } public void keyTyped(KeyEvent e) { // don't react } public void keyPressed(KeyEvent e) { // don't react } // Listeners, FocusListener public void focusLost(FocusEvent e) { if ( !e.isTemporary() ) { processTextChange( getText() ); } } public void focusGained(FocusEvent e) { // don't react } }