对于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(); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)