Eingabenüberprüfung

Knuffi

Mitglied
Hallo,
erst mal vorneweg: Ich bin noch Anfänger :)

Ich versuche mittels einer Methode die Benutzereingaben in der GUI zu überprüfen, bevor sie weitergeleitet werden.

Dabei geht es darum, dass der Benutzer in eine Anzahl von Textfeldern double oder int-Zahlen eingeben muss, bevor er einen Button zur Verarbeitung der Zahlen drückt.

Mein erster Ansatz war der folgende:
1. Ich habe die Prüfroutine in den ActionListener des Buttons reingeschrieben.

2. Ich habe bei einer kleinen Versuchs-GUI einfach jedes Textfeld einzeln überprüft, ob was drin steht und ob es ein int oder double sein könnte (ich befürchte, dass der Punkt als Dezimaldelimiter für viele User erst mal ein Problem sein könnte, aber ich muss mich noch ein wenig mit locale beschäftigen ...).

[Java]btnHinzufgen.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
String tname = fldName.getText();
double tx1,tx2,tx3;
//Versuch bei x1
try {
tx1 = Double.valueOf(fldX1.getText());
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"Die Eingabe für x1 war nicht gültig! \nBitte Zahl eingeben und auf den DezimalPUNKT achten!","Fehler", JOptionPane.ERROR_MESSAGE);
return;
}
//Versuch bei x2
try {
tx2 = Double.valueOf(fldX2.getText());
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"Die Eingabe für x2 war nicht gültig! \nBitte Zahl eingeben und auf den DezimalPUNKT achten!","Fehler", JOptionPane.ERROR_MESSAGE);
return;
}
//Versuch bei x3
try {
tx3 = Double.valueOf(fldX3.getText());
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"Die Eingabe für x3 war nicht gültig! \nBitte Zahl eingeben und auf den DezimalPUNKT achten!","Fehler", JOptionPane.ERROR_MESSAGE);
return;
}
Punkt TPunkt = new Punkt(tname, tx1,tx2,tx3);
PListe.add(TPunkt);
table.revalidate();
table.repaint();
}
});[/Java]

Jetzt stoße ich damit aber an Grenzen:
1. In der eigentlichen Anwendung kommt diese Überprüfung sehr oft vor und dazu noch mit drei bis 9 Feldern.
2. Ich will nicht in jeden Button wieder die ganze Routine reinschreiben, sondern an einem gesonderten Ort und dann im Listener nur noch darauf zugreifen. Eine eigene Klasse ist dafür wohl ein wenig zu hoch gegriffen, oder? Wie kann ich solche "allgemeinen" Routinen am besten unterbringen?
3. Kann ich die Namen der Textfelder in der Überprüfungsroutine nachdem ich sie als Argumente übergeben habe, irgendwie "serialisieren" oder "verzahlen", dass ich die Inhalte mir einer Art von Schleife überprüfen kann?

Danke schon mal
 

pl4gu33

Top Contributor
Jetzt stoße ich damit aber an Grenzen:
1. In der eigentlichen Anwendung kommt diese Überprüfung sehr oft vor und dazu noch mit drei bis 9 Feldern.
2. Ich will nicht in jeden Button wieder die ganze Routine reinschreiben, sondern an einem gesonderten Ort und dann im Listener nur noch darauf zugreifen. Eine eigene Klasse ist dafür wohl ein wenig zu hoch gegriffen, oder? Wie kann ich solche "allgemeinen" Routinen am besten unterbringen?
3. Kann ich die Namen der Textfelder in der Überprüfungsroutine nachdem ich sie als Argumente übergeben habe, irgendwie "serialisieren" oder "verzahlen", dass ich die Inhalte mir einer Art von Schleife überprüfen kann?
Danke schon mal

zu 2. wenn du immer wieder den selben Code benutzt, ist eine interne oder normale Klasse die den Listener implementiert, die beste Lösung, als 1000x anonyme Listener mit dem gleichen Code :)

dann brauchst du nur noch button.addActionListener(new MyListener());

zu 3. alle Textfelder in eine ArrayListe und diese dann durchiterieren
zb. ArrayList<JTextField> ...
 

