Java和GUI-根据MVC模式,ActionListeners在哪里?

Java和GUI-根据MVC模式,ActionListeners在哪里?,第1张

Java和GUI-根据MVC模式,ActionListeners在哪里?

对于Swing来说,这是一个很难回答的问题,因为Swing不是纯MVC实现,因此视图控制器是混合的。

从技术上讲,模型和控制器应该可以交互,而控制器和视图应该可以交互,但是视图和模型永远不能交互,这显然不是Swing的工作原理,但这是另一个争论……

另一个问题是,你真的不想将UI组件公开给任何人,控制器不应该关心某些 *** 作是如何发生的,只有它们可以发生。

这建议

ActionListener
附加到UI控件的s应该由视图维护。然后,视图应警告控制器已发生某种动作。为此,你可以使用
ActionListener
控制器订阅的视图(由视图管理)。

更好的是,我将拥有一个专用的视图侦听器,该监听器描述了该视图可能产生的动作,例如…

public interface MainViewListener {    public void didPerformClose(MainView mainView);}

然后,控制器将通过此侦听器订阅该视图,并且该视图将didPerformClose在(在这种情况下)按下关闭按钮时调用。

即使在此示例中,我也很想创建一个“主视图”界面,该界面描述了任何实现都可以保证提供的属性(设置程序和获取器)和 *** 作(侦听器/回调),那么你无需关心这些会发生一些动作,只有当他们这样做时,你才有望做某事…

在每个级别,你都想问自己,为另一个实例更改任何元素(更改模型,控制器或视图)有多容易?如果发现自己必须解耦代码,那么你就遇到了问题。通过接口进行通信,并尝试减少各层之间的耦合量以及每一层对其他层的了解,以至于它们仅维护合同即可

更新…

让我们以这个为例…

实际上有两个视图(为实际对话框打折),有凭据视图和登录视图,是的,你将看到它们是不同的。

CredentialsView

凭证视图负责收集要验证的详细信息,用户名和密码。它将向控制器提供信息,以便在更改那些凭据时通知它,因为控制器可能要采取一些措施,例如启用“登录”按钮…

该视图还希望知道何时进行认证,因为它将禁用其字段,因此用户在进行认证时无法更新视图,同样,它需要知道何时进行认证失败或成功,因为它将需要针对这些突发事件采取行动。

public interface CredentialsView {    public String getUserName();    public char[] getPassword();    public void willAuthenticate();    public void authenticationFailed();    public void authenticationSucceeded();    public void setCredentialsViewController(CredentialsViewController listener);}public interface CredentialsViewController {    public void credientialsDidChange(CredentialsView view);}

CredentialsPane

该CredentialsPane是一个物理实现CredentialsView,它实现了合同,但管理它自己的内部状态。合同的管理方式与控制者无关,它只关心合同是否得到维护…

