Prüfung von Textfeldern

MScalli

Erfahrenes Mitglied
Hi Leutz.
Ich Prüfe TFormattedTextFields bei der eingabe ab und habe jetzt zwei Probleme.
Habe jetzt mal ein ein lauffähiges Prog dazu geschrieben damit sich das jemand anschauen kann.

mein 1 Problem.
sobald ich nur eine 1 stellige oder 2 stellige zahl eingebe, gibt er sie 2 mal aus..

z.B. eingabe 1 ausgabe 1,001,00

kann sich das bitte wer anschauen

Code:
import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class TestJFormattedTextField {

	TestJFormattedTextField(){
		JFrame frame = new JFrame();
		frame.setSize(400,400);
		
		JLabel lbl;
		final JFormattedTextField tf_selbstkosten, tf_vk_preis1;
		JPanel panel = new JPanel();
		
		frame.add(panel);
		panel.setLayout(null);
		
		lbl = new JLabel("Selbstkosten");
		lbl.setBounds(10, 15, 100, 25);
		panel.add(lbl);
			tf_selbstkosten = new JFormattedTextField();
			tf_selbstkosten.setDocument(new DecimalDocument(10));
			tf_selbstkosten.setBounds(130, 15, 100, 25);
			tf_selbstkosten.setHorizontalAlignment(javax.swing.JTextField.RIGHT); 
			tf_selbstkosten.addFocusListener(new FocusListener(){
				public void focusGained(FocusEvent arg0) {
					tf_selbstkosten.setBackground(Color.YELLOW);
				}
				public void focusLost(FocusEvent arg0) {
					MyPrepareClass.prepareDecimal(tf_selbstkosten, "######0.00", 10, 2);
					tf_selbstkosten.setBackground(Color.WHITE);
				}
			});
		    panel.add(tf_selbstkosten);
		    
	    lbl = new JLabel("VK-Preis 1");
	    lbl.setBounds(10, 40, 100, 25);
	    panel.add(lbl);
	      tf_vk_preis1 = new JFormattedTextField();
	      tf_vk_preis1.setDocument(new DecimalDocument(10)); 
	      tf_vk_preis1.setBounds(130, 40, 100, 25);
	      tf_vk_preis1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
	      tf_vk_preis1.addFocusListener(new FocusListener(){
	        public void focusGained(FocusEvent arg0) {
	          tf_vk_preis1.setBackground(Color.YELLOW);
	        }
	        public void focusLost(FocusEvent arg0) {
	          MyPrepareClass.prepareDecimal(tf_vk_preis1, "######0.00", 10, 2);
	          tf_vk_preis1.setBackground(Color.WHITE);
	        }
	      });
	        panel.add(tf_vk_preis1);
	        
		frame.setVisible(true);
	}
	
	public static void main(String[] args) {
		new TestJFormattedTextField();

	}
}

Code:
import java.text.DecimalFormat;

import javax.swing.JFormattedTextField;


public class MyPrepareClass {
  
  MyPrepareClass(){
    
  }

