Java 让 GUI 等待一个定时器

Java make GUI wait for a timer

我只是想让这个程序等待一个计时器。我只想让程序暂停两秒钟。我想让这个程序做的是显示 "Start," 等待两秒钟直到计时器完成,然后显示 "Start, Finished Waiting, Finished." 如何让这个程序等待计时器完成?我相信它目前在一个单独的线程中创建计时器,而不是暂停主线程,所以它显示,"Start, Finished" 然后等待两秒钟然后显示 "Start, Finished, Finished Waiting." 这不是我想要的东西的顺序发生在,当 运行 一个 GUI 并找到 none 时,我到处寻找一个简单的计时器示例。感谢您的帮助,这是代码:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;

public class GUI extends JFrame {

    private static final long serialVersionUID = 3560258176733156660L;

    public static void main(String[] args) {
        new GUI().setVisible(true);
    }

    private Timer timer;
    private JTextArea area;
    private String text;

    public GUI() {
        setLayout(null);
        setSize(500, 120);
        setTitle("Timer");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        text = "";
        area = new JTextArea(text);
        area.setBounds(0, 0, 500, 120);
        add(area);
        doThings();

    }
    public void doThings() {
        text += "Start, ";
        area.setText(text);
        // Want program to wait for two seconds
        waitForTwoSeconds();
        text += "Finished ";
        area.setText(text);

    }
    public void waitForTwoSeconds() {

        timer = new Timer(2000, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                text += "Finished Waiting, ";
                area.setText(text);
                timer.stop();
            }
        });
        timer.start();
    }

}

在调用 waitForTwoSeconds 之后获取代码并将其放入 actionPerformed 方法中...

public void doThings() {
    area.setText("Start, ");
    // Want program to wait for two seconds
    waitForTwoSeconds();

}

public void waitForTwoSeconds() {

    timer = new Timer(2000, new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            area.append("Finished Waiting, ");
            area.append("Finished ");
            timer.stop();
        }
    });
    timer.setRepeats(false);
    timer.start();
}

这将导致 Finished Waiting, Finished 在您单击按钮 2 秒后附加到 JTextArea...

您不想在事件调度线程的上下文中执行任何长时间的 running/blocking 操作,这会使您的程序看起来像挂起,因为它已经挂起。

查看,Concurrency in Swing and How to use Swing Timers了解更多详情

已更新...

Swing(和大多数 UIs)是事件驱动的,也就是说,某事发生了,你就响应它。例如,对于 Timer,计时器触发并且您响应了该事件。你不能在 Event Dispatching Thread 中 block/wait,它只会导致 UI 停止响应和绘制,这就是框架的工作方式,你可以学会忍受它或继续对此感到沮丧(记住,想要某样东西和让它发挥作用是两件不同的事情)

但是,您可以做一些事情,Timer 是一个例子,另一个是 SwingWorker

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextArea ta;

        public TestPane() {
            setLayout(new BorderLayout());
            ta = new JTextArea(10, 20);
            JButton btn = new JButton("Make it so");
            add(new JScrollPane(ta));
            add(btn, BorderLayout.SOUTH);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    btn.setEnabled(false);
                    ta.append("Start, ");
                    SwingWorker<String, String> worker = new SwingWorker<String, String>() {

                        @Override
                        protected String doInBackground() throws Exception {
                            Thread.sleep(2000);
                            publish("Finished waiting, ");
                            return null;
                        }

                        @Override
                        protected void process(List<String> chunks) {
                            for (String text : chunks) {
                                ta.append(text);
                            }
                        }

                        @Override
                        protected void done() {
                            ta.append("Finished");
                            btn.setEnabled(true);
                        }

                    };
                    worker.execute();
                }
            });
        }

    }

}

这基本上是在后台线程中等待两秒钟,然后(通过 publish/process 方法)打印 "Finished Waiting",然后在 doInBackground returns, done 被(最终)调用并且 "Finished" 被打印出来。

这一切都已完成,以便 UI 更新发生在事件调度线程的上下文中,满足 Swing 的单线程要求

Ok, so I guess my question should really look like this then:
How do i make the program wait until the waitForTwoSeconds() method is complete before doing area.append("Finished "); ? This is really what I want to accomplish.

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

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;

public class GUI extends JFrame {

    private static final long serialVersionUID = 3560258176733156660L;

    public static void main(String[] args) {
        new GUI().setVisible(true);
    }

    private Timer timer;
    private JTextArea area;

    public GUI() {
        setLayout(null);
        setSize(500, 120);
        setTitle("Timer");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        area = new JTextArea("");
        area.setBounds(0, 0, 500, 120);
        add(area);
        doThings();

    }

    public void doThings() {
        area.setText("Start, ");
        // Want program to wait for two seconds
        waitForTwoSeconds();
        // Don't want to do this until waitForTwoSeconds() has finished...
        area.append("Finished ");

    }

    public void waitForTwoSeconds() {

        timer = new Timer(2000, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                area.append("Finished Waiting, ");
                timer.stop();
            }
        });
        timer.setRepeats(false);
        timer.start();
    }

}