ActionListener 和 for 循环

ActionListener and for loop

亲爱的 Whosebug 朋友们,

这是我正在尝试做的事情: - 我想要一个带有一些按钮和一个 JTextArea 的简单框架 - 我想有一个循环,在每次迭代时,都希望我点击一个按钮:当我点击这个按钮时,会发生很多事情,但我做不对: - 在一次尝试中,我让 for 循环工作但它不会停止,在每一个回合,它只接受第一个命令并执行所有 20 个回合而不停止 - 在当前版本中,我点击按钮没有任何反应 - 我已经研究过 SOF 和一系列其他站点,包括 Oracle 文档,但是(可能也是由于我的经验水平),我找不到足够清楚的解释让我理解

这是我的代码

package game4_prova_forloop;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class GAME4_prova_forloop {

    public static void main(String[] args) {

        //create frame
        JFrame frame = new JFrame("Action Listener");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 600);
        frame.setLayout(new FlowLayout());
        frame.setVisible(true);   

        //crete text area panel, 
        JPanel pannelloTextArea = new JPanel(); 
        pannelloTextArea.setBackground(new Color(255, 204, 204));
        pannelloTextArea.setSize(400, 400);
        frame.add(pannelloTextArea); 
        GroupLayout pannelloTextAreaLayout = new GroupLayout(pannelloTextArea); 

        //create scrollPane
        JScrollPane scrollTextArea = new JScrollPane(); 

        //1) create JTextArea
        JTextArea mostraTesto = new JTextArea(20, 20); 
        mostraTesto.setLineWrap(true);  //make it wrap text 
            pannelloTextArea.add(scrollTextArea); //add it to scroll pane
            pannelloTextArea.revalidate();
                scrollTextArea.add(mostraTesto); //add the scroll pane to text area 
                scrollTextArea.setViewportView(mostraTesto); 

        //2) create buttons 
        JButton action1 = new JButton("1");
        frame.add(action1);
        JButton action2 = new JButton("2");
        frame.add(action2);
        JButton action3 = new JButton("3");
        frame.add(action3);

        //3) pass textArea in the RoundLevelAction class
        RoundLevelAction roundLevelActionObj = new RoundLevelAction(mostraTesto); //first issue: I get an error
        //4) add listener to JButtons
        action1.addActionListener(roundLevelActionObj);
        action2.addActionListener(roundLevelActionObj);
        action3.addActionListener(roundLevelActionObj);          
    }

//THIS IS WHERE I START TO HAVE PROBLEMS: WHEN I CLICK NOTHING HAPPENS, WHEN 
//I WOULD EXPECT THE FOR LOOP TO GO THROUGH ITERATIONS
    public class RoundLevelAction implements ActionListener {

        //add inside the listener the pieces of GUI that you'll use
        private JTextArea mostraTesto;
        private Object action1;
        private Object action2;
        private Object action3;
        private Object action4;
        private Object action5;
        private Object action6;

        //create class for JTextArea
        public RoundLevelAction(JTextArea mostraTesto){
            this.mostraTesto = mostraTesto; 
        }    

        //and, finally, what I really want to do: a loop that, at each turn, expects me to click on 
        //a button and does an action in response
        public void actionPerformed(ActionEvent e) {
            //now create the loop
            for (int round_counter=1; round_counter<21; round_counter++) {                                       
                if (e.getSource()==action1){                             
                    mostraTesto.append("\n description action 1 and a bunch of other stuff");
                }
                else if (e.getSource()== action2){ 
                    mostraTesto.append("\n description action 2 and a bunch of other stuff");
                } 
                else if (e.getSource()== action3){
                    mostraTesto.append("\n description action 3 and a bunch of other stuff");
                } 
            }
        }
    }

}

重要提示:我很清楚上面的代码不符合 Java 最佳实践:它只是一个示例代码来说明我正在尝试做的事情(原始代码有很多行在多个 类)

我希望你能帮助我理解我哪里做错了

非常感谢

为什么您的代码目前无法正常工作,您之前的尝试可能出了什么问题。

action1.addActionListener(roundLevelActionObj);
action2.addActionListener(roundLevelActionObj);
action3.addActionListener(roundLevelActionObj);  

这将为您的每个按钮添加相同的侦听器。当您单击这些按钮中的任何一个时,将生成一个 ActionEvent 并发送到 ActionListener.

当您的 ActionListener 中有一个 for 循环时,每次您单击这些按钮中的任何一个时都会执行整个循环。执行的是 actionPerformed 方法中的整个代码块。这可能是您在第一次尝试时发现的。

您当前的尝试在 for 循环中进行了 if (e.getSource()==action1) 次检查。但是,该语句中的 action1 与您单击的按钮不同。这里的action1指的是字段

private Object action1;

在你的 RoundLevelAction class 中。如果您使用调试器,您会看到 if 语句中的 none 的计算结果为 true,这就是为什么您会觉得没有任何反应。 事实上,for 循环被触发但没有输出任何内容,因为 if 语句中的 none 被评估为真。

如果使用调试器,可以很容易地发现以上所有内容,并放置一些断点。

现在为您解决问题。我不清楚。

I would like to have a loop that, at every iteration, expects for me to click on a button

这个需求的问题在于 Swing 是单线程的。这意味着所有与 Swing 相关的操作都应该在单个线程(E(vent)D(ispatch(T(hread)))上发生,并且同一个线程用于处理用户输入(例如鼠标点击)和绘制 UI。这也意味着,如果您以某种方式阻塞了该单个线程,您的 UI 将变得不负责任。

所以如果你有一个循环,你不能简单地阻止 EDT 并等待按钮点击。由于EDT被屏蔽,所以无法点击EDT

  • 要么在单独的线程上循环,然后在该线程中等待,直到用户单击按钮。与该按钮关联的 ActionListener 然后可以重新激活线程
  • 您可以显示一个对话框,询问用户下一步要做什么,然后将这些按钮放在该对话框中。看看 JOptionPane#show... 方法。

Robin 的出色回答,虽然不是直接的解决方案,但让我思考了程序的逻辑,并问自己:我为什么要有一个 for 循环?要从 20 倒数到 0? 嗯..我总是可以向前数(呃!)。所以我完全摆脱了 for 循环,为每个 else ifs 放置一个计数器 ++,并将所有内容封装到一个 if counter<20 中。 现在每次迭代都通过按下其中一个按钮来激活,迭代上升,游戏遵循逻辑。 不是最佳解决方案,而是 "a" 解决方案。 我希望这对其他用户有用