Прерывание цикла из 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.");
}
}
}
как вы можете видеть, мне нужно как-то выйти из цикла for из списка действий, но я не уверен, есть ли способ сделать это.
Пожалуйста, помогите мне! Заранее спасибо!!!
3 ответа
Проблемы:
- Прежде всего, вы смешиваете Swing и консольный код в одной и той же программе. Поймите, что консоль (использующая объект Scanner на основе System.in) представляет собой "линейный" код, код, в котором программист полностью направляет направление потока программы, где мы часто используем "блокирующий" код для получения пользовательского ввода, код, который полностью блокирует программу поток, пока ввод не был введен, и это хорошо работает с вашим циклом while. Код Swing GUI (и большинство GUI), с другой стороны, представляет собой в основном нелинейный код, управляемый событиями, код, в котором пользователь имеет гораздо больший контроль над тем, когда вызывается код, код, который в основном избегает блокирования потока кода (за исключением модальных диалогов).
- Если вам абсолютно необходимо объединить эти два параметра, то вам не следует использовать JFrame, так как отображение JFrame не будет приостанавливать цикл while и будет повторяться бесконечно, а не в хорошем смысле. Вместо этого вам нужно будет использовать версию блокирующего кода Swing, модальное диалоговое окно с JDialog или JOptionPane. Это приостановит цикл while, обеспечивая более чистый и более линейный ввод.
- И независимо от того, что вы используете, ни один из кодов пользовательского интерфейса не должен быть в классе User. Этот класс должен содержать состояние (поля) и поведение (методы) отдельного пользователя, но опять-таки не должен включать код пользовательского интерфейса. Это принадлежит в другом месте; иначе вы получите ужасную смесь спагетти-кода, которую сложно отлаживать и улучшать. Поэтому дайте своему пользователю его поля, включая имя и ранг, дайте ему пользовательские методы, которые основная программа может вызывать, когда он хочет, чтобы пользователь что-то сделал, но поместите свой код пользовательского интерфейса в основной метод.
- Сконцентрируйте ваш Swing GUI на создании JPanels. Затем вы можете разместить JPanel где угодно, что сделает код намного более гибким. Например, если вы сделали это, то можете поместить JPanel в JOptionPane, что означает, что он будет отображаться как модальное диалоговое окно, блокируя цикл while, так, как вам бы хотелось.
- Незначительный спор: избегайте использования полей String для паролей. Это делает вашу программу очень простой для взлома и не является хорошей привычкой.
Итак, еще раз, если вам абсолютно необходимо смешать Swing и консоль, я сделаю что-то вроде этого:
Сначала класс User.java. Опять же, сфокусируйтесь только на состоянии пользователя и поведении:
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();
}
}
А затем, чтобы объединить все вышеперечисленное в консольной программе, отобразите этот JPanel в панели JOptionPane, поскольку это создает модальное диалоговое окно, блокирующее выполнение программы до тех пор, пока оно не будет обработано. Вы можете использовать такой код:
// 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.
Добавьте логическое значение до и внутри ActionListener
, Затем выполните if
заявление, чтобы проверить, должен ли цикл прерваться или продолжить.
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);
boolean shouldBreakLoop = false;
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);
shouldBreakLoop = true;
}
}
});
if (shouldBreakLoop) break;
}else{
System.out.println("Invalid input.");
}
}
}
Вот иди, дай шанс
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.");
}
}
}