Прекъсване на цикъл от 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 цикъла отвътре в actionlistener, но не съм сигурен дали има някакъв начин да направя това.

Моля, помогнете ми!!! Благодаря предварително!!!


person sarge424    schedule 22.11.2017    source източник
comment
Вместо безкраен цикъл, защо не използвате цикъл while, който проверява състоянието на влизането и излиза, след като бъде успешен?   -  person azurefrog    schedule 22.11.2017
comment
Не трябва да смесвате GUI код, управляван от събития, и код на конзолата на скенера. Останете или с единия, или с другия.   -  person Hovercraft Full Of Eels    schedule 22.11.2017


Отговори (2)


проблеми:

  • Първо и най-важно, вие смесвате Swing и конзолен код в една и съща програма и по лош начин. Разберете, че конзолата (използваща обект на скенер, базиран на System.in) е "линеен" код, код, при който програмистът изцяло насочва посоката на потока на програмата, където често използваме "блокиращ" код, за да получим въвеждане от потребителя, код, който напълно блокира програмата поток, докато не бъде въведен вход, и това работи добре с вашия цикъл while. Кодът на Swing GUI (и повечето GUI) от друга страна е предимно нелинеен код, управляван от събития, код, при който потребителят има много по-голям контрол върху това кой код кога се извиква, код, който най-вече избягва блокиране на потока от код (с изключение на на модални диалози).
  • Ако абсолютно трябва да комбинирате двете, тогава не трябва да не използвате JFrame, тъй като показването на JFrame няма да постави на пауза цикъла while и ще се повтаря безкрайно, а не в добър смисъл. Вместо това ще трябва да използвате Swing версията на блокиращия код, модален диалог, или с JDialog, или с JOptionPane. Те ще поставят на пауза цикъла while, позволявайки много по-чист и линеен вход.
  • И без значение кой използвате, никой от кода на потребителския интерфейс не трябва да бъде в рамките на потребителския клас. Този клас трябва да съдържа състоянието (полета) и поведението (методи) на отделен потребител, но отново не трябва да включва UI код. Това принадлежи другаде; в противен случай ще се окажете с ужасна смесица от спагети код, който трудно се отстранява и подобрява. Затова дайте на вашия потребител неговите полета, включително име и ранг, дайте му потребителски методи, които главната програма може да извика, когато иска потребителят да направи нещо, но поставете вашия UI код в главния метод.
  • Насочете своя Swing GUI към създаване на JPanel, след което можете да поставите 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 GUI.

person Hovercraft Full Of Eels    schedule 22.11.2017
comment
Благодаря много за отговора. Аз съм просто студент, така че не знаех за всички неща, за които говорите тук, но ви благодаря отново. Определено ще включи всички ваши отзиви. - person sarge424; 23.11.2017

Ето, пробвай го

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.");
            }
        }
    }
person Matt    schedule 22.11.2017