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" 解决方案。
我希望这对其他用户有用
亲爱的 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" 解决方案。 我希望这对其他用户有用