  public static void prepareDecimal(JFormattedTextField ftf, String vorlage, int laenge, int nachkomma) {
    
    //System.out.println(ftf.getText().indexOf(","));
    
    if(ftf.getText().equals("")){
      return;
    }
    
    // String in ein char-Array packen und prüfen ob mehrere "," vorhanden sind
    char[] ch_hilf = new char[ftf.getText().length()];
    ch_hilf = ftf.getText().toCharArray();
    
    int komma_zaehl = 0;
    int minus_zaehl = 0;
    
    for(int i = 0; i < ch_hilf.length; i++){
      if(ch_hilf[i] == ','){
        komma_zaehl++;
      }
      if(ch_hilf[i] == '-'){
        minus_zaehl++;
      }
    }
    
    // Sind mehrere minus-Zeichen vorhanden, Textfeld löschen und Focus zurück setzten
    if(minus_zaehl > 1){

      ftf.setText("");
      ftf.requestFocusInWindow();
      return;
    }
    
    // Sind mehrere kommas vorhanden, Textfeld löschen und Focus zurück setzten
    if(komma_zaehl > 1){
 
      ftf.setText("");
      ftf.requestFocusInWindow();
      return;
    }
    
    // passt die anzahl der vorkommastellen (wenn 1 komma vorhanden ist) 
    if(komma_zaehl == 1){
      String[] vor_nachkomma = ftf.getText().split(",");
      if(vor_nachkomma[0].length()> laenge - nachkomma - 1){

        ftf.setText("");
        ftf.requestFocusInWindow();
        return;
      }
    }
    
    // passt die anzahl der vorkommastellen (wenn kein komma vorhanden ist) 
    if(komma_zaehl == 0){
      if(ftf.getText().length()> laenge - nachkomma - 1){

        ftf.setText("");
        ftf.requestFocusInWindow();
        return;
      }
    }
    
    // erst "," durch "." ersetzten und Wert in einer Double Variablen merken
    double merk = Double.parseDouble( ftf.getText().replace(",", ".") );
    merk = merk + 0.00000001; // das wird hinzuaddiert da Java beim casten abrundet!
    
    // jetzt *10^nachkomma rechnen und nach Integer Casten(um nachkommastellen zu entfernen) 
    merk = merk * Math.pow(10,nachkomma);
    int merk_int = (int) merk;
    System.out.println("merk_int : " + merk_int);
    System.out.println("merk2 : " + merk);
    
    merk = (double) merk_int / Math.pow(10,nachkomma);
    System.out.println("merk3 : " + merk);
    
    // Format festlegen
    DecimalFormat df =   new DecimalFormat  ( vorlage );
    System.out.println("merk4 : " + df.format(merk));
    
    // formatiert zurück schreiben
    System.out.println("Hier stimmts noch :" + String.valueOf(df.format(merk)).replace(".", ","));
    ftf.setText(String.valueOf(df.format(merk)).replace(".", ","));
  }
}

Code:
import javax.swing.text.PlainDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.AttributeSet;

/**
 * Diese Klasse ist ein Dokument für Textfelder, welches...
 * 
 * 1. Eingabe auf x Zeichen begrenzt.
 * 2. Nur die Zeichen zulässt die in der Variable valid stehen
 *
 * Die Zuweisung geschieht über
 * JTextfield.setDocumenT(new Validation(int anzahl));
 */
public class DecimalDocument extends PlainDocument{

  private static final long serialVersionUID = 5032290234368360350L;
  
  private int limit;

    /**
     * Konstruktor für das Validationdokument
     * @param int limit: maximale Anzahl der einzugebenen Zeichen
     */
    public DecimalDocument(int newLimit){
        super();
        if (limit < 0){
            limit = 0;
        } else {
            limit = newLimit;
        }
    }

    /**
     * Funktion überschreibt die Methode insertString von PlaintDocument
     * @param int offset: Position
     * @param String str: der String
     * @param AttributeSet attr: Attributset
     */
    public void insertString (int offset, String str, AttributeSet attr) throws BadLocationException {
      
        if (str == null) return;
       
        //Zeichenkette mit den gültigen Zeichen
        String valid = "-,0123456789";
        
        for (int i=0; i<str.length();i++) {
          //System.out.println(str);
            if (valid.indexOf(str.charAt(i)) == -1) {
              // wenn man hier rein kommt ist das eingegebene Zeichen ungültig!!
                return;
            }
            if ((getLength() + str.length()) > limit){
              // wenn man hier rein kommt ist das übergebene limit erreicht
              return;
            }
        //Wichtig Aufruf der übergeordneten Methode
        super.insertString(offset, str, attr);
      }
    }
}

ein kleines Prob ist auch das festlegen von den Nachkommastellen..
da ich höchstens 4 nachkommastellen haben kann habe ich es so gelöst..

merk = merk + 0.00000001; // das wird hinzuaddiert da Java beim casten abrundet!

aber das iss wohl net die feine englische art ;)
evtl. weiss da auch einer ne lösung!

------------------------------------------------------
Ist das überhaupt der richtige Ansatz
Wie macht ihr sowas
 
Hmm auch nicht ganz schön aber vllt ein wenig übersichtlicher:
Java:
package de.tutorials;

import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;

import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import javax.swing.text.NumberFormatter;

public class TestJFormattedTextField {

