Texteingabe - Bedeutung Fehlermeldung, Lösung?

Wuast

Bekanntes Mitglied
Abend zusammen, ich möchte von einem Textfield den String in einen double parsen und diesen Wert dann bei einem anderen Methodenaufruf (Setter) übergeben.
Logischerweise moppet die IDE, dass der String ja leer ist und nicht geparst werden kann. Also wollte ich über eine Kontrollfunktion mit while da ran, aber da kriege ich die Fehlermeldung: class javax.swing.JTextField cannot be cast to class java.lang.CharSequence (javax.swing.JTextField is in module java.desktop of loader 'bootstrap'; java.lang.CharSequence is in module java.base of loader 'bootstrap'). das verstehe ich nicht so richtig, was bedeutet es und wie löse ich das? (Suche nach Bootstrap führt mich zur Webentwicklung?)

Java:
while (!((CharSequence) taxRateTxtField).isEmpty()) {
        double taxRate = Double.parseDouble(taxRateTxtField.getText());
    
    // usw.

eine ähnliche Situation hatte ich schon mal, da habe ich dann über einen ActionListener die Daten an eine andere Methode geschickt (ein "Bestätigen-Button"). Geht das auch ohne, also einfach nur über die Eingabe im Textfield, die ja mittels Enter bestätigt werden kann?!
Danke und LG 🙂
 
Du hast schon festgestellt, dass du den Text mit: taxRateTxtField.getText() bekommst:
Java:
String text = taxRateTxtField.getText();
if (text == null || text.isBlank()) {
    // mach was
} else {
    // mach was anderes
}
 
eine ähnliche Situation hatte ich schon mal, da habe ich dann über einen ActionListener die Daten an eine andere Methode geschickt (ein "Bestätigen-Button"). Geht das auch ohne, also einfach nur über die Eingabe im Textfield, die ja mittels Enter bestätigt werden kann?!
Danke und LG
Leider schreibst du nicht mit welchen UI-Framwork du arbeitest.
Für Swing:
Java:
        final JTextField textField = new JTextField();
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(final KeyEvent event) {
                if(event.getKeyCode() == KeyEvent.VK_ENTER){
                    String text = ((JTextField) e.getSource()).getText();
                    // mach was mit 'text'
                }
            }
        });
        // oder
        textField.addActionListener(event -> {
            String text = ((JTextField) event.getSource()).getText();
            // mach was mit 'text'
        });
 
Leider schreibst du nicht mit welchen UI-Framwork du arbeitest.
Für Swing:
Java:
        final JTextField textField = new JTextField();
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(final KeyEvent event) {
                if(event.getKeyCode() == KeyEvent.VK_ENTER){
                    String text = ((JTextField) e.getSource()).getText();
                    // mach was mit 'text'
                }
            }
        });
        // oder
        textField.addActionListener(event -> {
            String text = ((JTextField) event.getSource()).getText();
            // mach was mit 'text'
        });
Pardon, ja, Swing

Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: empty String

