Java Thread Start-Stop-Start在同一按钮上单击

时间:2016-12-27 17:06:15

标签: java multithreading swing button concurrency

我正在创建一个简单的java程序,其中的GUI是在窗口构建器的帮助下构建的。 GUI只包含一个按钮。

点击按钮,启动一个线程,该线程将无限制地打印到随机数,直到再次单击相同的按钮停止它为止。

这是我的代码

LoopTest.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class LoopTest extends JFrame implements ActionListener {//******
    private JButton startB, stopB;
    private JTextArea oa;
    Start sta;

    public LoopTest(){
        super("Final Exam: Question ");

        Container c = getContentPane();
        c.setLayout(new FlowLayout());

        startB = new JButton("START"); c.add(startB);

        stopB = new JButton("STOP"); c.add(stopB);

        oa = new JTextArea(5,20); c.add(oa);
        c.add(new JScrollPane(oa));

        registerEvents();
        sta = new Start("Loop", oa);

    }
    public void registerEvents(){
        startB.addActionListener(
                new ActionListener(){
                    public void actionPerformed(ActionEvent ae){
                        if(startB.isEnabled() == true )
                            sta.setLoopFlag(true);
                        if(!sta.isAlive())
                            sta.start();
                        startB.setEnabled(false);

                    }
                }
        );

        stopB.addActionListener(
                new ActionListener(){
                    public void actionPerformed(ActionEvent ae){
                        if(stopB.isEnabled()==true){
                            sta.setLoopFlag(false);

                        }

                    }

        }

        );
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub

    }
    public static void main(String[] args){
        LoopTest app = new LoopTest();
        app.setSize(300,300);
        app.setLocationRelativeTo(null);
        app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        app.setVisible(true);
    }

}

Start.java

public class Start extends Thread {

private JTextArea ta;
    private boolean loopFlag;

    public Start(String name, JTextArea ta){
        super(name);
        this.ta = ta;
        ta.setText("");
        loopFlag = true;
    }
    public void run(){
        int num=0;
        while(true)
            while(loopFlag){
                num = 1+ (int)(Math.random()*100);
                ta.append(num + "\n");
            }
    }


    public void setLoopFlag(boolean value){
        loopFlag = value;
    }

}

Stop.java

public class Stop extends Thread {
    public Stop( String name ){
        super(name);
    }
    public void run(){

    }
}

提前致谢。

1 个答案:

答案 0 :(得分:1)

当您对Swing事件线程中的Swing组件进行突变更改时,您的代码会破坏Swing线程规则。 建议:

  • 永远不要扩展线程。实现Runnable并在线程中使用Runnable几乎总是更好。
  • 避免在Swing事件线程的repaint()之外进行Swing调用。
  • 你的while (true)是一个“紧”循环 - 它里面没有Thread.sleep,这意味着它可能会在紧密循环中输入CPU,这可能会妨碍你的程序和你的电脑。
  • 最好避免在此完全使用直接背景线程,因为使用Swing Timer可以更轻松,更干净地解决代码问题。请查看Swing Timer Tutorial
  • 您可以通过调用start()stop()方法轻松启动和停止此计时器。
  • 我还优先使用JList而不是JTextArea,因为它可以更轻松地处理大量数据。
  • 我也喜欢在我的JButton中使用AbstractActions而不是ActionListeners,这个问题非常适合他们的使用。你可以创建一个Action for start和一个for stop,然后简单地换掉按钮的动作。

例如:

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class StartStop extends JPanel {
    private static final int TIMER_DELAY = 300;
    private StartAction startAction = new StartAction();
    private StopAction stopAction = new StopAction();
    private JButton button = new JButton(startAction);
    private DefaultListModel<Integer> model = new DefaultListModel<>();
    private JList<Integer> jList = new JList<>(model);
    private Timer timer = new Timer(TIMER_DELAY, new TimerListener());

    public StartStop() {
        JPanel btnPanel = new JPanel();
        btnPanel.add(button);

        jList.setFocusable(false);
        jList.setVisibleRowCount(10);
        jList.setPrototypeCellValue(100000);
        JScrollPane scrollPane = new JScrollPane(jList);

        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);
        add(btnPanel, BorderLayout.PAGE_END);
    }

    private class TimerListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            int num = 1 + (int) (Math.random() * 100);
            model.addElement(num);
        }
    }

    private class StartAction extends AbstractAction {
        public StartAction() {
            super("Start");
            putValue(MNEMONIC_KEY, KeyEvent.VK_S);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            timer.start();
            button.setAction(stopAction);
        }
    }

    private class StopAction extends AbstractAction {
        public StopAction() {
            super("Stop");
            putValue(MNEMONIC_KEY, KeyEvent.VK_S);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            timer.stop();
            button.setAction(startAction);
        }
    }


    private static void createAndShowGui() {
        JFrame frame = new JFrame("Start Stop");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new StartStop());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}