5

可能重复:
对单个线程使用 sleep()

我在使用 Thread.sleep() 时遇到了 JTextField.setText() 的问题。这是我正在制作的基本计算器。当输入字段中的输入格式不正确时,我希望“输入错误”出现在输出字段中 5 秒钟,然后将其清除。当我将文本设置为“输入错误”一次并打印出中间的文本时,setText() 方法确实有效,我发现它与 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) {
                    }
                }
            }
        }
    }
}

我实际上并没有使用嵌套类,但我希望它能够为您包含在一个类中。对 GUI 的外观感到抱歉,但这又是为了减少代码。重要部分 ( if (e.getSource() == equals)) 与我的代码保持不变。给出错误输入的最简单方法是使用字母。

4

3 回答 3

12

当你使用时,Thread.sleep()你是在主线程上做的。这会将 gui 冻结五秒钟,然后更新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()Swing 主线程中执行操作。这不是好的做法。您最多需要使用SwingWorker线程。

发生的事情是它正在运行第一行,击中Thread.sleep().

这可以防止(主)EDT 线程进行任何重绘(以及防止下一行执行)。

您应该使用 ajavax.swing.Timer来设置延迟反应,而不是将sleep()调用放在主线程中。

于 2013-01-01T00:17:00.820 回答
8

正如 Philip Whitehouse 在他的回答中所说,您正在通过Thread.sleep(...)调用阻止摇摆事件调度线程。

鉴于您已经花时间设置了一个,使用 a来控制清除文本ActionListener可能是最简单的。javax.swing.Timer为此,您可以在GUI类中添加一个字段:

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

在 for 的构造函数中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 回答