【问题标题】:How to update and view current window in MVC如何在 MVC 中更新和查看当前窗口
【发布时间】:2021-11-24 06:03:56
【问题描述】:

我知道这里的许多帖子都涉及到这个问题。 但是,我仍然不清楚,所以我想详细询问您我的问题。

我必须使用 Swing 和 MVC 模型开发一个 java 应用程序。
应用主要分为两部分:

  • 登录部分
  • 问卷部分(登录后显示问卷)

所以按照 MVC 模型,我将我的代码分为 3 个包,其中包含以下类:

Model
        LoginModel
        QuestionModel
View
        LoginView
        QuestionView
Controller
        LoginController
        QuestionController

开发这些类后,我不知道如何设置程序当前正在处理的窗口(登录、问卷调查或其他未来实现)。
所以我考虑实现其他 3 个使用观察者模式的类:

MainModel - Observable
MainView
MainController - Observer

但现在我不确定如何更改当前窗口。

例如登录成功时,窗口必须从LOGIN变为QUESTION,所以“MainModel.window = Window.QUESTION”并发送给View。
是否应该通过使用 MainModel 扩展 LoginModel 将其添加到 LoginModel.login() 中?
或者我该怎么做?

我的代码:

public class main {
    public static void main(String[] args) {
        MainView view = new MainView();
        MainModel model = new MainModel();
        MainController controller = new MainController(view, model);
    }
}

public class MainView {
    private JFrame window;

    public MainView() {
        window = new JFrame();
        window.setLayout(new CardLayout(0, 0));

        LoginView login = new LoginView();      // init window at opening
        QuestionView question = new QuestionView();

        window.add(login);
        window.add(question);

        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
    }
        
    public void update(Window window) {
        // ??
    }
}

public class MainModel {
    private List<Observer> observers = new ArrayList<>();
    private Window window;
    
    public MainModel() {
        window = Window.LOGIN;  // init window at opening
    }
    
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    
    public void setWindow(Window newWindow) {
        newWindow = window;
                
        for (Observer o : observers)
            o.update(newWindow);            
    }
}

public class MainController implements Observer {
    private MainView view;
    private MainModel model;
    
    public MainController(MainView view, MainModel model) {
        this.view = view;
        this.model = model;
        
        this.model.addObserver(this);
    }
    
    @Override
    public void update(Window window) {
        this.view.update(window);
    }
}

public class LoginView extends JPanel {
    private JButton btnLogin;
    // ... other attributes
    
    public LoginView() {        
        btnLogin = new JButton("Login");

        new LoginController(this);
    }
        
    public JButton getBtnLogin() {
        return btnLogin;
    }
    
    public void ShowResult(boolean bResult) {
        // print result with JOptionPane.showMessageDialog
    }   
}

public class LoginController {
    private LoginView view;
    
    public LoginController(LoginView view) {
        this.view = view;
        setActionListener();
    }
    
    public void setActionListener() {
        ActionListener loginButton;
        loginButton = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                LoginModel model = new LoginModel();
                boolean bResult = model.login(view.getUserNameField(), view.getPasswordField());
                
                view.ShowResult(bResult);
            }
        };
        
        view.getBtnLogin().addActionListener(loginButton);
    }
}

public class LoginModel {
    // ... attributes etc
    
    public boolean login(String username, String password) {
        boolean bResult;
        
        // ...                  Some operation etc (useless for this example)
        bResult = true;     //  Simulation login successful
        
        if (bResult)
            // ? Change window model to Window.QUESTION.
            // But how?
            // LoginModel extends MainModel? To call "super.setWindow(Window.QUESTION)?
        
        return bResult;
    }
}

// My Observer class
public interface Observer {
    public void update(Window window);
}

// My Window class
public enum Window {
    LOGIN,
    QUESTION,
}

// Questionnaire classes code is very similar to the Login code
public class QuestionView extends JPanel {
    private JButton btn;
    // ...
    new QuestionController(this);
    // ...
}

public class QuestionController {
    private QuestionView view;
    // ...
    setActionListener();
    // ...
}

所以总而言之,使用这种方法是否正确?或者我还能如何更好地查看/更新当前窗口?

【问题讨论】:

  • 看看这个Stack Overflow answer。这是一个学生测验,而不是问卷,但它应该足够接近,以便为您提供一个很好的模型来遵循。 GUI 的文本是西班牙语。

标签: java swing model-view-controller observer-pattern


【解决方案1】:

在 Swing 中,MVC 模式如下所示:

  • 视图从模型中读取
  • 视图可能不会更新模型
  • 控制器更新模型和视图

MVC 名称意味着您首先创建模型,然后是视图,然后是控制器。

通常没有一个控制器可以“统辖”它们。每个侦听器负责自己的模型和视图部分。

您通常有一个应用程序模型。一个应用程序模型由一个或多个普通的 Java getter/setter 类组成。在您的情况下,它看起来像一个 Person 类和一个 Questionaire 类。您可能还会有一个 Question 类,用于保存一个问题、几个可能的答案和选择的答案。您可能还有其他普通的 Java getter/setter 类,我现在没有考虑。

您将拥有一个 JFrame、一个 JPanel 来保存问题和可能的答案,以及一个用于登录名和密码的 JDialog。对于不同类型的答案(不是不同的问题),您可能需要多个 JPanel,因此您可能需要一个带有 CardLayout 的主 JPanel。

您的控制器将是登录 JButton 的 ActionListener,以及“我已完成回答此问题”的 JButton。您可能还有其他我现在没有考虑的听众。

【讨论】:

  • 因此使用“MainModel、MainView 等”是错误的,因为它们没有意义(它们只是存储当前窗口)。关于模型中的应用程序模型,我设置了 setter/getter 类,并且 View 填充了通过控制器返回的模型数据。但是,如果每个控制器都负责自己的视图/模型部分,我如何隐藏一个视图并显示另一个视图?例如登录成功后,LoginController 可以向 LoginView 发送一个方法来隐藏它。但同时我如何显示 QuestionView?由于 Login 和 Questionaire 没有任何共同之处,而且他们彼此不认识。
  • @Anyone97:正如我在回答中提到的,您使用 JDialog 进行登录,使用带有 CardLayout 的主 JPanel 用于 Questionaire JPanel。 How can I implement a login screen before showing a JFrame?How to Use CardLayout.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 2021-07-21
相关资源
最近更新 更多