Java 与父JPanel通信

Java 与父JPanel通信,java,swing,oop,Java,Swing,Oop,我正在使用Swing和MVC设计模式创建一个Java应用程序 该应用程序的设计如下: 有一个类QuizPanel扩展了JPanel。此面板是保存我的应用程序的主“屏幕”的容器 我的应用程序的每个“屏幕”都是一个单独的类,它扩展了JPanel。这些JPanel根据需要从QuizPanel中添加/删除 顶级的QuizPanel实现了我的界面可切换。Switchable界面由一个SwitchView(ViewState状态)方法组成。我将此传递到QuizPanel顶层面板中实例化的每个“屏幕”,这样

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

该应用程序的设计如下:

  • 有一个类
    QuizPanel
    扩展了
    JPanel
    。此面板是保存我的应用程序的主“屏幕”的容器
  • 我的应用程序的每个“屏幕”都是一个单独的类,它扩展了
    JPanel
    。这些JPanel根据需要从
    QuizPanel
    中添加/删除
  • 顶级的
    QuizPanel
    实现了我的界面
    可切换
    Switchable
    界面由一个
    SwitchView(ViewState状态)
    方法组成。我将此
    传递到
    QuizPanel
    顶层面板中实例化的每个“屏幕”,这样当按下按钮时,他们就可以调用
    SwitchView
在登录屏幕上,用户输入pin和学生ID,如果它们与数据库中的令牌匹配,我需要将
令牌
对象传递到我的应用程序的另一个屏幕(我尚未实现的问题屏幕)或以某种方式使其可用。令牌从嵌入式Derby数据库中检索

我能想到的唯一方法是创建一个带有静态
Token
变量的实用程序类,其他类可以访问该类(这似乎是一种令人讨厌的方法)。我是否因为我的应用程序设计有缺陷而在这方面遇到问题?是否有任何技术可以用于在应用程序的不同屏幕之间传递
令牌

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类

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 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;
    }
}
登录控制器

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);
    }
}
登录模型类

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 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;
    }
}
公共类登录模型{
私有列表令牌;
公共登录模型(){
TokenDao tokenAccessObject=新的tokenAccessObject();
tokens=tokenAccessObject.getAllTokens();
}
公共令牌验证令牌(令牌提供令牌){
for(令牌:令牌){
if(token.studentID==providedToken.studentID){
if(token.token.compareTo(providedToken.token)==0){
返回令牌;
}
}
}
返回null;
}
}

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

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

将令牌的值传递给父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中的token变量

将令牌值传递给父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中的token变量

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

但在您的情况下,您也可以使用一个Swing功能

  • 任何Swing窗口都有根窗格。以及铺设的每个
    j组件
    在窗口外可以访问此窗格
  • 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);
            }
        }
    }
    

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

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

    但在您的情况下,您也可以使用一个Swing功能

  • 任何Swing窗口都有根窗格。以及铺设的每个
    j组件
    在窗口外可以访问此窗格
  • 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);
            }
        }
    }
    

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

    谢谢您的回答,但令牌已与其他一些窗口一起存储在数据库中,我认为可能会有更面向对象的解决方案。我会在另一个视图中从数据库中检索它,但我需要用户的凭据来知道要检索哪一个。感谢您的回答,但是令牌已经与其他一些令牌一起存储在数据库中,我认为可能有一个更面向对象的解决方案。我想从另一个视图的数据库中检索它,但我需要用户的凭据来知道要检索哪个。谢谢您的回答。我考虑过这样做。问题是,我需要在我的应用程序的不同面板中提供这些信息。我不想在需要访问对象的每个JPanel的构造函数中传递
    令牌
    对象的实例。谢谢您的回答。我考虑过这样做。问题是,我需要在我的应用程序的不同面板中提供这些信息。我不想在需要访问对象的每个JPanel的构造函数中传递
    令牌
    对象的实例。感谢您的建议!这就是我要找的,太好了。谢谢你的建议!这就是我要找的