Knuffi

Mitglied
3. hab ich verstanden,
Zu 2. Dann brauche ich aber für jede Anzahl von Textfeldern einen anderen Listener, richtig?

Dann bin ich noch auf ein Problem gestoßen: Dem "Locale":
In obigem Beispiel muss der User ja Dezimalpunkte eingeben. Nach der Therorie sollte man damit ja auch Dezimalkomma eingeben können. Ich habe nun mal in der Main-Methode folgendes untergebracht:
[Java] System.out.println(Locale.getDefault().getCountry());
System.out.println(Locale.getDefault().getISO3Language());
System.out.println(Locale.getDefault().getLanguage());
double doub = 1.234;
System.out.println(new String().valueOf(doub));[/Java]

Das führt zur folgenden Ausgabe:

Wie bringe ich Java dazu, KOMMA-Zahlen bei der Eingabe zu akzeptieren und auszugeben, wenn die Locales schon so (in meinen Augen richtig) gesetzt sind? Ich habe nun ein paar Stunden gesucht und gelesen, bekomme es aber nicht hin. ???:L
 

Knuffi

Mitglied
Danke, funktioniert endlich! :D

Ganz oben in der GUI-Klasse
Java:
	public static NumberFormat nf =
	        NumberFormat.getNumberInstance();

und dann im Button


Java:
		btnHinzufgen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String tname = fldName.getText();
				double tx1,tx2,tx3;
				//Versuch bei x1
				try {
					tx1 = (Double) nf.parse(fldX1.getText());
					} catch (ParseException e) {
						JOptionPane.showMessageDialog(null,"Die Eingabe für x1 war nicht gültig! \nBitte Zahl eingeben und auf den DezimalPUNKT achten!","Fehler", JOptionPane.ERROR_MESSAGE);
						return;
					
					}
				//Versuch bei x2
				try {
					tx2 = (Double) nf.parse(fldX1.getText());
					} catch (ParseException e) {
						JOptionPane.showMessageDialog(null,"Die Eingabe für x2 war nicht gültig! \nBitte Zahl eingeben und auf den DezimalPUNKT achten!","Fehler", JOptionPane.ERROR_MESSAGE);
						return;
					
					}
				//Versuch bei x3
				try {
					tx3 = (Double) nf.parse(fldX1.getText());
					} catch (ParseException e) {
						JOptionPane.showMessageDialog(null,"Die Eingabe für x3 war nicht gültig! \nBitte Zahl eingeben und auf den DezimalPUNKT achten!","Fehler", JOptionPane.ERROR_MESSAGE);
						return;
					
					}
				Punkt TPunkt = new Punkt(tname, tx1,tx2,tx3);
				PListe.add(TPunkt);
				table.revalidate();
				table.repaint();
			}
 

Guybrush Threepwood

Top Contributor
Eigentlich wäre das ja ein Anwendungsfall für Documets, z. B.:
Java:
import java.awt.Toolkit;

import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**Document for the use on formatted textfields. Beware when setting the minimum attribute: should only be set to zero or
 * negative values 
 * @author Psychometrica
 *
 */
public class DoubleDocument extends PlainDocument {
	private static final long serialVersionUID = -4507680654340326555L;
	private JTextField jtTxt = null;
	private double maximum = Double.MAX_VALUE;
	private double minimum = Double.MIN_VALUE;
	private int maxDigitNumber = Integer.MAX_VALUE;

	public DoubleDocument(JTextField txt, double min, double max,
			int numberOfDigits) {
		super();
		this.minimum = min;
		this.maximum = max;
		this.maxDigitNumber = numberOfDigits;
		this.jtTxt = txt;
	}

	public DoubleDocument(JTextField jtTxt, double min, double maximum) {
		super();
		this.jtTxt = jtTxt;
		this.minimum = min;
		this.maximum = maximum;
	}
	
	public DoubleDocument(JTextField jtTxt, double maximum) {
		super();
		this.jtTxt = jtTxt;
		this.maximum = maximum;
	}

	public DoubleDocument(JTextField jtTxt) {
		super();
		this.jtTxt = jtTxt;
	}