public class CredentialsPane extends JPanel implements CredentialsView {    private CredentialsViewController controller;    private JTextField userNameField;    private JPasswordField passwordField;    public CredentialsPane(CredentialsViewController controller) {        setCredentialsViewController(controller);        setLayout(new GridBagLayout());        userNameField = new JTextField(20);        passwordField = new JPasswordField(20);        GridBagConstraints gbc = new GridBagConstraints();        gbc.gridx = 0;        gbc.gridy = 0;        gbc.insets = new Insets(2, 2, 2, 2);        gbc.anchor = GridBagConstraints.EAST;        add(new JLabel("Username: "), gbc);        gbc.gridy++;        add(new JLabel("Password: "), gbc);        gbc.gridx = 1;        gbc.gridy = 0;        gbc.anchor = GridBagConstraints.WEST;        gbc.fill = GridBagConstraints.HORIZONTAL;        add(userNameField, gbc);        gbc.gridy++;        add(passwordField, gbc);        documentListener listener = new documentListener() { @Override public void insertUpdate(documentEvent e) {     getCredentialsViewController().credientialsDidChange(CredentialsPane.this); } @Override public void removeUpdate(documentEvent e) {     getCredentialsViewController().credientialsDidChange(CredentialsPane.this); } @Override public void changedUpdate(documentEvent e) {     getCredentialsViewController().credientialsDidChange(CredentialsPane.this); }        };        userNameField.getdocument().adddocumentListener(listener);        passwordField.getdocument().adddocumentListener(listener);    }    @Override    public CredentialsViewController getCredentialsViewController() {        return controller;    }    @Override    public String getUserName() {        return userNameField.getText();    }    @Override    public char[] getPassword() {        return passwordField.getPassword();    }    @Override    public void willAuthenticate() {        userNameField.setEnabled(false);        passwordField.setEnabled(false);    }    @Override    public void authenticationFailed() {        userNameField.setEnabled(true);        passwordField.setEnabled(true);        userNameField.requestFocusInWindow();        userNameField.selectAll();        JOptionPane.showMessageDialog(this, "Authentication has failed", "Error", JOptionPane.ERROR_MESSAGE);    }    @Override    public void authenticationSucceeded() {        // Really don't care, but you might want to stop animation, for example...    }    public void setCredentialsViewController(CredentialsViewController controller){        this.controller = controller;    }}

登录查看

LoginView
负责管理
CredentialsView
,同时也为通知
LoginViewController
时应该存放着认证,或者整个过程由用户取消,通过一些手段…

同样,

LoginViewController
它将告诉视图何时进行认证以及认证失败还是成功。

public interface LoginView {    public CredentialsView getCredentialsView();    public void willAuthenticate();    public void authenticationFailed();    public void authenticationSucceeded();    public void dismissView();    public LoginViewController getLoginViewController();}public interface LoginViewController {    public void authenticationWasRequested(LoginView view);    public void loginWasCancelled(LoginView view);}

登录窗格

LoginPane
特殊之处在于,它充当的视图
LoginViewController
,但也充当的控制器
CredentialsView
。这很重要,因为没有任何说法说视图不能成为控制器,但是我会谨慎考虑如何实现这样的事情,因为这样做并非总是有意义,但是因为这两个视图是一起收集信息和管理事件,在这种情况下很有意义。

由于

LoginPane
将需要根据的更改来更改自己的状态
CredentialsView
,因此
LoginPane
在这种情况下允许充当控制器是有意义的,否则,你需要提供更多方法来控制按钮的状态,但是这开始将UI逻辑流到控制器…

public static class LoginPane extends JPanel implements LoginView, CredentialsViewController {    private LoginViewController controller;    private CredentialsPane credientialsView;    private JButton btnAuthenticate;    private JButton btnCancel;    private boolean wasAuthenticated;    public LoginPane(LoginViewController controller) {        setLoginViewController(controller);        setLayout(new BorderLayout());        setBorder(new EmptyBorder(8, 8, 8, 8));        btnAuthenticate = new JButton("Login");        btnCancel = new JButton("Cancel");        JPanel buttons = new JPanel();        buttons.add(btnAuthenticate);        buttons.add(btnCancel);        add(buttons, BorderLayout.SOUTH);        credientialsView = new CredentialsPane(this);        add(credientialsView);        btnAuthenticate.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) {     getLoginViewController().authenticationWasRequested(LoginPane.this); }        });        btnCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) {     getLoginViewController().loginWasCancelled(LoginPane.this);     // I did think about calling dispose here,     // but's not really the the job of the cancel button to decide what should happen here... }        });        validateCreientials();    }    public static boolean showLoginDialog(LoginViewController controller) {        final LoginPane pane = new LoginPane(controller);        JDialog dialog = new JDialog();        dialog.setTitle("Login");        dialog.setModal(true);        dialog.add(pane);        dialog.pack();        dialog.setLocationRelativeTo(null);        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);        dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) {     pane.getLoginViewController().loginWasCancelled(pane); }        });        dialog.setVisible(true);        return pane.wasAuthenticated();    }    public boolean wasAuthenticated() {        return wasAuthenticated;    }    public void validateCreientials() {        CredentialsView view = getCredentialsView();        String userName = view.getUserName();        char[] password = view.getPassword();        if ((userName != null && userName.trim().length() > 0) && (password != null && password.length > 0)) { btnAuthenticate.setEnabled(true);        } else { btnAuthenticate.setEnabled(false);        }    }    @Override    public void dismissView() {        SwingUtilities.windowForComponent(this).dispose();    }    @Override    public CredentialsView getCredentialsView() {        return credientialsView;    }    @Override    public void willAuthenticate() {        getCredentialsView().willAuthenticate();        btnAuthenticate.setEnabled(false);    }    @Override    public void authenticationFailed() {        getCredentialsView().authenticationFailed();        validateCreientials();        wasAuthenticated = false;    }    @Override    public void authenticationSucceeded() {        getCredentialsView().authenticationSucceeded();        validateCreientials();        wasAuthenticated = true;    }    public LoginViewController getLoginViewController() {        return controller;    }    public void setLoginViewController(LoginViewController controller) {        this.controller = controller;    }    @Override    public void credientialsDidChange(CredentialsView view) {        validateCreientials();    }}

工作实例

import java.awt.BorderLayout;import java.awt.EventQueue;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.Insets;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.util.Random;import java.util.logging.Level;import java.util.logging.Logger;import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.Jframe;import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JPasswordField;import javax.swing.JTextField;import javax.swing.SwingUtilities;import javax.swing.UIManager;import javax.swing.UnsupportedLookAndFeelException;import javax.swing.border.EmptyBorder;import javax.swing.event.documentEvent;import javax.swing.event.documentListener;import sun.net.www.protocol.http.HttpURLConnection;public class Test {    protected static final Random AUTHENTICATION_ORACLE = new Random();    public static void main(String[] args) {        new Test();    }


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5014203.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)

保存