5

重複の可能性:
単一のスレッドに sleep() を使用する

Thread.sleep() を使用しているときに JTextField.setText() に問題があります。これは私が作っている基本的な電卓用です。入力フィールドへの入力が正しい形式ではない場合、出力フィールドに「INPUT ERROR」が 5 秒間表示されてからクリアされるようにします。setText() メソッド、テキストを一度「INPUT ERROR」に設定しただけで機能し、その間にテキストを印刷することで、それと setText("") の両方で次々と機能することがわかりました。問題は、それらの間に Thread.sleep() を配置すると発生します。コードの SSCCE バージョンは次のとおりです。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.regex.Pattern;
import javax.swing.*;

public class Calc {
    static Calc calc = new Calc();

    public static void main(String args[]) {
        GUI gui = calc.new GUI();
    }

    public class GUI implements ActionListener {

        private JButton equals;

        private JTextField inputField, outputField;

        public GUI() {
            createFrame();
        }

        public void createFrame() {
            JFrame baseFrame = new JFrame("Calculator");
            baseFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel contentPane = new JPanel();
            BoxLayout layout = new BoxLayout(contentPane, BoxLayout.Y_AXIS);
            contentPane.setLayout(layout);
            baseFrame.setContentPane(contentPane);
            baseFrame.setSize(320, 100);

            equals = new JButton("=");
            equals.addActionListener(this);

            inputField = new JTextField(16);
            inputField.setHorizontalAlignment(JTextField.TRAILING);
            outputField = new JTextField(16);
            outputField.setHorizontalAlignment(JTextField.TRAILING);
            outputField.setEditable(false);

            contentPane.add(inputField);
            contentPane.add(outputField);
            contentPane.add(equals);

            contentPane.getRootPane().setDefaultButton(equals);
            baseFrame.setResizable(false);
            baseFrame.setLocation(100, 100);

            baseFrame.setVisible(true);
        }

        /**
         * When an action event takes place, the source is identified and the
         * appropriate action is taken.
         */

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == equals) {
                inputField.setText(inputField.getText().replaceAll("\\s", ""));
                String text = inputField.getText();
                System.out.println(text);
                Pattern equationPattern = Pattern.compile("[\\d(][\\d-+*/()]+[)\\d]");
                boolean match = equationPattern.matcher(text).matches();
                System.out.println(match);
                if (match) {
                    // Another class calculates
                } else {
                    try {
                        outputField.setText("INPUT ERROR"); // This doesn't appear
                        Thread.sleep(5000);
                        outputField.setText("");
                    } catch (InterruptedException e1) {
                    }
                }
            }
        }
    }
}

私は実際にはネストされたクラスを使用していませんが、1 つのクラスに含めることができるようにしたかったのです。GUI の外観については申し訳ありませんが、これもコードを削減するためのものです。重要なセクション ( if (e.getSource() == equals)) は、私のコードから変更されていません。間違った入力を行う最も簡単な方法は、文字を使用することです。

4

3 に答える 3

12

使用するときThread.sleep()は、メインスレッドで実行しています。これにより、GUI が 5 秒間フリーズしてから、outputField. その場合、最後に設定された空白のテキストが使用されます。

Swing Timersを使用する方がはるかに優れています。これは、達成しようとしていることを実行する例です。

if (match) {
    // Another class calculates
} else {
    outputField.setText("INPUT ERROR");
    ActionListener listener = new ActionListener(){
        public void actionPerformed(ActionEvent event){
            outputField.setText("");
        }
    };
    Timer timer = new Timer(5000, listener);
    timer.setRepeats(false);
    timer.start();
}
于 2013-01-01T00:25:31.760 に答える
8

フィリップホワイトハウスが彼の答えで述べているように、あなたはThread.sleep(...)呼び出しでスイングイベントディスパッチスレッドをブロックしています。

すでに設定するのに時間がかかっていることを考えると、テキストのクリアを制御するためActionListenerにを使用するのがおそらく最も簡単でしょう。javax.swing.Timerこれを行うには、GUIクラスにフィールドを追加します。

    private Timer clearTimer = new Timer(5000, this);

のコンストラクターでGUI、リピート機能をオフにします。実際にはワンショットしか必要ないためです。

    public GUI() {
        clearTimer.setRepeats(false);
        createFrame();
    }

次に、actionPerformedこれを使用してタイマーを開始/フィールドをクリアするように変更できます。

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == equals) {
            inputField.setText(inputField.getText().replaceAll("\\s", ""));
            String text = inputField.getText();
            System.out.println(text);
            Pattern equationPattern = Pattern.compile("[\\d(][\\d-+*/()]+[)\\d]");
            boolean match = equationPattern.matcher(text).matches();
            System.out.println(match);
            if (match) {
                // Another class calculates
            } else {
                clearTimer.restart();
                outputField.setText("INPUT ERROR"); // This doesn't appear
            }
        } else if (e.getSource() == clearTimer) {
            outputField.setText("");
        }
    }
于 2013-01-01T00:52:04.417 に答える
8

Thread.sleep()Swing のメイン スレッドで実行しています。これは良い習慣ではありません。SwingWorkerせいぜいスレッドを使用する必要があります。

何が起こっているかというと、最初の行を実行してThread.sleep().

これにより、(メイン) EDT スレッドが再描画を実行できなくなります (次の行が実行されなくなります)。

a を使用javax.swing.Timerして遅延反応をセットアップし、sleep()呼び出しをメイン スレッドに置かないでください。

于 2013-01-01T00:17:00.820 に答える