J'écris actuellement un modèle Java et en quelque sorte, je ne sais pas où appartiennent les ActionListeners si je voulais suivre proprement le modèle MVC.
L'exemple est basé sur Swing, mais il ne s'agit pas du framework mais plutôt du concept de base de MVC en Java, utilisant n'importe quel framework pour créer une interface graphique.
J'ai commencé avec une application absolument simple contenant un JFrame et un JButton (pour disposer le cadre donc fermer l'application). Le code qui suit ce post. Rien de vraiment spécial, juste pour clarifier ce dont nous parlons. Je n'ai pas encore commencé avec le modèle car cette question me dérangeait trop.
Il y a déjà eu plus d'une question similaire, comme celles-ci:
modèle MVC avec de nombreux ActionListeners
Java swing - Où doit aller l'ActionListener?
Mais aucun d'eux n'était vraiment satisfaisant car j'aimerais savoir deux choses:
J'espère que ce n'est pas trop général ou vague que je demande ici, mais ça me fait réfléchir depuis un moment maintenant. J'ai toujours utilisé une sorte de à ma façon, laissant l'ActionHandler connaître le contrôleur , mais cela ne semble pas correct, donc j'aimerais enfin savoir comment cela se fait correctement.
Sincères amitiés,
JaySon
Manette:
package controller;
import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import view.MainView;
public class MainController
{
MainView mainView = new MainView();
public MainController()
{
this.initViewActionListeners();
}
private void initViewActionListeners()
{
mainView.initButtons(new CloseListener());
}
public class CloseListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
mainView.dispose();
}
}
}
Vue:
package view;
import Java.awt.Dimension;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainView extends JFrame
{
JButton button_close = new JButton();
JPanel panel_mainPanel = new JPanel();
private static final long serialVersionUID = 5791734712409634055L;
public MainView()
{
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setSize(500, 500);
this.add(panel_mainPanel);
setVisible(true);
}
public void initButtons(ActionListener actionListener)
{
this.button_close = new JButton("Close");
this.button_close.setSize(new Dimension(100, 20));
this.button_close.addActionListener(actionListener);
this.panel_mainPanel.add(button_close);
}
}
C'est une question très difficile à répondre avec Swing, car Swing n'est pas une implémentation MVC pure, la vue et le contrôleur sont mélangés.
Techniquement, un modèle et un contrôleur devraient pouvoir interagir et le contrôleur et la vue devraient pouvoir interagir, mais la vue et le modèle ne devraient jamais interagir, ce qui n'est clairement pas le fonctionnement de Swing, mais c'est un autre débat ...
Un autre problème est que vous ne voulez vraiment pas exposer les composants de l'interface utilisateur à quiconque, le contrôleur ne devrait pas se soucier de la façon dont certaines actions se produisent, seulement qu'il le peut.
Cela suggère que les ActionListener
attachés à vos contrôles d'interface utilisateur devraient être conservés par la vue. La vue devrait alors alerter le contrôleur qu'une sorte d'action s'est produite. Pour cela, vous pouvez utiliser un autre ActionListener
, géré par la vue, auquel le contrôleur est abonné.
Mieux encore, j'aurais un écouteur de vue dédié, qui décrit les actions que cette vue pourrait produire, par exemple ...
public interface MainViewListener {
public void didPerformClose(MainView mainView);
}
Le contrôleur s'abonne alors à la vue via cet écouteur et la vue appelle didPerformClose
lorsque (dans ce cas) le bouton de fermeture est enfoncé.
Même dans cet exemple, je serais tenté de créer une interface "vue principale", qui décrit les propriétés (setters et getters) et les actions (listeners/callbacks) que toute implémentation est garantie de fournir, alors vous ne vous souciez pas de la façon dont ces des actions se produisent, seulement que lorsqu'elles le font, vous devez faire quelque chose ...
À chaque niveau que vous souhaitez vous poser, serait-il facile de changer un élément (changer le modèle ou le contrôleur ou la vue) pour une autre instance? Si vous devez découpler le code, vous avez un problème. Communiquez via des interfaces et essayez de réduire la quantité de couplage entre les couches et la quantité que chaque couche connaît des autres au point où elles maintiennent simplement des contrats
mis à jour ...
Prenons cela pour un exemple ...
Il y a en fait deux vues (actualisation de la boîte de dialogue réelle), il y a la vue des informations d'identification et la vue de connexion, oui, elles sont différentes comme vous le verrez.
La vue des informations d'identification est chargée de collecter les détails à authentifier, le nom d'utilisateur et le mot de passe. Il fournira des informations au contrôleur pour lui faire savoir quand ces informations d'identification ont été modifiées, car le contrôleur peut vouloir prendre des mesures, comme activer le bouton "connexion" ...
La vue voudra également savoir quand l'authentification est sur le point d'avoir lieu, car elle voudra désactiver ses champs, de sorte que l'utilisateur ne peut pas mettre à jour la vue pendant que l'authentification a lieu, également, il devra savoir quand l'authentification échoue ou réussit, car il devra prendre des mesures pour faire face à ces éventualités.
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);
}
Le CredentialsPane
est l'implémentation physique d'un CredentialsView
, il implémente le contrat, mais gère son propre état interne. La façon dont le contrat est géré est sans importance pour le responsable du traitement, il ne se soucie que du contrat qui a été respecté ...
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;
}
}
Le LoginView
est responsable de la gestion d'un CredentialsView
, mais aussi de la notification du LoginViewController
quand l'authentification doit avoir lieu ou si le processus a été annulé par l'utilisateur, par certains moyens. .
De même, le LoginViewController
indiquera à la vue quand l'authentification est sur le point d'avoir lieu et si l'authentification a échoué ou a réussi.
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);
}
Le LoginPane
est un peu spécial, il agit comme la vue pour le LoginViewController
, mais il agit également comme le contrôleur pour le CredentialsView
. C'est important, car rien ne dit qu'une vue ne peut pas être un contrôleur, mais je serais prudent sur la façon dont vous implémentez de telles choses, car il n'est pas toujours logique de le faire de cette façon, mais parce que les deux vues sont travailler ensemble pour recueillir des informations et gérer les événements, il était logique dans ce cas.
Étant donné que le LoginPane
devra changer son propre état en fonction des modifications apportées au CredentialsView
, il est logique d'autoriser le LoginPane
à agir comme contrôleur dans ce cas, sinon , vous devez fournir plus de méthodes qui contrôlent cet état des boutons, mais cela commence à faire fondre la logique de l'interface utilisateur sur le contrôleur ...
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();
}
public interface CredentialsView {
public String getUserName();
public char[] getPassword();
public void willAuthenticate();
public void authenticationFailed();
public void authenticationSucceeded();
public CredentialsViewController getCredentialsViewController();
}
public interface CredentialsViewController {
public void credientialsDidChange(CredentialsView view);
}
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);
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
LoginViewController controller = new LoginViewController() {
@Override
public void authenticationWasRequested(LoginView view) {
view.willAuthenticate();
LoginAuthenticator authenticator = new LoginAuthenticator(view);
authenticator.authenticate();
}
@Override
public void loginWasCancelled(LoginView view) {
view.dismissView();
}
};
if (LoginPane.showLoginDialog(controller)) {
System.out.println("You Shell pass");
} else {
System.out.println("You Shell not pass");
}
System.exit(0);
}
});
}
public class LoginAuthenticator {
private LoginView view;
public LoginAuthenticator(LoginView view) {
this.view = view;
}
public void authenticate() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (AUTHENTICATION_Oracle.nextBoolean()) {
view.authenticationSucceeded();
view.dismissView();
} else {
view.authenticationFailed();
}
}
});
}
});
t.start();
}
}
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();
}
}
public static 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;
}
}
}
Ils sont associés au contrôle, mais ils ne doivent pas nécessairement faire directement partie du contrôle. Par exemple, veuillez consulter le code affiché ci-dessous que je préparais pour une autre question, une sur les classes internes anonymes et le couplage, ici je donne à tous mes boutons des actions internes anonymes (qui sont des ActionListeners, bien sûr), puis j'utilise les actions pour changer l'état de l'interface graphique. Tous les auditeurs de l'interface graphique (le contrôle) seront informés de ce changement et pourront alors agir en conséquence.
import Java.awt.*;
import Java.awt.event.*; Java.beans.PropertyChangeEvent;
import Java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class AnonymousInnerEg2 {
private static void createAndShowUI() {
GuiModel2 model = new GuiModel2();
GuiPanel2 guiPanel = new GuiPanel2();
GuiControl2 guiControl = new GuiControl2();
guiControl.setGuiPanel(guiPanel);
guiControl.setGuiModel(model);
try {
guiControl.init();
} catch (GuiException2 e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("AnonymousInnerEg");
frame.getContentPane().add(guiPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
Java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
enum GuiState {
BASE("Base"), START("Start"), END("End");
private String name;
private GuiState(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class GuiModel2 {
public static final String STATE = "state";
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
private GuiState state = GuiState.BASE;
public GuiState getState() {
return state;
}
public void setState(GuiState state) {
GuiState oldValue = this.state;
GuiState newValue = state;
this.state = state;
support.firePropertyChange(STATE, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener l) {
support.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
support.removePropertyChangeListener(l);
}
}
@SuppressWarnings("serial")
class GuiPanel2 extends JPanel {
public static final String STATE = "state";
private String state = GuiState.BASE.getName();
private JLabel stateField = new JLabel("", SwingConstants.CENTER);
public GuiPanel2() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
for (final GuiState guiState : GuiState.values()) {
btnPanel.add(new JButton(new AbstractAction(guiState.getName()) {
{
int mnemonic = (int) getValue(NAME).toString().charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
String name = getValue(NAME).toString();
setState(name);
}
}));
}
setLayout(new BorderLayout());
add(stateField, BorderLayout.PAGE_START);
add(btnPanel, BorderLayout.CENTER);
}
public String getState() {
return state;
}
public void setState(String state) {
String oldValue = this.state;
String newValue = state;
this.state = state;
firePropertyChange(STATE, oldValue, newValue);
}
public void setStateField(String name) {
stateField.setText(name);
}
}
class GuiControl2 {
private GuiPanel2 guiPanel;
private GuiModel2 model;
private boolean allOK = false;
public void setGuiPanel(GuiPanel2 guiPanel) {
this.guiPanel = guiPanel;
guiPanel.addPropertyChangeListener(GuiPanel2.STATE,
new GuiPanelStateListener());
}
public void init() throws GuiException2 {
if (model == null) {
throw new GuiException2("Model is null");
}
if (guiPanel == null) {
throw new GuiException2("GuiPanel is null");
}
allOK = true;
guiPanel.setStateField(model.getState().getName());
}
public void setGuiModel(GuiModel2 model) {
this.model = model;
model.addPropertyChangeListener(new ModelListener());
}
private class GuiPanelStateListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!allOK) {
return;
}
if (GuiPanel2.STATE.equals(evt.getPropertyName())) {
String text = guiPanel.getState();
model.setState(GuiState.valueOf(text.toUpperCase()));
}
}
}
private class ModelListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!allOK) {
return;
}
if (GuiModel2.STATE.equals(evt.getPropertyName())) {
GuiState state = (GuiState) evt.getNewValue();
guiPanel.setStateField(state.getName());
}
}
}
}
@SuppressWarnings("serial")
class GuiException2 extends Exception {
public GuiException2() {
super();
}
public GuiException2(String message) {
super(message);
}
}
Remarque cependant: je ne suis pas un codeur professionnel ou même un codeur formé à l'université, veuillez donc ne considérer cela que comme mon opinion.
Je suis en train d'apprendre Java à l'école. Les professeurs nous ont dit que les auditeurs doivent toujours être déclarés à l'intérieur de la classe Controller. La façon dont je le fais, c'est de implémenter une méthode, par exemple listeners (). À l'intérieur se trouvent toutes les déclarations des auditeurs utilisant des classes anonymes. C'est la façon dont mes professeurs veulent que cela voit, mais franchement, je ne suis pas vraiment sûr d'avoir tout compris .