	private static final class MyFormattedTextField extends JFormattedTextField {
		private int maxLength;
		private int nachKommaCnt;
		private int vorkommaCnt;
		private String vorlage;
		private DecimalFormat df;

		MyFormattedTextField(int maxLength, int nachKommaCnt) {
			super();
			this.maxLength = maxLength;
			this.nachKommaCnt = nachKommaCnt;
			this.vorkommaCnt = maxLength - nachKommaCnt - 1;
			init();
		}

		private void init() {
			createFormatTemplate();
			this.setHorizontalAlignment(javax.swing.JTextField.RIGHT);

			this.addFocusListener(new FocusListener() {
				public void focusGained(FocusEvent arg0) {
					MyFormattedTextField.this.setBackground(Color.YELLOW);
				}

				public void focusLost(FocusEvent arg0) {
					prepareDecimal();
					MyFormattedTextField.this.setBackground(Color.WHITE);
				}
			});

			this.addKeyListener(new KeyAdapter() {

				@Override
				public void keyReleased(KeyEvent evt) {
					final String valid = "-,0123456789";
					// Kontrollzeichen zulassen
					if (Character.isISOControl(evt.getKeyChar())) {
						return;
					}
					// Wenn nicht in gültigen Zeichen ignorieren
					if (valid.indexOf(evt.getKeyChar()) == -1) {
						evt.consume();
					}
					
					//Hier könnte man evtl auch noch prüfen ob
					//maximal ein Komma und Minuszeichen vorkommt
					//oder auch die Gesamtlänge des Text
				}

			});
		}

		private void createFormatTemplate() {
			//Template zusammenbauen aus den Längen
			final String vorkommaString = createString(vorkommaCnt, "#") + "0";
			final String nachkommaString = createString(nachKommaCnt, "0");
			final String vorlage = vorkommaString + "." + nachkommaString;
			this.df = new DecimalFormat(vorlage, DecimalFormatSymbols
					.getInstance(Locale.GERMANY));
			//wie soll gerundet werden?
			this.df.setRoundingMode(RoundingMode.HALF_DOWN);

		}

		private static String createString(int num, String fill) {
			//fill mal num
			final StringBuilder b = new StringBuilder();
			for (int i = 0; i < num; i++) {
				b.append(fill);
			}
			return b.toString();
		}

		/**
		 * Zählt das vorkommen von search in strg.
		 */
		private int count(String strg, String search) {
			int cnt = -1;
			int index = strg.indexOf(strg);
			while (index != -1) {
				cnt++;
				index = strg.indexOf(strg, index + 1);
			}
			return cnt;
		}

		private void prepareDecimal() {
			final String txt = this.getText().trim();

			if (txt.equals("")) {
				return;
			}

			// String in ein char-Array packen und prüfen ob mehrere ","
			// vorhanden
			// sind
			final int komma_zaehl = count(txt, ",");
			final int minus_zaehl = count(txt, "-");

			// Sind mehrere minus-Zeichen vorhanden, Textfeld löschen und Focus
			// zurück setzten
			if (minus_zaehl > 1 || komma_zaehl > 1) {
				this.setText("");
				this.requestFocusInWindow();
				return;
			}

			// passt die anzahl der vorkommastellen (wenn 1 komma vorhanden ist)
			final String vorKomma;
			if (komma_zaehl == 1) {
				String[] vor_nachkomma = txt.split(",");
				vorKomma = vor_nachkomma[0];
			} else {
				vorKomma = txt;
			}

			if (vorKomma.length() > vorkommaCnt) {
				this.setText("");
				this.requestFocusInWindow();
				return;
			}

			// erst "," durch "." ersetzten und Wert in einer Double Variablen
			// merken
			double merk = Double.parseDouble(txt.replace(",", "."));

			final String formatted = df.format(merk);

			// formatiert zurück schreiben
			this.setText(formatted);
		}

	}

