Guybrush
Guybrush

Reputation: 256

Communicating with a parent JPanel

I'm creating a Java application using Swing and the MVC design pattern.

The application is designed as follows:

On the login screen, the user enters a pin and student ID, if these match a token in the database, I need to pass the Token object to another screen of my application (a question screen that I haven't implemented yet) or have it available somehow. The token is retrieved from an embedded Derby database.

The only way I can think of doing this is creating a utility class with static Token variable that can be accessed by the other classes (this seems like a nasty way to do it). Am I having trouble with this because the design of my application is flawed? Is there any technique I can use to pass the Token across the different screens of my application?

Main

public static void main(String[] args) {
    QuizPanel quizPanel = new QuizPanel();

    JFrame frame = new JFrame("Quiz");
    frame.setPreferredSize(new Dimension(400, 400));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(quizPanel);
    frame.pack();
    frame.setLocationRelativeTo(null);

    frame.setVisible(true);
}

QuizPanel Class

public class QuizPanel extends JPanel implements Switchable{

    private MainMenuPane mainMenuPane;
    private RegisterPane registerPane;
    private LoginPane loginPane;

    public QuizPanel() {
        setLayout(new BorderLayout());

        registerPane = new RegisterPane();
        RegisterController registerController = new RegisterController(registerPane, this);

        mainMenuPane = new MainMenuPane();
        MainMenuController mainMenuController = new MainMenuController(mainMenuPane, this);

        loginPane = new LoginPane();
        LoginController loginController = new LoginController(loginPane, this);

        switchView(ViewState.MAINMENU_STATE);
    }

    @Override
    public void switchView(ViewState state) {
        System.out.println("Changing state: " + state);
        switch (state) {
            case REGISTER_STATE:
                removeAll();
                setLayout(new BorderLayout());
                add(registerPane, BorderLayout.CENTER);
                repaint();
                revalidate();
                break;
            case MAINMENU_STATE:
                removeAll();
                setLayout(new BorderLayout());
                add(mainMenuPane, BorderLayout.CENTER);
                repaint();
                revalidate();
                break;
            case LOGIN_STATE:
                removeAll();
                setLayout(new BorderLayout());
                add(loginPane, BorderLayout.CENTER);
                repaint();
                revalidate();
                break;
            default:
                System.out.println("UNREGISTERED STATE!");
                break;
        }
    }
}

Login Controller

public class LoginController implements ILoginController, ILoginViewObserver {
    private ILoginView view;
    private LoginModel loginModel;
    private Switchable parentView;

    public LoginController(ILoginView view, Switchable parentView) {
        this.view = view;
        this.loginModel = new LoginModel();
        this.parentView = parentView;

        view.addLoginViewObserver(this);
    }

    @Override
    public ILoginView getLoginView() {
        return view;
    }

    @Override
    public void submitButtonWasPressed(Token token) {
        Token verifiedToken = loginModel.verifyToken(token);

        if (verifiedToken != null) {
            System.out.println("Token (" + token.token + ") successfully verified");
            // How can I pass the token to the new JPanel the parent view will be displaying?
        } else {
            System.out.println("Token is invalid");
        }
    }

    @Override
    public void cancelButtonWasPressed() {
        parentView.switchView(ViewState.MAINMENU_STATE);
    }
}

LoginModel Class

public class LoginModel {
    private List<Token> tokens;

    public LoginModel() {
        TokenDao tokenAccessObject = new TokenAccessObject();
        tokens = tokenAccessObject.getAllTokens();
    }

    public Token verifyToken(Token providedToken) {
        for (Token token : tokens) {
            if (token.studentID == providedToken.studentID){
                if (token.token.compareTo(providedToken.token) == 0) {
                    return token;
                }
            }
        }
        return null;
    }
}

Upvotes: 0

Views: 470

Answers (3)

Sergiy Medvynskyy
Sergiy Medvynskyy

Reputation: 11327

I think that in this case you can use Singleton pattern. This pattern should be used as rarely as possible, but in your case (common information which must be accessed from different classes of application) you can use it (IMHO).

But in your case you can also use one Swing feature.

  1. Any Swing window has a root pane. And each JComponent that is laid out in the window has access to this pane.
  2. JComponent has also possibility to store some user data in a map, called "client properties". Because JRootPane extends JComponent you can store/retrieve your token is this map.

Here is a simple code:

public class TokenUtils {

    private static final String TOKEN_PROPERTY = "token";

    public static Token findToken(JComponent component) {
        JRootPane root = component.getRootPane();
        if (root != null) {
            return Token.class.cast(root.getClientProperty(TOKEN_PROPERTY));
        }
       return null;
    }

    public static void putToken(JComponent component, Token token) {
        JRootPane root = component.getRootPane();
        if (root != null) {
            root.putClientProperty(TOKEN_PROPERTY, token);
        }
    }
}

Important: if you use more than one window, you must put the token into the each of them.

Upvotes: 1

Donatic
Donatic

Reputation: 323

A methode to pass the value of the token to the parent JPanel is to add a methode in your interface like setToken(int token) and a global variable in your Quiz panel

QuizPanel:

private int token;
@Override
public void setToken(int token){
     this.token = token;
}

Swiched Interface:

public void setToken(int token);

Login:

parentView.setToken(token);

Than you say parentView.setToken(token) in your LoginController. Now the token variable in the QuizPanel will be set.

Upvotes: 1

Cufe
Cufe

Reputation: 18

You could save the token to a file then on the jpanel read that file to get the token

Upvotes: 0

Related Questions