DocumentListener Java, как предотвратить пустую строку в JTextBox?

введите здесь описание изображенияЯ работаю над личным проектом, чтобы стать лучше в программировании. Моя цель - сделать его намного более надежным, я только начинаю. Я действующий студент информатики. Во всяком случае, я работаю над созданием части программы, как показано. Я рассчитываю почасовую заработную плату и предоставляю некоторые результаты, которые я еще не реализовал. Я использую DocumentListener, поэтому он будет автоматически вычисляться. Я получаю сообщение об ошибке, когда текст полностью удаляется из поля. Я попытался исправить это с помощью оператора if:

 if (tipMon.equals("") || tipMon == null) {
 tipMon.setText("0");
 }

Вот что у меня есть до сих пор. Это еще не сделано, и я извиняюсь за нуб-код. Я начал 2 месяца назад с фактического кодирования.

 import java.awt.GridLayout;
 import java.awt.event.ActionListener;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyListener;

 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JTextField;
 import javax.swing.JOptionPane;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
 import javax.swing.text.Document;
 import javax.swing.text.FieldView;

 public class deliveryDocListener extends JFrame implements ActionListener, 
DocumentListener{

private JLabel mon, tues, wed, thurs, fri, sat, sun, hourlyWage, blank, row2, monWage,
    tuesWage,wedWage,thursWage, friWage, satWage, sunWage, total, totalTips, totalHours, 
    totalHourlyEarnings, totalPay, weekPay;

private JTextField hourlyWageInput, tipMon, tipTues, tipWed, tipThurs, tipFri, tipSat, tipSun,
    hourMon, hourTues, hourWed, hourThurs, hourFri, hourSat, hourSun;


public deliveryDocListener(){
    super("Delivery Helper v0.1 Alpha");
    setLayout(new GridLayout(0,4));

    hourlyWage = new JLabel("Hourly Wage: ");
    add(hourlyWage);
    hourlyWageInput = new JTextField("7.25", 5);

    add(hourlyWageInput);
    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);

    row2 = new JLabel("Day of the Week");
    add(row2);
    row2 = new JLabel("Tips");
    add(row2);
    row2 = new JLabel("Hours Worked");
    add(row2);
    row2 = new JLabel("Hourly Earnings");
    add(row2);

    mon = new JLabel("Monday");
    add(mon);



    tipMon = new JTextField("0");

    Document tipMonListener = tipMon.getDocument();
    //Document class doc variable stores what happens in the getDocument()
    //method, getDocument() i think is what checked it real time we shall see
    tipMonListener.addDocumentListener(this);
    //add listener to he text field, this refers to most recent object (tipMon = new JTextField("0");"
    //notice how its purple is the same as new where the object got made?
    add(tipMon);

    hourMon = new JTextField("0");
    Document hourMonListener = hourMon.getDocument();
    hourMonListener.addDocumentListener(this);
    add(hourMon);


    monWage = new JLabel("0");
    add(monWage);

    tues = new JLabel("Tuesday");
    add(tues);
    tipTues = new JTextField("0");
    add(tipTues);
    hourTues = new JTextField("0");
    add(hourTues);
    tuesWage = new JLabel("0");
    add(tuesWage);

    wed = new JLabel("Wednesday");
    add(wed);
    tipWed = new JTextField("0");
    add(tipWed);
    hourWed = new JTextField("0");
    add(hourWed);
    wedWage = new JLabel("0");
    add(wedWage);

    thurs = new JLabel("Thursday");
    add(thurs);
    tipThurs = new JTextField("0");
    add(tipThurs);
    hourThurs = new JTextField("0");
    add(hourThurs);
    thursWage = new JLabel("0");
    add(thursWage);

    fri = new JLabel("Friday");
    add(fri);
    tipFri = new JTextField("0");
    add(tipFri);
    hourFri = new JTextField("0");
    add(hourFri);
    friWage = new JLabel("0");
    add(friWage);

    sat = new JLabel("Saturday");
    add(sat);
    tipSat = new JTextField("0");
    add(tipSat);
    hourSat = new JTextField("0");
    add(hourSat);
    satWage = new JLabel("0");
    add(satWage);

    sun = new JLabel("Sunday");
    add(sun);
    tipSun = new JTextField("0");
    add(tipSun);
    hourSun = new JTextField("0");
    add(hourSun);
    sunWage = new JLabel("0");
    add(sunWage);

    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);

    total = new JLabel("Total: ");
    add(total);
    totalTips = new JLabel("totalTipsOutput");
    add(totalTips);
    totalHours = new JLabel("totalHoursOutput");
    add(totalHours);
    totalHourlyEarnings = new JLabel("totalHourlyEarningsOutput");
    add(totalHourlyEarnings);

    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);

    blank = new JLabel();
    add(blank);
    blank = new JLabel();
    add(blank);
    totalPay = new JLabel("Gross Income: ");
    add(totalPay);
    weekPay = new JLabel("totalPayOutput");
    add(weekPay);

}

