从ActionPerformed方法中重复更改JButton文本

时间:2015-08-29 21:48:05

标签: java swing jbutton action dice

所以我对java比较陌生(自学成才,所以我会喜欢你能给出的任何建议/批评)作为练习我决定使用Jbuttons作为Dice创建一个掷骰子滚动程序。为了模拟骰子的滚动,我想在呈现结果之前将Jbutton的文本随机地改变为不同的数字几秒钟。

我写这样做的方法似乎有效,直到我试图从ActionPerformed方法中调用。当我这样做时,程序将冻结直到方法结束,然后将按钮文本更改为最终结果。

我很好奇是否有人可以解释为什么会发生这种情况,或者教我正确的做法。谢谢你的帮助。

Bellow是同一问题的一个简单例子

    package experiments.changingtext;

    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.*;

    public class ChangingText extends JFrame implements ActionListener{

    JButton button = new JButton("Change Me");

    public ChangingText(){

        this.setSize(200,200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel pane = new JPanel();

        button.addActionListener(this);
        pane.add(button);

        this.add(pane);

        this.setVisible(true);

        try{Thread.sleep(500);}catch(Exception ex){}
        //Works as expected
        this.changeButtonText();
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        //when run program freezes and presents the final text "change to 5"
        if(e.getSource() == button){
            button.setText("change to 1");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 2");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 3");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 4");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 5");
        }
    }

    public void changeButtonText(){

        button.setText("change to 1");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 2");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 3");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 4");
            try{Thread.sleep(500);}catch(Exception ex){}

            button.setText("change to 5");
    }
}

1 个答案:

答案 0 :(得分:3)

不需要直接使用后台线程。而是使用Swing Timer为您进行后台计数,最重要的是,允许在Swing事件线程上进行所有间歇性调用。有关如何使用这个非常有用的工具的更多信息,请查看Swing Timer Tutorial。简而言之,您在JButton的ActionListener中创建一个新的Timer,为Timer提供自己的ActionListener,它保存重复调用的代码,直到完成。

例如:

import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.Map;
import java.util.Random;

import javax.swing.*;

public class ChangingText2 extends JPanel {
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private static final float PTS = 24f;
    public static final int TIMER_DELAY = 200;
    public static final int MAX_TIME = 2000;
    private JButton button = new JButton("1");

    public ChangingText2() {
        button.setFont(button.getFont().deriveFont(Font.BOLD, PTS));
        button.addActionListener(new ButtonListener());

        setLayout(new GridBagLayout());
        add(button);
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private class ButtonListener implements ActionListener {

        private Timer timer;

        @Override
        public void actionPerformed(ActionEvent e) {
            if (timer != null && timer.isRunning()) {
                return;
            }
            timer = new Timer(TIMER_DELAY, new ActionListener() {
                private int count = 0;

                @Override
                public void actionPerformed(ActionEvent e2) {
                    if (count * TIMER_DELAY > MAX_TIME) {
                        ((Timer) e2.getSource()).stop();
                        return;
                    }
                    count++;
                    Die die = Die.getRandomDie();
                    ((AbstractButton) e.getSource()).setText("" + die.getValue());
                }
            });
            timer.start();
        }
    }

    private static void createAndShowGui() {
        ChangingText2 mainPanel = new ChangingText2();

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

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

enum Die {
    ONE(1), TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6);
    private int value;
    private static Random random = new Random();

    private Die(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public static Die getRandomDie() {
        int index = random.nextInt(Die.values().length);
        return Die.values()[index];
    }

}