AnsweredAssumed Answered

HOW TO: Implement Model View Controller in an ArcMap Tool Add-in - Java

Question asked by ldonahue on Feb 6, 2013
This sample was intended to show how to implement the MVC pattern in an ArcMap add-in.

If you like it, ok.  If not, ok.  Feel free to comment or nitpick it.

package com.domain.somename;  import java.awt.event.MouseEvent; import java.io.IOException;  import com.esri.arcgis.addins.desktop.Tool; import com.esri.arcgis.arcmap.Application; import com.esri.arcgis.arcmapui.IMxDocument; import com.esri.arcgis.carto.Map; import com.esri.arcgis.framework.IApplication; import com.esri.arcgis.interop.AutomationException;  public class Tool1 extends Tool {      /**      * Called when the tool is activated by clicking it.      */     @Override     public void activate() throws IOException, AutomationException {         // Not doing anything in here...     }      /**      * Initializes this button with the ArcGIS application.       */     @Override     public void init(IApplication app) throws IOException, AutomationException {         super.init(app);                  try {             mxDocument = (IMxDocument)app.getDocument();                          try {                 left = ((Application) app).getLeft() + 100;                 top = ((Application) app).getTop() + 200;             } catch (IOException e2) {                 e2.printStackTrace();             }                      } catch (AutomationException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }     }      /**      * Called when a mouse button is pressed while the tool is active.       */     @Override     public void mousePressed(MouseEvent mouseEvent) {         super.mousePressed(mouseEvent);                  // get an instance of our view         if(t1View == null){             t1View = Tool1View.getInstance();             t1View.addWindowListener(t1View);         }                  // create an instance of the model         if(t1Model == null){             t1Model = new Tool1Model(t1View, mouseEvent);             t1Model.setMxDoc(mxDocument);         }                  // create an instance of the controller         if(t1Controller == null){             try {                 t1Controller = new Tool1Controller(t1View, t1Model, (Map)mxDocument.getActiveView().getFocusMap());             } catch (AutomationException e) {                 e.printStackTrace();             } catch (IOException e) {                 e.printStackTrace();             }         }                  // display the View         t1View.setBounds(left, top, 270, 170);         t1View.toFront();         t1View.setVisible(true);              }          public IApplication getApp() {         return app;     }      public IMxDocument getMxDocument() {         return mxDocument;     }          private IApplication app;     private IMxDocument mxDocument;          private Tool1View t1View = null;     private Tool1Model t1Model = null;     private Tool1Controller t1Controller = null;          private int left;     private int top;  }


package com.domain.somename;  import java.awt.event.MouseEvent; import java.io.IOException;  import javax.swing.JOptionPane;  import com.esri.arcgis.arcmapui.IMxDocument; import com.esri.arcgis.interop.AutomationException;  public class Tool1Model {      public Tool1Model(Tool1View view, MouseEvent me){         m_tool1View = view;         m_me = me;     }          public void handleSubmit(){         int xcoord = m_me.getX();         int ycoord = m_me.getY();                  String message = m_tool1View.getTxtDescription().getText() + " was placed at screen coordinates: " + xcoord + "," + ycoord;                  JOptionPane.showMessageDialog(m_tool1View, message);         JOptionPane.showMessageDialog(m_tool1View, "... But not really, this was just a lame example...");                  try {             mxDoc.getActiveView().refresh();         } catch (AutomationException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }     }          /**      * @return the mxDoc      */     public IMxDocument getMxDoc() {         return mxDoc;     }      /**      * @param mxDoc the mxDoc to set      */     public void setMxDoc(IMxDocument mxDoc) {         this.mxDoc = mxDoc;     }      private Tool1View m_tool1View = null;     private MouseEvent m_me;          private IMxDocument mxDoc; }


package com.domain.somename;  import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener;  import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import javax.swing.border.TitledBorder; import javax.swing.JTextField; import javax.swing.JButton;  public class Tool1View extends JFrame implements WindowListener{      private static final long serialVersionUID = -697599487543207794L;     private static Tool1View instance = null;     private JPanel contentPane;     private JTextField txtDescription;     private JButton btnSubmit;      /**      * Make our view a singleton because there is no reason to have multiple instances of this view      */     public static Tool1View getInstance(){         if(instance == null){             instance = new Tool1View();         }         return instance;     }          public Tool1View() {         constructGUI();     }          /**      * Construct the GUI for Tool1View      */     private void constructGUI(){                  setTitle("Tool1 GUI");         contentPane = new JPanel();         setContentPane(contentPane);         contentPane.setLayout(null);                  JPanel panel = new JPanel();         panel.setBorder(new TitledBorder(null, "Enter a description for this location", TitledBorder.LEADING, TitledBorder.TOP, null, null));         panel.setBounds(10, 11, 234, 79);         contentPane.add(panel);         panel.setLayout(null);                  JLabel label = new JLabel("Description:");         label.setBounds(10, 35, 70, 14);         panel.add(label);                  txtDescription = new JTextField();         txtDescription.setColumns(10);         txtDescription.setBounds(90, 32, 125, 20);         panel.add(txtDescription);                  btnSubmit = new JButton("Submit");         btnSubmit.setBounds(155, 96, 89, 23);         contentPane.add(btnSubmit);     }      public JTextField getTxtDescription() {         return txtDescription;     }      public JButton getBtnSubmit() {         return btnSubmit;     }          /**      * Assign an ActionListener to this button from the Tool1Controller.      */     void addSubmitListener(ActionListener sal){         btnSubmit.addActionListener(sal);     }          /**      * Override the windowClosing event.      */     @Override     public void windowClosing(WindowEvent e) {         instance.setDefaultCloseOperation(DISPOSE_ON_CLOSE);     }     @Override     public void windowOpened(WindowEvent e) {     }     @Override     public void windowClosed(WindowEvent e) {     }     @Override     public void windowIconified(WindowEvent e) {     }     @Override     public void windowDeiconified(WindowEvent e) {     }     @Override     public void windowActivated(WindowEvent e) {     }     @Override     public void windowDeactivated(WindowEvent e) {     } }


package com.domain.somename;  import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException;  import com.esri.arcgis.carto.Map; import com.esri.arcgis.interop.AutomationException;  public class Tool1Controller {      public Tool1Controller(Tool1View view, Tool1Model model, Map map){         c_tool1View = view;         c_tool1Model = model;         c_map = map;                  c_tool1View.addSubmitListener(new AddSubmitListener());     }          /**      * Inner class used as the ActionListener for the btnSubmit in Tool1View.      */     private class AddSubmitListener implements ActionListener {          @Override         public void actionPerformed(ActionEvent e) {             // call the model to handle the button event...             c_tool1Model.handleSubmit();                          // you can let the controller handle map refresh, rather than in the model...             try {                 c_map.refresh();             } catch (AutomationException e1) {                 e1.printStackTrace();             } catch (IOException e1) {                 e1.printStackTrace();             }         }      }          private Tool1View c_tool1View;     private Tool1Model c_tool1Model;     private Map c_map; }

Outcomes