@Override
public void changedUpdate(DocumentEvent e) { 
    // TODO Auto-generated method stub

}

@Override
public void insertUpdate(DocumentEvent e) {
    //executes when someone enters text into input
    String tipMonStr = tipMon.getText();
    //monWage.setText(tipMonStr);
    String hourMonStr = hourMon.getText();

    double x = Double.parseDouble(tipMonStr);
    double y = Double.parseDouble(hourMonStr);
    double z = Double.parseDouble(hourlyWageInput.getText());

    if (tipMonStr.length() == 0) {
        tipMon.setText("0");
    }

    if (hourMonStr.length() == 0) {
        y = 0;
        hourMonStr = "0";
    }

    if (hourlyWageInput.getText().length() == 0) {
        z = 0;
        //String z = "0";
    }

    monWage.setText(Double.toString((z*y+x)/y));

    //bug when nothing in cell because no number (0) to use in math
}

@Override
public void removeUpdate(DocumentEvent e) {
    //executes when someone enters text into input
    String tipMonStr = tipMon.getText();
    //monWage.setText(tipMonStr);
    String hourMonStr = hourMon.getText();

    double x = Double.parseDouble(tipMonStr);
    double y = Double.parseDouble(hourMonStr);
    double z = Double.parseDouble(hourlyWageInput.getText());
    monWage.setText(Double.toString((z*y+x)/y));

    if (tipMon.equals("") || tipMon == null) {
        tipMon.setText("0");
    }

}


public void updateLog(DocumentEvent e, String action) {
    monWage.setText(Double.toString(5));
}

@Override
public void actionPerformed(ActionEvent arg0) {
    monWage.setText(Double.toString(5));

}

}


person David Tunnell    schedule 05.08.2012    source источник


Ответы (3)


Я сделаю это ответом: я бы не использовал DocumentListener для этой цели, так как мне кажется, что это неправильный инструмент для работы. Во-первых, он постоянно прослушивает и обновляет результаты, в то время как пользователь все еще вводит данные, которые еще не завершены, в JTextField. Гораздо лучше было бы использовать ActionListener, добавленный к JButton или к вашим JTextFields.

Я полагаю, вы могли бы использовать FocusListener, но даже это меня беспокоит, поскольку он довольно низкоуровневый.

Также: рассмотрите возможность использования InputVerifier для проверки вашего ввода.

Кроме того: рассмотрите возможность отображения ваших табличных данных в JTable, где 1-й и 2-й столбцы доступны для редактирования, а другие - нет.

Изменить
Я не уверен, что это кошерно, но это может сработать, если вы сделаете расчет из верификатора. Например, обновлено для общности:

import javax.swing.*;

/**
* @see http://stackoverflow.com/a/11818183/522444
*/
public class VerifierEg {

    private static final String ZERO = "0.0";
    private JTextField field1 = new JTextField(ZERO, 5);
    private JTextField field2 = new JTextField(ZERO, 5);
    private JTextField resultField = new JTextField(ZERO, 10);

    private void createAndShowGui() {
        resultField.setEditable(false);
        resultField.setFocusable(false);

        JPanel mainPanel = new JPanel();
        final JTextField[] fields = {field1, field2};

        mainPanel.add(field1);
        mainPanel.add(new JLabel(" x "));
        mainPanel.add(field2);
        mainPanel.add(new JLabel(" = "));
        mainPanel.add(resultField);

        for (JTextField field : fields) {
            field.setInputVerifier(new MyInputVerifier(field));
        }

        JFrame frame = new JFrame("VerifierEg");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private void calcProduct() {
        double d1 = Double.parseDouble(field1.getText());
        double d2 = Double.parseDouble(field2.getText());
        double prod = d1 * d2;
        resultField.setText(String.valueOf(prod));
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                VerifierEg eg = new VerifierEg();
                eg.createAndShowGui();
            }
        });
    }

    /**
    * @see http://stackoverflow.com/a/11818946/230513
    */
    private class MyInputVerifier extends InputVerifier {

        private JTextField field;
        private double value;

        public MyInputVerifier(JTextField field) {
            this.field = field;
        }

        @Override
        public boolean shouldYieldFocus(JComponent input) {
            if (verify(input)) {
                field.setText(String.valueOf(value));
                calcProduct();
                return true;
            } else {
                field.setText(ZERO);
                field.selectAll();
                return false;
            }

        }

        @Override
        public boolean verify(JComponent input) {
            try {
                value = Double.parseDouble(field.getText());
                return true;
            } catch (NumberFormatException e) {
                return false;
            }
        }
    }
}
person Hovercraft Full Of Eels    schedule 05.08.2012
comment
Спасибо за ваш вдумчивый ответ. Первоначально я использовал прослушиватель действий, но мне показалось, что нажимать ввод в каждом поле неудобно. Я попробую кнопку, которая вычисляет все для пользователя. Я также проверю InputVerifier. И я посмотрю на JTabel. - person David Tunnell; 05.08.2012
comment
Обновлено, чтобы включить немного более общий InputVerifier. - person trashgod; 06.08.2012

Как предполагает @HFOE, InputVerifier является правильным выбором, но verify() "должен иметь никаких побочных эффектов». Вместо этого вызовите calcProduct() в shouldYieldFocus().

 /**
 * @see http://stackoverflow.com/a/11818946/230513
 */
private class MyInputVerifier extends InputVerifier {

    private JTextField field;
    private double value;

    public MyInputVerifier(JTextField field) {
        this.field = field;
    }

    @Override
    public boolean shouldYieldFocus(JComponent input) {
        if (verify(input)) {
            field.setText(String.valueOf(value));
            calcProduct();
            return true;
        } else {
            field.setText(ZERO);
            field.selectAll();
            return false;
        }

    }

    @Override
    public boolean verify(JComponent input) {
        try {
            value = Double.parseDouble(field.getText());
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}
person trashgod    schedule 05.08.2012
comment
Я должен удалить свой ответ из уважения к этому, гораздо лучшему ответу. Спасибо, что показали мне что-то новое! - person Hovercraft Full Of Eels; 05.08.2012
comment
@HovercraftFullOfEels: Пожалуйста, передумайте; Я призываю вас включить этот фрагмент в ваш полный пример. - person trashgod; 05.08.2012
comment
Я думаю (может быть, я ошибаюсь), что aterai или StanislavL описали эту проблему с более подробным описанием (не удалось выяснить) и обходным путем, поэтому я использую JSpinner или JFormattedTextField (например, число) как ясный и простой альтернатива - person mKorbel; 05.08.2012
comment
@mKorbel: вы в хорошей компании. InputVerifier не имеет встроенного способа сообщить пользователю, что не так. Всплывающая подсказка или строка состояния являются общими средствами. - person trashgod; 06.08.2012

  • используйте JSpinner или JFormattedTextField с Number instance, тогда DocumentListener должно работать правильно, no needed to parse String to Number instance

  • в противном случае вы должны использовать DocumentFilter вместо JTextField для фильтрации non numeric chars, остальное (подсчет) остается неизменным, все еще required robust parsing String to the Number instance

person mKorbel    schedule 05.08.2012