简体   繁体   中英

Issue change JButton text repeatedly from within ActionPerformed method

So I am relatively new to java (self taught so i would love any advice/criticism you could give) and as practice i decided to create a dice rolling program with swing using Jbuttons as Dice. To simulate the rolling of dice I wanted to randomly change the text of the Jbutton to different numbers for a few seconds before presenting the result.

The method I wrote to do this seemed to work until I tried to called if from within the ActionPerformed method. When I did this the program would freeze until the end of the method and then change the buttons text to the final result.

I was curious if someone could explain why this happens, or teach me the correct way do something like this. Thanks for any help.

Bellow is a quick example of the same issue

    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");
    }
}

There's no need to use background threads directly. Rather use a Swing Timer which does the background counting for you, and most importantly, allows all the intermittent calls to be made on the Swing event thread. Please check out the Swing Timer Tutorial for more on how to use this very useful tool. Briefly, you create a new Timer within the JButton's ActionListener, give the Timer its own ActionListener which holds code that it calls repeatedly until done.

For example:

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];
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM