Java and GUI - Where do ActionListeners belong according to MVC pattern?

后端 未结 3 1048
傲寒
傲寒 2020-11-22 13:28

I\'m currently writing a template Java application and somehow, I\'m not sure about where the ActionListeners belong if I wanted to cleanly follow the MVC pattern.

T

3条回答
  •  没有蜡笔的小新
    2020-11-22 14:06

    They are associated with the control, but they don't have to be a direct part of the control. For instance, please see the code posted below that I was preparing for another question, one on anonymous inner classes and coupling, here I give all my buttons anonymous inner Actions (which are ActionListeners, of course), and then use the Actions to change the GUI state. Any listeners to the GUI (the control) will be notified of this change, and can then act accordingly.

    import java.awt.*;
    import java.awt.event.*; 
    import 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);
       }
    }
    

    Note in warning though: I am not a professional coder or even a university trained coder, so please take this as just my opinion only.

提交回复
热议问题