【问题标题】:Why is my Swing application freezing?为什么我的 Swing 应用程序冻结?
【发布时间】:2013-06-20 19:45:47
【问题描述】:

基本上,每次我点击我的一个 JButton 时,它都会锁定。我环顾四周,发现可能是因为无限循环,但我在任何地方都看不到。

一双新鲜的眼睛会派上用场!

无论如何,这里是声明的 JButton:

public static JButton textYes = new JButton("Yes");
public static JButton textNo = new JButton("No");

这是我的 main() 方法:

public static void main(String[] args) throws IOException {
    Greed gui = new Greed();
    gui.launchFrame();
    redirectSystemStreams();

    Container contentPane = f.getContentPane();
    contentPane.add(new Greed());

    Scanner is = new Scanner(System.in);
    System.out.println("Welcome to Greed...");
        //do {
    System.out.println("Would you like to play? (yes/no)");
    area = "menu";
    menu = is.next();
}

这里是 Start() 方法:

public static void start(String menu) {
            switch (menu) {
                case "yes":
                    jTextArea1.setText(null);
                    diceOne = 0;
                    diceTwo = 0;
                    diceThree = 0;
                    diceFour = 0;
                    diceFive = 0;
                    System.out.println("Rolling...");
                    Game();

                    break;
                case "no":
                    System.out.println("Goodbye...");
                    System.exit(0);

                    break;
                default:
                    invalidInput();

                    break;
            }
}

这里是带有 JButton 监听器的 actionPerformed() 方法:

public void actionPerformed(ActionEvent e) {
    //jTextArea1.setText(null);
    if (box1.isSelected()) {
        System.out.println("1 is selected");
        willRerollDiceOne = true;
    }
    else {
        //System.out.println("1 not selected");
        willRerollDiceOne = false;
    }
    if (box2.isSelected()) {
        System.out.println("2 is selected");
        willRerollDiceTwo = true;
    }
    else {
        //System.out.println("2 not selected");
        willRerollDiceTwo = false;
    }
    if (box3.isSelected()) {
        System.out.println("3 is selected");
        willRerollDiceThree = true;
    }
    else {
        //System.out.println("3 not selected");
        willRerollDiceThree = false;
    }
    if (box4.isSelected()) {
        System.out.println("4 is selected");
        willRerollDiceFour = true;
    }
    else {
        //System.out.println("4 not selected");
        willRerollDiceFour = false;
    }
    if (box5.isSelected()) {
        System.out.println("5 is selected");
        willRerollDiceFive = true;
    }
    else {
        //System.out.println("5 not selected");
        willRerollDiceFive = false;
    }

    if ("menu".equals(area)) {
        if(e.getSource() == textYes){
            start("yes");
        }
        if(e.getSource() == textNo){
            start("no");
        }
    }
    if ("choiceReroll".equals(area)) {
        if(e.getSource() == textYes){
            choiceReroll = "yes";
        }
        if(e.getSource() == textNo){
            choiceReroll = "no";
        }
    }
}

我认为它以某种方式连接到 JButton。

如果我需要显示更多代码,请告诉我。

无论如何,我们都非常感谢您的帮助!

感谢您的帮助和时间!

编辑:很抱歉,我忘了显示连接到 JBUttons 的听众:

textYes.addActionListener(this);
textNo.addActionListener(this);

编辑:另外,这里是 Game() 方法:

public static void Game() {
    rollDiceOne();
    rollDiceTwo();
    rollDiceThree();
    rollDiceFour();
    rollDiceFive();

    displayDiceValues();
    f.validate();
    f.repaint();

    choiceRerollDice();
}

还有 rollDice# 方法:

public static void rollDiceOne() {
    diceOne = 1 + (int)(Math.random()*6);
}
public static void rollDiceTwo() {
    diceTwo = 1 + (int)(Math.random()*6);
}
public static void rollDiceThree() {
    diceThree = 1 + (int)(Math.random()*6);
}
public static void rollDiceFour() {
    diceFour = 1 + (int)(Math.random()*6);
}
public static void rollDiceFive() {
    diceFive = 1 + (int)(Math.random()*6);
}

【问题讨论】:

  • Game() 是做什么的?看起来您在 UI 线程中进行处理,这使 UI 无法更新。
  • 游戏运行几种不同的方法。我可以很快发布 Game() 方法。
  • 我们还需要所有的 rollDice# 方法。
  • 当然,我也会把它们放上来。
  • 尽管他们所做的只是掷骰子

