与父级JPanel通信

时间:2018-08-22 12:22:40

标签: java swing oop

我正在使用Swing和MVC设计模式创建Java应用程序。

该应用程序的设计如下:

  • 有一个类QuizPanel扩展了JPanel。此面板是保存我的应用程序主屏幕的容器。
  • 我的应用程序的每个“屏幕”都是扩展JPanel的单独类。这些JPanel可以根据需要从QuizPanel添加/删除。
  • 顶级QuizPanel实现了我的界面SwitchableSwitchable接口由单个SwitchView(ViewState state)方法组成。我将this传递给在QuizPanel顶层面板中实例化的每个“屏幕”,以便他们可以在按下按钮时调用SwitchView

在登录屏幕上,用户输入一个密码和学生ID,如果它们与数据库中的令牌匹配,我需要将Token对象传递给我的应用程序的另一个屏幕(我尚未回答的问题屏幕)尚未实施)或以某种方式提供。从嵌入式Derby数据库中检索令牌。

我想到的唯一方法是创建一个带有静态Token变量的实用程序类,该变量可以被其他类访问(这似乎是一种讨厌的方法)。因为我的应用程序设计有缺陷,我是否对此感到麻烦?我可以使用任何技术在应用程序的不同屏幕之间传递Token吗?

主要

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类

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;
        }
    }
}

登录控制器

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类

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;
    }
}

3 个答案:

答案 0 :(得分:1)

将令牌的值传递给父级JPanel的方法是在您的界面中添加一个方法,例如setToken(int token)和“测验”面板中的全局变量

QuizPanel:

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

夹心界面:

public void setToken(int token);

登录:

parentView.setToken(token);

在您的LoginController中说parentView.setToken(token)。现在,将在QuizPanel中设置令牌变量。

答案 1 :(得分:1)

我认为在这种情况下,您可以使用Singleton pattern。此模式应尽可能少用,但是在您的情况下(必须从不同应用程序类访问的公共信息),可以使用它(IMHO)。

但是,根据您的情况,您还可以使用一个Swing功能。

  1. 任何Swing窗口都有一个根窗格。然后放置的每个JComponent 窗外的人可以访问此窗格。
  2. JComponent也可以在地图中存储一些用户数据, 称为“客户端属性”。因为JRootPane扩展了JComponent 您可以在地图上存储/检索令牌。

这是一个简单的代码:

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);
        }
    }
}

重要:如果您使用多个窗口,则必须将令牌放入每个窗口中。

答案 2 :(得分:0)

您可以将令牌保存到文件中,然后在jpanel上读取该文件以获取令牌