从 ActionListener 中中断 for 循环
Breaking for loop from within ActionListener
我正在做一个学校项目,我正在开发一种游戏。在这个游戏中我要求用户登录,我遇到了一些困难。
这是我的代码的相关部分:
import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class User{
int rank;
String name;
String pass;
User(){
Scanner s = new Scanner(System.in);
System.out.println(" Login\n1.New user\n2.Old user");
int in = s.nextInt();
for(;;){
if(in == 1){
//create new user
}else if(in == 2){
JFrame loginFrame = new JFrame();
loginFrame.setVisible(true);
loginFrame.setLayout(null);
loginFrame.setSize(120+14,180+35);
JLabel enterName = new JLabel("Enter Username:");
enterName.setBounds(10,10,100,20);
JTextField nameField = new JTextField();
nameField.setBounds(120,10,130,20);
JLabel enterPass = new JLabel("Enter Password:");
enterPass.setBounds(10,40,100,20);
JPasswordField passField = new JPasswordField();
passField.setBounds(120,40,130,20);
JButton hitEnter = new JButton("Login");
hitEnter.setBounds(10,70,250,20);
loginFrame.add(enterName);
loginFrame.add(nameField);
loginFrame.add(enterPass);
loginFrame.add(passField);
loginFrame.add(hitEnter);
loginFrame.setSize(270+14,100+36);
hitEnter.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent enter){
name = nameField.getText();
pass = new String(passField.getText());
boolean validUser = checkUser(filename,name,pass);
if(validUser){
loginFrame.setVisible(false);
//some how break the for loop from here
}
}
});
}else{
System.out.println("Invalid input.");
}
}
}
如您所见,我需要以某种方式从 actionlistener 内部退出 for 循环,但我不确定是否有任何方法可以做到这一点。
请帮帮我!!!
提前致谢!!!
给你试试看
import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class User{
int rank;
String name;
String pass;
//Added boolean up here
boolean validUser;
User(){
Scanner s = new Scanner(System.in);
System.out.println(" Login\n1.New user\n2.Old user");
int in = s.nextInt();
//Make sure it is set to false
validUser = false;
while(!validUser){
if(in == 1){
//create new user
}else if(in == 2){
JFrame loginFrame = new JFrame();
loginFrame.setVisible(true);
loginFrame.setLayout(null);
loginFrame.setSize(120+14,180+35);
JLabel enterName = new JLabel("Enter Username:");
enterName.setBounds(10,10,100,20);
JTextField nameField = new JTextField();
nameField.setBounds(120,10,130,20);
JLabel enterPass = new JLabel("Enter Password:");
enterPass.setBounds(10,40,100,20);
JPasswordField passField = new JPasswordField();
passField.setBounds(120,40,130,20);
JButton hitEnter = new JButton("Login");
hitEnter.setBounds(10,70,250,20);
loginFrame.add(enterName);
loginFrame.add(nameField);
loginFrame.add(enterPass);
loginFrame.add(passField);
loginFrame.add(hitEnter);
loginFrame.setSize(270+14,100+36);
hitEnter.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent enter){
name = nameField.getText();
pass = new String(passField.getText());
validUser = checkUser(filename,name,pass);
if(validUser){
loginFrame.setVisible(false);
//some how break the for loop from here
}
}
});
}else{
System.out.println("Invalid input.");
}
}
}
问题:
- 首先,您在同一个程序中混合使用 Swing 和控制台代码,而且方式很糟糕。理解控制台(使用基于System.in的Scanner对象)是"linear"代码,程序员完全指挥程序流向的代码,我们经常使用"blocking"代码来获取用户输入,在输入输入之前完全阻止程序流的代码,这很适合你的 while 循环。另一方面,Swing GUI(和大多数 GUI)代码主要是非线性事件驱动代码,用户可以更好地控制何时调用什么代码的代码,主要是避免阻塞代码流(模态对话框除外)。
- 如果您绝对必须将两者结合起来,那么您应该不使用 JFrame,因为显示 JFrame 不会暂停while 循环,它会无限循环,而且不是以一种好的方式。相反,您需要使用 Swing 版本的阻塞代码,一个带有 JDialog 或 JOptionPane 的 modal 对话框。这些将暂停 while 循环,允许更清晰和更线性的输入。
- 而且无论你使用哪个,用户界面代码none都应该在用户class内。此 class 应包含单个用户的状态(字段)和行为(方法),但同样不应包含 UI 代码。那属于别处;否则你最终会得到一堆难以调试和增强的意大利面条代码。所以给你的用户它的字段,包括名字和等级,给它用户方法,当它想让用户做某事时,主程序可以调用它,但是把你的 UI 代码放在 main 方法中。
- 将您的 Swing GUI 用于创建 JPanel,然后您可以将 JPanel 放置在任何需要的地方,从而使代码更加灵活。例如,如果您这样做,那么您可以将 JPanel 放入 JOptionPane 中,这意味着它将显示为 modal 对话框,完全按照您的意愿阻止 while 循环。
- 小问题:避免使用字符串字段作为密码。这使您的程序很容易被侵入,这不是一个好习惯。
因此,如果您绝对必须混合使用 Swing 和控制台,我会这样做:
首先是User.javaclass。同样,只关注用户状态和行为:
public class User {
private int rank;
private String name;
private char[] pass; // ***** Don't store password as a String
// ?? other fields if needed
public User(String name, char[] pass) {
this.name = name;
this.pass = pass;
}
public void setRank(int rank) {
this.rank = rank;
}
public int getRank() {
return rank;
}
public String getName() {
return name;
}
// again, if this were a real-world program, you wouldn't make password accessible
public char[] getPass() {
return pass;
}
// other User methods would go here
@Override
public String toString() {
return "User [rank=" + rank + ", name=" + name + "]";
}
// you'll want to override equals(Object o) and hashCode() here
}
然后您可以创建一个用于获取用户登录信息的 JPanel。当想要显示这种类型的面板时,我喜欢使用 GridBagLayout。例如:
// inports here....
@SuppressWarnings("serial")
public class GetUserInfo extends JPanel {
private static final Insets INSETS = new Insets(4, 4, 4, 4);
private JTextField nameField = new JTextField(10);
private JPasswordField passField = new JPasswordField(10);
public GetUserInfo() {
// gridbaglayout works well for your needs
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = INSETS;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(new JLabel("Name:"), gbc);
gbc.gridy = 1;
add(new JLabel("Password:"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.EAST;
add(nameField, gbc);
gbc.gridy = 1;
add(passField, gbc);
}
// allow classes to query this JPanel for the user name
public String getName() {
return nameField.getText();
}
// and password data
public char[] getPass() {
return passField.getPassword();
}
}
然后将上述内容组合到控制台程序中,在 JOptionPane 中显示此 JPanel,因为这会创建一个 modal 对话框,该对话框会阻止程序流,直到它被处理。您可以使用这样的代码:
// user interface code can go here
Scanner s = new Scanner(System.in);
System.out.println(" Login\n1.New user\n2.Old user: ");
int in = s.nextInt();
s.nextLine();
User user = null; // hold our user object
boolean inputNotOK = true; // keep looping until this is false
GetUserInfo getUserInfo = new GetUserInfo(); // our JPanel for getting user sign in information
if (in == 1) {
// code to get a new user
} else if (in == 2) {
// code to sign in existing user
while (inputNotOK) {
String title = "Get User Name and Password";
int optionType = JOptionPane.OK_CANCEL_OPTION;
int msgType = JOptionPane.PLAIN_MESSAGE;
int value = JOptionPane.showConfirmDialog(null, getUserInfo, title, optionType, msgType);
if (value == JOptionPane.OK_OPTION) {
// if the user presses "OK" on the dialog
String name = getUserInfo.getName();
char[] pass = getUserInfo.getPass();
// validUser is a method that you have that checks if the user sign in is appropriate
if (validUser(name, pass)) {
user = new User(name, pass);
System.out.println("new user: " + user);
inputNotOK = false;
} else {
// show an error JOptionPane here to warn the user
// that their sign-on information was incorrect
}
}
}
}
s.close();
// method that should check to see if user name and password are acceptable
private static boolean validUser(String name, char[] pass) {
// TODO code to test if username and password are OK
// TODO: change this to an actual test
return true;
}
使用这样的代码,如果您以后决定要删除 所有 控制台(扫描器)代码,您可以,因为您现在已经有了一个 JPanel,可以用于桌面 Swing GUI.
我正在做一个学校项目,我正在开发一种游戏。在这个游戏中我要求用户登录,我遇到了一些困难。
这是我的代码的相关部分:
import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class User{
int rank;
String name;
String pass;
User(){
Scanner s = new Scanner(System.in);
System.out.println(" Login\n1.New user\n2.Old user");
int in = s.nextInt();
for(;;){
if(in == 1){
//create new user
}else if(in == 2){
JFrame loginFrame = new JFrame();
loginFrame.setVisible(true);
loginFrame.setLayout(null);
loginFrame.setSize(120+14,180+35);
JLabel enterName = new JLabel("Enter Username:");
enterName.setBounds(10,10,100,20);
JTextField nameField = new JTextField();
nameField.setBounds(120,10,130,20);
JLabel enterPass = new JLabel("Enter Password:");
enterPass.setBounds(10,40,100,20);
JPasswordField passField = new JPasswordField();
passField.setBounds(120,40,130,20);
JButton hitEnter = new JButton("Login");
hitEnter.setBounds(10,70,250,20);
loginFrame.add(enterName);
loginFrame.add(nameField);
loginFrame.add(enterPass);
loginFrame.add(passField);
loginFrame.add(hitEnter);
loginFrame.setSize(270+14,100+36);
hitEnter.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent enter){
name = nameField.getText();
pass = new String(passField.getText());
boolean validUser = checkUser(filename,name,pass);
if(validUser){
loginFrame.setVisible(false);
//some how break the for loop from here
}
}
});
}else{
System.out.println("Invalid input.");
}
}
}
如您所见,我需要以某种方式从 actionlistener 内部退出 for 循环,但我不确定是否有任何方法可以做到这一点。
请帮帮我!!! 提前致谢!!!
给你试试看
import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class User{
int rank;
String name;
String pass;
//Added boolean up here
boolean validUser;
User(){
Scanner s = new Scanner(System.in);
System.out.println(" Login\n1.New user\n2.Old user");
int in = s.nextInt();
//Make sure it is set to false
validUser = false;
while(!validUser){
if(in == 1){
//create new user
}else if(in == 2){
JFrame loginFrame = new JFrame();
loginFrame.setVisible(true);
loginFrame.setLayout(null);
loginFrame.setSize(120+14,180+35);
JLabel enterName = new JLabel("Enter Username:");
enterName.setBounds(10,10,100,20);
JTextField nameField = new JTextField();
nameField.setBounds(120,10,130,20);
JLabel enterPass = new JLabel("Enter Password:");
enterPass.setBounds(10,40,100,20);
JPasswordField passField = new JPasswordField();
passField.setBounds(120,40,130,20);
JButton hitEnter = new JButton("Login");
hitEnter.setBounds(10,70,250,20);
loginFrame.add(enterName);
loginFrame.add(nameField);
loginFrame.add(enterPass);
loginFrame.add(passField);
loginFrame.add(hitEnter);
loginFrame.setSize(270+14,100+36);
hitEnter.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent enter){
name = nameField.getText();
pass = new String(passField.getText());
validUser = checkUser(filename,name,pass);
if(validUser){
loginFrame.setVisible(false);
//some how break the for loop from here
}
}
});
}else{
System.out.println("Invalid input.");
}
}
}
问题:
- 首先,您在同一个程序中混合使用 Swing 和控制台代码,而且方式很糟糕。理解控制台(使用基于System.in的Scanner对象)是"linear"代码,程序员完全指挥程序流向的代码,我们经常使用"blocking"代码来获取用户输入,在输入输入之前完全阻止程序流的代码,这很适合你的 while 循环。另一方面,Swing GUI(和大多数 GUI)代码主要是非线性事件驱动代码,用户可以更好地控制何时调用什么代码的代码,主要是避免阻塞代码流(模态对话框除外)。
- 如果您绝对必须将两者结合起来,那么您应该不使用 JFrame,因为显示 JFrame 不会暂停while 循环,它会无限循环,而且不是以一种好的方式。相反,您需要使用 Swing 版本的阻塞代码,一个带有 JDialog 或 JOptionPane 的 modal 对话框。这些将暂停 while 循环,允许更清晰和更线性的输入。
- 而且无论你使用哪个,用户界面代码none都应该在用户class内。此 class 应包含单个用户的状态(字段)和行为(方法),但同样不应包含 UI 代码。那属于别处;否则你最终会得到一堆难以调试和增强的意大利面条代码。所以给你的用户它的字段,包括名字和等级,给它用户方法,当它想让用户做某事时,主程序可以调用它,但是把你的 UI 代码放在 main 方法中。
- 将您的 Swing GUI 用于创建 JPanel,然后您可以将 JPanel 放置在任何需要的地方,从而使代码更加灵活。例如,如果您这样做,那么您可以将 JPanel 放入 JOptionPane 中,这意味着它将显示为 modal 对话框,完全按照您的意愿阻止 while 循环。
- 小问题:避免使用字符串字段作为密码。这使您的程序很容易被侵入,这不是一个好习惯。
因此,如果您绝对必须混合使用 Swing 和控制台,我会这样做:
首先是User.javaclass。同样,只关注用户状态和行为:
public class User {
private int rank;
private String name;
private char[] pass; // ***** Don't store password as a String
// ?? other fields if needed
public User(String name, char[] pass) {
this.name = name;
this.pass = pass;
}
public void setRank(int rank) {
this.rank = rank;
}
public int getRank() {
return rank;
}
public String getName() {
return name;
}
// again, if this were a real-world program, you wouldn't make password accessible
public char[] getPass() {
return pass;
}
// other User methods would go here
@Override
public String toString() {
return "User [rank=" + rank + ", name=" + name + "]";
}
// you'll want to override equals(Object o) and hashCode() here
}
然后您可以创建一个用于获取用户登录信息的 JPanel。当想要显示这种类型的面板时,我喜欢使用 GridBagLayout。例如:
// inports here....
@SuppressWarnings("serial")
public class GetUserInfo extends JPanel {
private static final Insets INSETS = new Insets(4, 4, 4, 4);
private JTextField nameField = new JTextField(10);
private JPasswordField passField = new JPasswordField(10);
public GetUserInfo() {
// gridbaglayout works well for your needs
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = INSETS;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(new JLabel("Name:"), gbc);
gbc.gridy = 1;
add(new JLabel("Password:"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.EAST;
add(nameField, gbc);
gbc.gridy = 1;
add(passField, gbc);
}
// allow classes to query this JPanel for the user name
public String getName() {
return nameField.getText();
}
// and password data
public char[] getPass() {
return passField.getPassword();
}
}
然后将上述内容组合到控制台程序中,在 JOptionPane 中显示此 JPanel,因为这会创建一个 modal 对话框,该对话框会阻止程序流,直到它被处理。您可以使用这样的代码:
// user interface code can go here
Scanner s = new Scanner(System.in);
System.out.println(" Login\n1.New user\n2.Old user: ");
int in = s.nextInt();
s.nextLine();
User user = null; // hold our user object
boolean inputNotOK = true; // keep looping until this is false
GetUserInfo getUserInfo = new GetUserInfo(); // our JPanel for getting user sign in information
if (in == 1) {
// code to get a new user
} else if (in == 2) {
// code to sign in existing user
while (inputNotOK) {
String title = "Get User Name and Password";
int optionType = JOptionPane.OK_CANCEL_OPTION;
int msgType = JOptionPane.PLAIN_MESSAGE;
int value = JOptionPane.showConfirmDialog(null, getUserInfo, title, optionType, msgType);
if (value == JOptionPane.OK_OPTION) {
// if the user presses "OK" on the dialog
String name = getUserInfo.getName();
char[] pass = getUserInfo.getPass();
// validUser is a method that you have that checks if the user sign in is appropriate
if (validUser(name, pass)) {
user = new User(name, pass);
System.out.println("new user: " + user);
inputNotOK = false;
} else {
// show an error JOptionPane here to warn the user
// that their sign-on information was incorrect
}
}
}
}
s.close();
// method that should check to see if user name and password are acceptable
private static boolean validUser(String name, char[] pass) {
// TODO code to test if username and password are OK
// TODO: change this to an actual test
return true;
}
使用这样的代码,如果您以后决定要删除 所有 控制台(扫描器)代码,您可以,因为您现在已经有了一个 JPanel,可以用于桌面 Swing GUI.