标签: java swing user-interface jbutton infinite-loop


【解决方案1】:

问题是您的ActionListener 无需使用新线程即可完成所有操作。这意味着您正在冻结 UI 线程,这基本上会阻止 UI 刷新。

您可以做的是在actionPerformed 方法中使用Thread。

public void actionPerformed(final ActionEvent e) {
    Thread t = new Thread() {
        public void run() {
            //jTextArea1.setText(null);
            if (box1.isSelected()) {
                System.out.println("1 is selected");
                willRerollDiceOne = true;
            }
            else {
                //System.out.println("1 not selected");
                willRerollDiceOne = false;
            }
            if (box2.isSelected()) {
                System.out.println("2 is selected");
                willRerollDiceTwo = true;
            }
            else {
                //System.out.println("2 not selected");
                willRerollDiceTwo = false;
            }
            if (box3.isSelected()) {
                System.out.println("3 is selected");
                willRerollDiceThree = true;
            }
            else {
                //System.out.println("3 not selected");
                willRerollDiceThree = false;
            }
            if (box4.isSelected()) {
                System.out.println("4 is selected");
                willRerollDiceFour = true;
            }
            else {
                //System.out.println("4 not selected");
                willRerollDiceFour = false;
            }
            if (box5.isSelected()) {
                System.out.println("5 is selected");
                willRerollDiceFive = true;
            }
            else {
                //System.out.println("5 not selected");
                willRerollDiceFive = false;
            }

            if ("menu".equals(area)) {
                if(e.getSource() == textYes){
                    start("yes");
                }
                if(e.getSource() == textNo){
                    start("no");
                }
            }
            if ("choiceReroll".equals(area)) {
                if(e.getSource() == textYes){
                    choiceReroll = "yes";
                }
                if(e.getSource() == textNo){
                    choiceReroll = "no";
                }
            }
        }
    };
    t.start();

}

使用线程将防止 UI 冻结

更新

正如 MadProgrammer 所说,在这种情况下,最好使用 SwingWorker 而不是线程

【讨论】:

  • 这不起作用,它只是说“线程不能应用于给定类型”和“局部变量 e 是从内部类中访问的;需要声明为 final”。还有其他想法吗?我真的很感激。
  • @user2506658 是的,Thread 不能使用局部变量,除非它们是 final。所以你需要使用final变量或Instance variables。对于线程不能应用于给定类型,抛出的Exception 的完整消息是什么?
  • @user2506658 查看我的编辑,将public void actionPerformed(ActionEvent e) 更改为public void actionPerformed(final ActionEvent e),局部变量 e 从内部类中访问;需要声明为final错误应该消失
  • "类 Thread 中的方法开始不能应用于给定类型;必需:未找到参数:字符串原因:实际参数列表和正式参数列表的长度不同"
  • @BackSlash 当心,这个答案可能会引起注意,因为它违反了 Swing 的单线程合同,导致 OP 得到一个不正确的答案。
【解决方案2】:

我怀疑choiceRerollDice 正在使用扫描仪来读取用户的输入,这会阻塞事件调度线程,从而阻止它被重新绘制。

您将 CLI 范式与 GUI 范式混合在一起,这又提出了一个问题,为什么?

在使用图形界面时,您不应使用 CLI 样式输入(即Scanner),而应使用可用的图形控件,例如按钮或文本字段

【讨论】:

    【解决方案3】:

    看起来您从未将任何侦听器附加到按钮,而是尝试从 System.in 中读取。如果这是真的,那么程序将挂起,等待来自 System.in 的输入。

    而不是拥有

    Scanner is = new Scanner(System.in);
    ...
    area = "menu";
    menu = is.next();
    

    在按钮上使用 actionListeners,与

    textYes.addActionListener(/*Your Action Listener*/);
    ...
    

    编辑 - 即使附加了 ActionListeners,它也会挂在 Scanner 行上,试图从输入流中读取。删除这些行应该可以解决它。

    【讨论】:

    • 很抱歉,但我确实有一些听众,我只是错过了提及。
    • 删除哪些行? The menu = is.next(); ?
    • “扫描仪是 = new Scanner(System.in);”和“菜单= is.next;”线。除非您希望用户输入他们的回复,否则不需要这些。
    • 不。即使删除了这些行,它仍然存在同样的问题。
    • 哦。此外,每当我尝试使用 textYes.addActionListener(); 时,它都会告诉我它不是抽象的。
    猜你喜欢
    • 2016-02-10
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多