	public void insertString(int offset, String s, AttributeSet attributeSet)
			throws BadLocationException {

		// allow decimal comma instead of point
		String text = (jtTxt.getText() + s).replaceFirst(",", ".");
		if(text.length()==0){
			super.insertString(offset, s, attributeSet);
			return;
		}else if((minimum<0)&&(text.length()==1)&&(s.equals("-"))){
			super.insertString(offset, s, attributeSet);
			return;
		}
		
		try {
			String[] segments = text.split("\\.");
			if (segments.length > 2)
				throw new Exception();
			else if (segments.length == 2) {
				if (segments[1].length() > maxDigitNumber)
					throw new Exception();
			}

			double value = Double.parseDouble(text);
			if ((value<minimum)||(value > maximum))
				throw new Exception();

		} catch (Exception ex) {
			Toolkit.getDefaultToolkit().beep();
			return;
		}
		super.insertString(offset, s, attributeSet);
	}
}

Auf diese Weise gibt es ein Döt, wenn jemand etwas Falsches eingibt. Anwendung:
Java:
numberField.setDocument(new DoubleDocument(numberField));

P.S.: Der Code stammt im Wesentlichen hier aus dem Forum. Wo genau weiß ich leider nicht mehr. Ich glaube es war im FAQ.
 

Knuffi

Mitglied
Hmpf ... ???:L
Das mit dem Code, den ich oben gepostet habe klappt wohl doch nicht so ganz.
Wenn ich mit dem obigen Source eine Integer in das Textfeld eingebe, dann bekomme ich die Fehlermeldung

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Double

Wenn ich dann daraufhin die entsprechende Zeile abändere
Java:
tx1 = nf.parse(fldX1.getText()).doubleValue();
dann bleibt zwar die Fehlermeldung weg, aber so Eingaben wie "2s" (ergibt 2) oder "2.3" (ergibt 23, liegt wohl am Numberformat) sollten halt auch nicht durchgehen.
Funktionieren tut es, wenn ein Buchstabe vorneweg kommt: "s2" ergibt die entsprechende Fehlermeldung.

Gebe ich "2,3" ein, dann klappt alles wunderbar

@Guybrush:
Das schaut mir aber wesentlich schwieriger aus, als ein eigener Actionlistener ... inzwischen habe ich ihn nach den Tipps von pl4gu33 auch verkürzt und ausgelagert, die Probleme, die ich eben erwähnt habe, bleiben aber.

Java:
package Check;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;

import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class MyListener3 implements ActionListener {
	public static NumberFormat nf = NumberFormat.getNumberInstance();
	public ArrayList<JTextField> AL = new ArrayList<JTextField>();
	double tx1,tx2,tx3;
	double[] XL = {tx1,tx2,tx3};
			
	
	public MyListener3(JTextField px1, JTextField px2, JTextField px3) {
			AL.add(px1);
			AL.add(px2);
			AL.add(px3);
				
		}
	

	@Override
	public void actionPerformed(ActionEvent e) {
		for (int i = 0; i < AL.size(); i++) {
			//	Versuch
				try {
//					System.out.println(AL.get(i).getText());
					XL[i] = nf.parse(AL.get(i).getText()).doubleValue();
					System.out.println(XL[i]);
				} catch (ParseException e1) {
						int j = i+1;
						JOptionPane.showMessageDialog(null,"Die Eingabe für x"+j+" war nicht gültig! \nBitte Zahl eingeben!","Fehler", JOptionPane.ERROR_MESSAGE);
						return;
					}
		}
	}
}
 
Zuletzt bearbeitet:

Guybrush Threepwood

Top Contributor
@Guybrush:
Das schaut mir aber wesentlich schwieriger aus, als ein eigener Actionlistener ...

Eigentlich ist es extrem einfach. Du brauchst lediglich die Klasse und in Deinem eigenen Code für jedes Textfeld nur eine einzelne Zeile. Alles weitere macht das DoubleDocument automatisch und Du musst nichts daran basteln. Der größte Teil des Codes in Deinen ActionListenern wird überflüssig. Probiere es mal aus. Es ist wirklich die bessere Lösung.
 

Oben