bei
Java:
String taxRateString = taxRateTxtField.getText();
        if (taxRateString == null || taxRateString.isBlank()) {
            double taxRate = Double.parseDouble(taxRateString);
// usw.

d.h. ich brauche immer den Action oder eventListener?
 
Pardon, ja, Swing

Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: empty String

bei
Java:
String taxRateString = taxRateTxtField.getText();
        if (taxRateString == null || taxRateString.isBlank()) {
            double taxRate = Double.parseDouble(taxRateString);
// usw.

d.h. ich brauche immer den Action oder eventListener?
Denk doch mal nach, was du hier überhaupt machst. Wenn der String "null" ist oder "blank", dann versucht du ihn in ein Zahl umzuwandeln. Das muss ja schiefgehen.
 
Wenn du mit Swing arbeitest, warum benutzt du nicht JFormattedTextField für Zahlen-Eingabefelder? Dann kannst du über set- und getValue ein entsprechendes Object verwenden, z.B.: Double. So ist diese umständliche Umwandlung über String gar nicht notwendig und du kannst Dinge wie Validierung, Anzahl der Kommastellen und min/max bereits vorher einstellen.
 
Abend zusammen, ich möchte von einem Textfield den String in einen double parsen und diesen Wert dann bei einem anderen Methodenaufruf (Setter) übergeben.
Java:
import javax.swing.JFrame;

public class FormatInput {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Format Text");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new FormatTestPanel(400, 80));
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }
}
Java:
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;

@SuppressWarnings("serial")
public class FormatTestPanel extends JPanel {
    private JTextField[] input = { new JTextField(), new JTextField() };
    private JLabel result = new JLabel();
    private JButton ok = new JButton("ok");

    public FormatTestPanel(int width, int height) {
        setPreferredSize(new Dimension(width, height));
        int maxChar = 10;
        int gap = width / 20;
        int fontSize = width / 21;
        Font font = new Font("Courier", Font.BOLD, fontSize);
        int w = maxChar * (int) (fontSize * .68);
        int h = 3 * fontSize / 2;
        setFont(font);
        for (JTextField t : input) {
            FormatDocument doc = new FormatDocument(maxChar);
            doc.setType(FormatDocument.TYPE.FLOAT);
            add(t);
            t.setFont(font);
            t.setDocument(doc);
            t.setPreferredSize(new Dimension(w, h));
            t.setHorizontalAlignment(JTextField.RIGHT);
        }
        add(result);
        result.setFont(font);
        result.setPreferredSize(new Dimension(width - 2 * gap - 2 * w, h));
        result.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
        result.setHorizontalAlignment(JLabel.RIGHT);
        ok.setPreferredSize(new Dimension(w, h));
        add(ok);
        ok.addActionListener(e -> {
            result.setText(sum() + "");
        });
    }

    private double getValue(JTextField input) {
        String text = input.getText();
        return text.equals("") ? 0 : Double.parseDouble(text);
    }

    private double sum() {
        return getValue(input[0]) + getValue(input[1]);
    }

}
Java:
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

@SuppressWarnings("serial")
public class FormatDocument extends PlainDocument {
    public static enum TYPE {
        TEXT, INT, FLOAT
    };

    private int maxSize;
    private TYPE type = TYPE.TEXT;

    public FormatDocument(int maxSize) {
        this.maxSize = maxSize;
    }

    @Override
    public void insertString(final int offset, String text, final AttributeSet attributeSet)
            throws BadLocationException {
        if (type == TYPE.INT || type == TYPE.FLOAT) {
            String format = ".*[^0-9";
            String point = "";
            if (type == TYPE.FLOAT) {
                Content content = getContent();
                String txt = content.getString(0, content.length());
                point = txt.contains(".") ? "" : ".";
            }
            format += point + "]";
            text = text.replaceAll(format, ""); // remove all non digits
        }
        if (isNewLengthOk(text))
            super.insertString(offset, text, attributeSet);
    }

    protected boolean isNewLengthOk(final String text) {
        return (getLength() + text.length() <= maxSize);
    }

    public void setType(TYPE type) {
        this.type = type;
    }
}
 
Denk doch mal nach, was du hier überhaupt machst. Wenn der String "null" ist oder "blank", dann versucht du ihn in ein Zahl umzuwandeln. Das muss ja schiefgehen.
Öhm.. ups. Sollte nat. genau anders herum sein 😀 Vergiss das. Mal wieder zu bl..
Wenn du mit Swing arbeitest, warum benutzt du nicht JFormattedTextField für Zahlen-Eingabefelder? Dann kannst du über set- und getValue ein entsprechendes Object verwenden, z.B.: Double. So ist diese umständliche Umwandlung über String gar nicht notwendig und du kannst Dinge wie Validierung, Anzahl der Kommastellen und min/max bereits vorher einstellen.
Guck ich mir an!
Java:
i
    OVERKILL ? :D 
}
 
Wenn du mit Swing arbeitest, warum benutzt du nicht JFormattedTextField für Zahlen-Eingabefelder? Dann kannst du über set- und getValue ein entsprechendes Object verwenden, z.B.: Double. So ist diese umständliche Umwandlung über String gar nicht notwendig und du kannst Dinge wie Validierung, Anzahl der Kommastellen und min/max bereits vorher einstellen.
Ich krebs jetzt seit ner Stunde damit rum und es will nicht so richtig.

In den docs heißt es dazu "JFormattedTextField extends JTextField adding support for formatting arbitrary values, as well as retrieving a particular object once the user has edited the text. The following illustrates configuring a JFormattedTextField to edit dates: JFormattedTextField ftf = new JFormattedTextField();
ftf.setValue(new Date());"

