Logo VB-EDV-Beratung

VbDoubleField

Die Klasse VbDoubleField ist eine Erweiterung der Klasse JTextField, die Dezimal-Zahlen einliest. Dabei können die Stellenanzahl und andere Eigenschaften vorgegeben werden. Als zusätzliche Informationen werden
len die Länge des Feldes
dec die Anzahl der Dezimalstellen
maxSep die maximale Anzahl Tausender-Trennzeichen
maxDec die Anzahl der Dezimal-Trennzeichen (0 oder 1)
zero ob auf im Feld führende Nullen dargestellt werden sollen
thousandSeperator ob im Feld Tausender-Trennzeichen dargestellt werden sollen
df das DecimalFormat für die Darstellung
chSep das Tausender-Trennzeichen
chDec das Dezimal-Trennzeichen
gespeichert.

package vb;

import javax.swing.*;
import java.text.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.*;

public class VbDoubleField extends JTextField implements FocusListener{
    int len = 0, dec = 0, maxSep = 0, maxDec = 0;
    boolean zero = false,
            thousandSeparator = true;
    DecimalFormat df = new DecimalFormat();
    char chSep = '.',
         chDec = ',';

Den verschiedenen Konstruktoren kann man einige Eigenschaften gleich mitgeben.

    public VbDoubleField() {
        setup();
    }

    public VbDoubleField(int cols) {
        len = cols;
        setup();
    }

    public VbDoubleField(int cols, int frac) {
        len = cols;
        dec = frac;
        setup();
    }

    public VbDoubleField(double val, int cols, int frac) {
        len = cols;
        dec = frac;
        setup();
        setDouble(val);
    }

    public VbDoubleField(int cols, boolean sep) {
        len = cols;
        thousandSeparator = sep;
        setup();
    }

    public VbDoubleField(int cols, int frac, boolean sep) {
        len = cols;
        dec = frac;
        thousandSeparator = sep;
        setup();
    }

    public VbDoubleField(double val, int cols, int frac, boolean sep) {
        len = cols;
        dec = frac;
        thousandSeparator = sep;
        setup();
        setDouble(val);
    }

setup() und setupDf() machen die Initialisierung bzw. Änderungen.

    void setup(){
        setHorizontalAlignment(JTextField.RIGHT);
        addFocusListener(this);
        setupDf();
    }

    void setupDf(){
        StringBuffer bf = new StringBuffer(100);
        char digit = zero ? '0' : '#';
        int i;
        if (len < 1)
            len = 15;
        DecimalFormatSymbols fs = new DecimalFormatSymbols();
        chSep = fs.getGroupingSeparator();
        chDec = fs.getDecimalSeparator();
        maxDec = (dec > 0) ? 1 : 0;
        if (thousandSeparator){
            maxSep = (len-dec-maxDec-1) /3;
            for (i=0;i<len-3-dec-maxDec;i++)
                bf.append(digit);
            bf.append(',');
            bf.append(digit);
            bf.append(digit);
            bf.append('0');
        } else {
            maxSep = 0;
            for (i=0;i<len-1;i++)
                bf.append(digit);
            bf.append('0');
        }
        if (dec > 0) {
            bf.append('.');
            for (i=0;i<dec;i++)
                bf.append('0');
        }
        int width0 = getFontMetrics(getFont()).charWidth('0'),
            widthSep = getFontMetrics(getFont()).charWidth(chSep),
            widthDec = getFontMetrics(getFont()).charWidth(chDec);
        Dimension d = getPreferredSize();
        d.width = (len - maxDec)* width0 + maxSep * widthSep + maxDec * widthDec + 6;
        setPreferredSize(d);
        df = new DecimalFormat(bf.toString());
    }

Diese Methoden verändern einzelne Eigenschaften.

    public void setZeroes(boolean zr){
        zero = zr;
        setupDf();
    }

    public void setThousandSeparator(boolean th){
        thousandSeparator = th;
        setupDf();
    }

setDouble(double val) setzt den Text des Feldes auf den Wert von val.

    public void setDouble(double val){
        setText(df.format(val));
    }

getDouble() gibt den numerischen Wert des Feldes zurück und löst gegebenenfalls eine VbDialogException aus.

    public double getDouble() throws VbDialogException{
        double ret = 0;
        try {
            ret = df.parse(getText()).doubleValue();
        } catch (ParseException pe) {
            throw new VbDialogException(this,"falscher Wert '" + getText() + "'");
        }
        if (ret >= Math.pow(10,len-dec-maxDec))
            throw new VbDialogException(this,"Wert '" + getText() + "' ist zu groß");
        return ret;
    }

Wenn das Feld den Fokus verliert, soll der Inhalt ordentlich formatiert werden. focusGained ist nur da, damit das Interface FocusListener vollständig ist.

    public void focusLost(FocusEvent fe){
        if (!fe.isTemporary()) {
            try {
                setDouble(getDouble());
            } catch (VbDialogException vde) {
                Toolkit.getDefaultToolkit().beep();
            }
        }

    public void focusGained(FocusEvent fe){
    }

Damit nur Ziffern und Dezimaltrennzeichen und nur bis zur maximalen Länge eingegeben werden können, wird einfach als Dokumenten-Model ein eingeschränktes PlainDocument verwendet.

    protected class VbDoubleFieldDocument extends PlainDocument {
        public void insertString(int offs, String str, AttributeSet a)
            throws BadLocationException {
            if (str == null)
                return;
            int nSep = 0, nDig = 0, nDec = 0, i;
            char[] source = str.toCharArray(),
                   result = new char[source.length],
                   contents = getText(0,getLength()).toCharArray();

            for(i=0;i<contents.length;i++){
                if (contents[i] == chSep)
                    nSep++;
                else if (contents[i] == chDec)
                    nDec++;
                else
                    nDig++;
            }
            int j = 0;
            int maxLen = len - getLength();
            for (i = 0; i < source.length; i++) {
                if ((Character.isDigit(source[i]) && (nDig++ < len - maxDec)) ||
                    ((source[i] == chSep) && (nSep++ < maxSep)) ||
                    ((source[i] == chDec) && (nDec++ < maxDec)))
                    result[j++] = source[i];
                else {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
            super.insertString(offs, new String(result, 0, j), a);
        }
    }

    protected Document createDefaultModel() {
          return new VbDoubleFieldDocument();
    }

Und hier gibt's VbDoubleField.java noch mal im Stück.

© 2003 Volker Böhm Best viewed with any Browser Valid HTML 4.0