【问题标题】:Issue change JButton text repeatedly from within ActionPerformed method从 ActionPerformed 方法中重复发出更改 JButton 文本
【发布时间】:2015-08-29 21:48:04
【问题描述】:

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

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

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

下面是同一问题的一个简单示例

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

【问题讨论】:

  • Swing 使用单线程来管理事件和绘制,这意味着我们使用 Thread.sleep,你阻塞了事件调度线程,阻止它绘制 ui。相反,您可以使用 Swing Timer

标签: java swing jbutton action dice


【解决方案1】:

无需直接使用后台线程。而是使用 Swing Timer 来为您进行后台计数,最重要的是,它允许在 Swing 事件线程上进行所有间歇性调用。请查看Swing Timer Tutorial,了解更多关于如何使用这个非常有用的工具的信息。简而言之,您在 JButton 的 ActionListener 中创建一个新的 Timer,为 Timer 提供自己的 ActionListener,该 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];
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多