Das bedeutet doch, dass ich nach Eingabe eines Wertes diesen über das getValue verwerten könnte, z.B.
Java:
public void setTaxRate() {
    JPanel setTaxRatePanel = new JPanel();
    JFrame frame = new JFrame("Fill in tax-rate");

    frame.setSize(400, 200);
    frame.setDefaultCloseOperation(JFrame.[B][I]EXIT_ON_CLOSE[/I][/B]);
    frame.setVisible(true);
    frame.add(setTaxRatePanel);

    setTaxRatePanel.setLayout(null);

    JLabel askForInput = new JLabel("Tax-rate in %: ");
    askForInput.setBounds(15, 30, 100, 30);
    setTaxRatePanel.add(askForInput);

    JFormattedTextField taxRateInput = new JFormattedTextField();
    taxRateInput.setBounds(150, 30, 100, 30);
    setTaxRatePanel.add(taxRateInput);
taxRateInput.setValue(new Object());
        double tax = (double) taxRateInput.getValue();
        System.out.println(tax);
oder nicht?

Egal wie ich es drehe und wende, entweder bekomme ich oben genannte Fehlermeldung mit den bootstrap oder die null-Pointer-Exception.
Edit: Wahlweise auch die Hashcode für das Object, wenn ich den cast zum Double weglasse. ("java.lang.Object@72420d3c")
Dann kannst du über set- und getValue ein entsprechendes Object verwenden, z.B.: Double. So ist diese umständliche Umwandlung über String gar nicht notwendig und du kannst Dinge wie Validierung, Anzahl der Kommastellen und min/max bereits vorher einstellen.
Das kriege ich also nicht umgesetzt.

Edit2:
Java:
taxRateInput.setValue(Double.class);
        double tax = (double) taxRateInput.getValue();
        System.out.println(tax);
liefert auch wieder eine java.lang.ClassCastException: 🙁

Wo ist der Wurm?
 
Zuletzt bearbeitet:
Das versucht in das Feld ein Objekt vom Typ Class zu setzen. Wenn willst du einen Double Wert (z.b. 2.5) setzen - nicht ein Class-Objekt.
Das war auch reine Verzweiflung 😀

Eigentlich will ich doch nichts konkretes übergeben bei setValue, sondern den Inhalt aus dem JFormattedTextField haben. Meine bisherige Erfahrung geht ausschließlich auf die AbstractTableModel zurück, wo ich setValueAt(Object value, ...) das "value" referenzieren konnte für den weiteren Gebrauch. Ich verstehe nicht, was ich bei dem JFormattedTextField brauche.
 
Java:
import java.text.*;
import javax.swing.*;
public class Test {
    public void run() {
        NumberFormat nf = DecimalFormat.getInstance();
        JFormattedTextField tf = new JFormattedTextField(nf);
        tf.setColumns(20);
        tf.addActionListener(e -> {
            double value = ((Number)tf.getValue()).doubleValue();
            double result = value * 2;
            JOptionPane.showMessageDialog(null, String.format("%.2f * 2 == %.2f", value, result));
        });
        JPanel panel = new JPanel();
        panel.add(tf);
       
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}

Zahl eintippen, Enter drücken, staunen 😛
 
Java:
import java.text.*;
import javax.swing.*;
public class Test {
    public void run() {
        NumberFormat nf = DecimalFormat.getInstance();
        JFormattedTextField tf = new JFormattedTextField(nf);
        tf.setColumns(20);
        tf.addActionListener(e -> {
            double value = ((Number)tf.getValue()).doubleValue();
            double result = value * 2;
            JOptionPane.showMessageDialog(null, String.format("%.2f * 2 == %.2f", value, result));
        });
        JPanel panel = new JPanel();
        panel.add(tf);
      
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}

Zahl eintippen, Enter drücken, staunen 😛
erledigt, hab gestaunt 🙂
also ich halte fest: setValue brauche ich nicht, das läuft "im Hintergrund" bei Eingabe eines Wertes. Ich brauche den getValue.
außerdem: Ich brauche den Listener, weil ohne gehts scheinbar nicht.

Auch gut zu wissen, dass ich einen Cast auf Number machen kann, wusste garnicht, dass es die Klasse Number gibt.

Damit ist "Twitter Bootstrap" gemeint: eine Sammlung von Design-Vorlagen zur Frontendentwicklung von Webpräsenzen.
Jau danke, hab ich auch gerade gesehen 🙂 Aber was wollte mir denn die Fehlermeldung jetzt sagen? Das wird ja wohl nichts mit dem Bootstrap von "Twitter" bzw. der Frontentwicklung zu tun haben?!

Danke für alle Antworten.
 
außerdem: Ich brauche den Listener, weil ohne gehts scheinbar nicht.
Du brauchst im GUI immer irgendwelche Listener (wenn Du nicht mit mehreren Threads arbeiten willst), weil das GUI ereignisgesteuert arbeitet. Hier habe ich einfach mal den ActionListener direkt ans das Textfeld gehangen, Du kannst natürlich auch einen Button einbauen oder einen Timer oder einen FocusListenr -> was auch immer.


Auch gut zu wissen, dass ich einen Cast auf Number machen kann, wusste garnicht, dass es die Klasse Number gibt.
Ja, getValue() liefert ja ein Object, das ist wenig hilfreich. Number ist die Basisklasse aller primitiven Wrapper. Integer, Double usw. sind von Number abgeleitet. Der Code sagt also: ganz gleich, was das Textfield konkret für einen Wrapper liefert, ich möchte den double-Wert haben.

setValue() kannst Du natürlich weiterhin verwenden.
 
Prima, dann habe ich das jetzt gerafft denke ich.

Vllt. noch kurz zu den Listenern (und dann is gut hier mit dem Off-Topic): Gibt es da auch so eine Art "Basis-Klasse", die ich immer nehmen kann? Wenn ich z.B. die Zahleneingabe weiterverarbeite, dann ändert sich eine Zahl in der Programmlogik, und davon abhängig ja auch weitere, die mit der eingegebenen Zahl rechnen. Wenn ich das Ergebnis einer anderen Berechnung in dem Hauptframe des GUI anzeigen will, brauche ich ja auch einen Listener. Oder geht das nur noch über das .. ich sag mal stümperhaft "klassische Observer-Ich hab mal ein bisschen geschaut, von den Vorschlägen der Listener scheint keine so richtig zu passen (z:B. inputMethodListener)

falls ein Bsp. benötigt wird (nicht ganz das gleiche wie die Eingabe in das JFormattedTextField aber sollte ja von der Art her gleich sein:
Java:
JTextPane abstractPane = new JTextPane();
        
        abstractPane.addInputMethodListener(l -> {        //Fehlermeldung: argumente sind nicht richtig, d.h. doch falscher Listener an der Stelle
        functions.setAbstract();                        //die Methode liefert in Abhängigkeit eines EventHandlers über ein Switch-Case den Return einer anderen Methode zurück - dieser Verändert den String review
        abstractPane.setText("Absctract of " + review);    // Das soll sich dann also ändern
        });                                                   
           toolBar.add(abstractPane);
 
Naja, des einfachste Ereignis lautet "hey, es hat sich irgendwas geändert", das wäre dann ein ChangeEvent und dafür gibts auch einen ChangeListener. Das ChangeEvent ist aber Swing-spezifisch, hat also im Kern der Anwendung nichts verloren. Da kann man über einen PropertyChangeEvent nachdenken oder aber einfach selbst schreiben, was für fachliche Ereignisse sowieso die bessere Wahl ist.

Das schöne ist ja, dass es keine Framework-spezifischen Ereignisse sein müssen: GUI registriert sich beim Anwendungskern als Listener (aka Observer), Anwendungskern löst ein Ereignis aus, GUI wird informiert und reagiert.

Ein InputMethodEvent wird z. B. ausgelöst, wenn sich die Position der "Einfügemarke" ändert; ich weiß jetzt nicht, ob es das ist, wonach Du suchst. In AWT/Swing gibts einen FocusManager, mit dem man z. B. den Fokus für mehrere Komponenten auf einmal nachverfolgen kann (man muss dann also nicht bei jeder Komponente einzeln einen Listener registrieren). Details https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html
 
Dann schreibe ich wohl am besten einfach den Observer selbst. Aber wie war das noch gleich zur Laufzeit, das wird nicht automatisch in das UI übernommen dann, oder?
 

Zurück
Oben