	TestJFormattedTextField() {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		frame.setSize(400, 400);

		JPanel panel = new JPanel();
		frame.add(panel);
		panel.setLayout(null);

		JLabel lbl = new JLabel("Selbstkosten");
		lbl.setBounds(10, 15, 100, 25);
		panel.add(lbl);
		JFormattedTextField tf_selbstkosten = new MyFormattedTextField(10, 2);
		tf_selbstkosten.setBounds(130, 15, 100, 25);
		panel.add(tf_selbstkosten);

		lbl = new JLabel("VK-Preis 1");
		lbl.setBounds(10, 40, 100, 25);
		panel.add(lbl);

		JFormattedTextField tf_vk_preis1 = new MyFormattedTextField(10, 2);
		tf_vk_preis1.setBounds(130, 40, 100, 25);
		panel.add(tf_vk_preis1);

		frame.setVisible(true);
	}

	public static void main(String[] args) {
		new TestJFormattedTextField();

	}
}

Zumindest tuts das was es soll und man muß nicht so viel rumparsen.
 
Leider hab ich hier das Problem das gerundet wird.
Also bei der eingabe von 1,999 wird es 2,00.

ist es möglich das runden irgendwie zu umgehen
die Zahl soll einfach nur abgeschnitten werden.

ausserdem ist die eingabe von z.B. 12345,11 (oder mehr stellen) nicht möglich
 
Zuletzt bearbeitet:
Also ich habe jetzt eine Lösung für mein Problem..
ziemlich unschön(wie ich denke) aber es geht.

Bei meinem Prog oben einfach bei kleineren Zahlen die vorangehenden Stellen mit Blanks füllen
Code:
.
.
		// Format festlegen
		DecimalFormat df =   new DecimalFormat  ( vorlage );
		
		String str_hilf = String.valueOf(df.format(merk)).replace(".", ",");
		for(int i =  str_hilf.length(); i < laenge; i++){
			str_hilf = " " + str_hilf;
		}
		System.out.println("*" + str_hilf + "*");

		ftf.setText(str_hilf);

Ich bin aber immer noch offen wenn wer ne schönere Lösung hat ;)

Vielen dank zeja für deine Hilfe!!
 
Naja sonderlich reingeguckt hast du in meinen Code offenbar nicht...

Wenn du DecimalFormat mit der Deutschen Locale Initialisierst bekommst du z.B. direkt Kommas und brauchst das nicht nachträglich mit nem Replace ändern.

Und warum füllst du jetzt was mit Leerzeichen auf?

Leider gibt es keinen RoundingMode.NONE /CUT.
Die Stelle danach mit einer 0 ersetzen funktioniert aber auch:

Java:
package de.tutorials;

import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;

import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import javax.swing.text.NumberFormatter;

public class TestJFormattedTextField {

	private static final class MyFormattedTextField extends JFormattedTextField {
		private int maxLength;
		private int nachKommaCnt;
		private int vorkommaCnt;
		private String vorlage;
		private DecimalFormat df;

		MyFormattedTextField(int maxLength, int nachKommaCnt) {
			super();
			this.maxLength = maxLength;
			this.nachKommaCnt = nachKommaCnt;
			this.vorkommaCnt = maxLength - nachKommaCnt - 1;
			init();
		}

		private void init() {
			createFormatTemplate();
			this.setHorizontalAlignment(javax.swing.JTextField.RIGHT);

			this.addFocusListener(new FocusListener() {
				public void focusGained(FocusEvent arg0) {
					MyFormattedTextField.this.setBackground(Color.YELLOW);
				}

				public void focusLost(FocusEvent arg0) {
					prepareDecimal();
					MyFormattedTextField.this.setBackground(Color.WHITE);
				}
			});

			this.addKeyListener(new KeyAdapter() {

				@Override
				public void keyReleased(KeyEvent evt) {
					final String valid = "-,0123456789";
					// Kontrollzeichen zulassen
					if (Character.isISOControl(evt.getKeyChar())) {
						return;
					}
					// Wenn nicht in gültigen Zeichen ignorieren
					if (valid.indexOf(evt.getKeyChar()) == -1) {
						evt.consume();
					}

					// Hier könnte man evtl auch noch prüfen ob
					// maximal ein Komma und Minuszeichen vorkommt
					// oder auch die Gesamtlänge des Text
				}

			});
		}

		private void createFormatTemplate() {
			// Template zusammenbauen aus den Längen
			final String vorkommaString = createString(vorkommaCnt, "#") + "0";
			final String nachkommaString = createString(nachKommaCnt, "0");
			final String vorlage = vorkommaString + "." + nachkommaString;

			this.df = new DecimalFormat(vorlage, DecimalFormatSymbols
					.getInstance(Locale.GERMANY));
			// wie soll gerundet werden?
			this.df.setRoundingMode(RoundingMode.HALF_UP);

		}

		private static String createString(int num, String fill) {
			// fill mal num
			final StringBuilder b = new StringBuilder();
			for (int i = 0; i < num; i++) {
				b.append(fill);
			}
			return b.toString();
		}

		/**
		 * Zählt das vorkommen von search in strg.
		 */
		private int count(String strg, String search) {
			int cnt = 0;
			int index = strg.indexOf(strg);
			while (index != -1) {
				cnt++;
				index = strg.indexOf(strg, index + 1);
			}
			return cnt;
		}

		private void prepareDecimal() {
			String txt = this.getText().trim();

			if (txt.equals("")) {
				return;
			}

			// String in ein char-Array packen und prüfen ob mehrere ","
			// vorhanden
			// sind
			final int komma_zaehl = count(txt, ",");
			final int minus_zaehl = count(txt, "-");

			// Sind mehrere minus-Zeichen vorhanden, Textfeld löschen und Focus
			// zurück setzten
			if (minus_zaehl > 1 || komma_zaehl > 1) {
				this.setText("");
				this.requestFocusInWindow();
				return;
			}

			// passt die anzahl der vorkommastellen (wenn 1 komma vorhanden ist)
			final String vorKomma;
			if (komma_zaehl == 1) {
				String[] vor_nachkomma = txt.split(",");
				vorKomma = vor_nachkomma[0];

				int index = txt.indexOf(",");

				if (txt.length() >= index + (nachKommaCnt + 2)) {
					// Stelle nach den maximalen Kommastellen auf 0 setzen,
					// damit
					// abgeschnitten statt gerundet wird
					StringBuffer b = new StringBuffer(txt);
					String temp = b.replace(index + (nachKommaCnt + 1),
							index + (nachKommaCnt + 2), "0").toString();
					txt = temp;
				}

			} else {
				vorKomma = txt;
			}

			if (vorKomma.length() > vorkommaCnt) {
				this.setText("");
				this.requestFocusInWindow();
				return;
			}

			// erst "," durch "." ersetzten und Wert in einer Double Variablen
			// merken
			double merk = Double.parseDouble(txt.replace(",", "."));

			BigDecimal decimal = BigDecimal.valueOf(merk);
			decimal.setScale(3, RoundingMode.FLOOR);

			final String formatted = df.format(decimal);

			// formatiert zurück schreiben
			this.setText(formatted);
		}

	}

	TestJFormattedTextField() {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		frame.setSize(400, 400);

		JPanel panel = new JPanel();
		frame.add(panel);
		panel.setLayout(null);

		JLabel lbl = new JLabel("Selbstkosten");
		lbl.setBounds(10, 15, 100, 25);
		panel.add(lbl);
		JFormattedTextField tf_selbstkosten = new MyFormattedTextField(10, 2);
		tf_selbstkosten.setBounds(130, 15, 100, 25);
		panel.add(tf_selbstkosten);

		lbl = new JLabel("VK-Preis 1");
		lbl.setBounds(10, 40, 100, 25);
		panel.add(lbl);

		JFormattedTextField tf_vk_preis1 = new MyFormattedTextField(10, 2);
		tf_vk_preis1.setBounds(130, 40, 100, 25);
		panel.add(tf_vk_preis1);

		frame.setVisible(true);
	}

	public static void main(String[] args) {
		new TestJFormattedTextField();

	}
}
 
hehe.. jetzt habe ich sogar 2 möglichkeiten ;)
meins funktioniert jetzt auch einwandfrei.

Aber wenn meinst das die andere Lösung schneller ist dann werd ich das die nächsten Tage umbauen.

und auf die Idee mit der 0 hinhängen bin ich echt nicht gekommen..
Ich glaub das ist einiges weniger an aufwand^^

nochmal 1000 dank @ zeja
 
Zurück