ArcGIS Engine Controls Some Examples


This document was published with and applies to ArcGIS 9.3.

Building applications with visual JavaBeans

This scenario is for developers who want to build and deploy an application using visual Java components. The process of building and deploying an application using the visual beans available in the ArcGIS Engine software development kit (SDK) for the Java platform is outlined. The completed application can be found in the samples installation location. The sample is installed as part of the ArcGIS developer samples.
 
On the Windows platform, the sample is in the following location:
 
On the Solaris and Linux platforms, the sample is in the following location:

Project description

This scenario demonstrates the required steps to create a application for viewing preauthored ESRI map documents (MXDs). The scenario covers the following areas:

Concepts

The ArcGIS Engine SDK for the Java platform provides reusable visual Java components. This developer scenario shows how these components can be embedded in a Java user interface to build a map viewer application.
 
The visual beans that conform to the JavaBeans component architecture, allowing them to be used as drag and drop components for designing Java GUIs in JavaBeans compatible integrated development environments (IDEs). Each component has specific properties and methods and is capable of firing events. By assembling the ArcGIS Engine visual components in a Java application and wiring up with each other and with nonvisual ArcObjects components, custom geographic information system (GIS) applications can be rapidly built and deployed on supported ArcGIS Engine platforms.

Design

In this application, the MapBean, PageLayoutBean, TOCBean, and ToolbarBean components are placed inside a javax.swing.JFrame container and interact with each other and with other ArcGIS Engine objects to provide GIS viewing capability. The MapBean serves as an overview map in the corner of the application, while the PageLayoutBean is the visual centerpiece.
 
The scenario starts with building a GUI using the BorderLayout manager to position the components. Once the components are added to the JFrame container, they are connected to each other using the setBuddy() method. At this stage, the application is ready to function as a simple map viewer.
 
The scenario then extends the functionality of the simple map viewer by building custom tools and demonstrating event handling. To achieve this, it explores the application programming interface (API) of the visual and other nonvisual ArcGIS Engine components.
 
While the components can be used as drag and drop JavaBeans in a Java IDE supporting visual GUI design, in this scenario, the components will be programmatically placed to give a better understanding of the code.

Requirements

To successfully follow this scenario, you need the following (for information regarding the requirements for deployment, see the Deployment section in this topic):
 
To build the application, the following visual components from ArcGIS Engine will be used:
 
In addition, objects from the following packages will be used:
 
To reference the previous packages, arcobjects.jar must be added to your classpath. The arcobjects.jar file is located at %ARCGISHOME%\ArcGIS\java\lib. 

Implementation

To implement the scenario, follow the steps in this section. While the scenario specifically uses the Gulf of St. Lawrence map document installed with the samples, you can use your own map document. The implementation provides you with all the code you need to successfully complete the scenario. It doesn't provide step-by-step instructions to develop applications in Java, as it assumes you already have a working knowledge of the development environment.

Setting up the development environment

To compile and run applications using ArcGIS Engine, set up your development environment. For more information, see Post installation.

Building a GUI using the visual components

  1. Create a MapViewerFrame.java file. The MapViewerFrame class provides the GUI and functionality of the map viewer application. Implement this class as a subclass of javax.swing.JFrame. See the following code example:

 

[Java]
// MapViewerFrame.java.
import java.io.IOException;
import javax.swing.JFrame;
public class MapViewerFrame extends JFrame{
    // Constructor.
    public MapViewerFrame(){
        setTitle("MapViewer");
    }
    public void buildAndShow()throws IOException{
        this.setVisible(true);
    }
} // End MapViewerFrame class.
  1. Create a MapViewer.java file. This file provides the main method, which constructs the MapViewerFrame, gives it an initial size, and launches the frame. See the following code example:

[Java]
// MapViewer.java.
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import javax.swing.UIManager;
import com.esri.arcgis.system.AoInitialize;
import com.esri.arcgis.system.EngineInitializer;
import com.esri.arcgis.system.esriLicenseProductCode;
public class MapViewer{
    public static void main(String[] args)throws IOException{
        EngineInitializer.initializeVisualBeans();
        String laf = UIManager.getSystemLookAndFeelClassName();
        UIManager.setLookAndFeel(laf);
        final AoInitialize aoInit = new AoInitialize();
        aoInit.initialize(esriLicenseProductCode.esriLicenseProductCodeEngine);
        MapViewerFrame mapViewerFrame = new MapViewerFrame();
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = d.width / 6;
        int y = d.height / 6;
        int width = d.width * 2 / 3;
        int height = d.height * 2 / 3;
        mapViewerFrame.setBounds(x, y, width, height);
        mapViewerFrame.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e){
                try{
                    aoInit.shutdown(); 
                }
                catch (IOException ex){
                    ex.printStackTrace(); 
                }
                System.exit(0); 
            }
        }
        );
        mapViewerFrame.buildAndShow();
    }
} // End MapViewer class.
  1. Compile the MapViewerFrame and MapViewer Java files. To do so, the Java compiler needs to know where to find the referenced Java classes. This is done by including arcobjects.jar in the classpath. To compile using the command line, use the cd command to change to the directory containing the MapViewerFrame and MapViewer Java code.
javac - classpath % ARCGISHOME % \java\lib\arcobjects.jar;. * .java
 
The preceding code example compiles the Java program and produces class files for the application. If you get NoClassDefFoundError, check your classpath and verify arcobjects.jar exists at the specified location.
  1. Launch the MapViewer class and verify a blank Java frame appears before proceeding to the next step. To run the Java program, click the Run button in your IDE or give the following command from the command line:  
java - classpath % ARCGISHOME %\java\lib\arcobjects.jar;. MapViewer
  1. Add member variables for the components to be added to the MapViewerFrame class and create these components in the constructor. See the following code example:

[Java]
// MapViewerFrame.java.
import java.io.IOException;
import javax.swing.JFrame;

// Add new imports for this step.
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JPanel;
import com.esri.arcgis.beans.TOC.TOCBean;
import com.esri.arcgis.beans.map.MapBean;
import com.esri.arcgis.beans.pagelayout.PageLayoutBean;
import com.esri.arcgis.beans.toolbar.ToolbarBean;

public class MapViewerFrame extends JFrame{
    PageLayoutBean pageLayout;
    MapBean map;
    TOCBean toc;
    ToolbarBean toolbar;
    JLabel statusLabel;
    // Constructor.
    public MapViewerFrame(){
        setTitle("MapViewer");
        pageLayout = new PageLayoutBean();
        map = new MapBean();
        toc = new TOCBean();
        toolbar = new ToolbarBean();
        statusLabel = new JLabel(" ");
    }
}
  1. In the MapViewerFrame user interface, the toolbar component occupies BorderLayout.NORTH and the pageLayout component occupies the BorderLayout.CENTER position. The table of contents and map components go into a JPanel, which sits in the BorderLayout.WEST position. To achieve this, create a method to build a JPanel containing the two controls with the desired layout. See the following code example:

[Java]
// New method to build the left panel.
private JPanel buildMapTOCPanel(){
    JPanel leftPanel = new JPanel();
    JPanel bottomPanel = new JPanel();
    leftPanel.setLayout(new BorderLayout());
    bottomPanel.setLayout(new BorderLayout());
    bottomPanel.setPreferredSize(new Dimension(200, 200));
    bottomPanel.add(map, BorderLayout.CENTER);
    leftPanel.add(toc, BorderLayout.CENTER);
    leftPanel.add(bottomPanel, BorderLayout.SOUTH);
    return leftPanel;
}
  1. In the BorderLayout.SOUTH position of the MapViewerFrame, add a JLabel to act as a status bar. The buildAndShow() method looks like the following code example when you update it with all layout locations:

[Java]
public void buildAndShow()throws IOException{
    JPanel mapTOCPanel = buildMapTOCPanel();
    this.getContentPane().add(toolbar, BorderLayout.NORTH);
    this.getContentPane().add(pageLayout, BorderLayout.CENTER);
    this.getContentPane().add(mapTOCPanel, BorderLayout.WEST);
    this.getContentPane().add(statusLabel, BorderLayout.SOUTH);

    this.setVisible(true);
}
  1. Compile and run the application to confirm that the GUI's layout looks like the following screen shot:

    A standard Java layout manager (BorderLayout) has been used to position the components and manages the layout and sizes of the components. You will be able to resize the window and check that the components are updated appropriately without requiring any explicit resizing code.

Loading map documents

  1. When the components are added, load the map documents into the controls. To do this, add the following imports to MapViewer.java. See the following code example:
 

[Java]
import com.esri.arcgis.controls.IPageLayoutControlEventsAdapter;
import com.esri.arcgis.controls.IPageLayoutControlEventsOnPageLayoutReplacedEvent;
  1. Add the following code example to the end of the buildAndShow method, before the call to this.setVisible():
For cross-platform compatibility, verify the file and path names used to store data are in lowercase text.

[Java]
public void buildAndShow()throws IOException{
    . . . . . . addEventListeners();
    // Load a preauthored map document into the PageLayout bean.

    String arcgisHome = System.getenv("ARCGISHOME");
    String documentPath = arcgisHome + 
        "java/samples/data/mxds/gulf of st. lawrence.mxd";
    if (pageLayout.checkMxFile(documentPath)){
        pageLayout.loadMxFile(documentPath, null);
    }
    this.setVisible(true);
  1. When the document is loaded into the pageLayout bean, an onPageLayoutReplaced event is generated. Add code to load the same map document in the map component in response to this event. In the addEventListeners() method, add the event listener to the pageLayout component for the onPageLayoutReplaced event as an anonymous inner-class by using IPageLayoutControlEventsAdapter. See the following code example:

 

[Java]
private void addEventListeners()throws IOException{
    pageLayout.addIPageLayoutControlEventsListener(new
        IPageLayoutControlEventsAdapter(){
        public void onPageLayoutReplaced
            (IPageLayoutControlEventsOnPageLayoutReplacedEvent evt)throws
            IOException{
            map.loadMxFile(pageLayout.getDocumentFilename(), null, null);
                map.setExtent(map.getFullExtent()); 
        }
    }
    );
}

Buddying up the ToolbarBean and TOCBean

Components are not aware of each other even though they have been added to the JFrame. For the controls to work in sync, the TOC and toolbar components should know the control with which they are associated. Otherwise, the toolbar component will not know which component it is controlling, and the TOC component will not know which component's TOC it should display.
 
To set up this communication between the components, add the following code example to the buildAndShow() method after the load document code:

[Java]
public void buildAndShow()throws IOException{
    . . . 
    // Load a preauthored map document on the pageLayout component.

    String arcgisHome = System.getenv("ARCGISHOME");
    String documentPath = arcgisHome + 
        "java/samples/data/mxds/gulf of st. lawrence.mxd";
    if (pageLayout.checkMxFile(documentPath))
        pageLayout.loadMxFile(documentPath, null);
    // Set buddy controls to wire up the TOC and toolbar beans
    // with the PageLayout bean.
    toc.setBuddyControl(pageLayout);
    toolbar.setBuddyControl(pageLayout);
}

this.setVisible(true);

Adding commands to the toolbar

The toolbar control has been added to the user interface. By default, this control is not populated with any tools. You will add tools in the following steps.
 
ArcGIS Engine comes with more than 120 commands and tools that work with the MapBean, PageLayoutBean, and ToolbarBean. These commands and tools provide a lot of frequently used GIS functionality for map navigation, graphics management, and feature selection. You will add some of these commands and tools to your application.
  1. To add the prebuilt toolbar commands, add the following imports to MapViewerFrame.java:

[Java]
import com.esri.arcgis.controls.ControlsMapFullExtentCommand;
import com.esri.arcgis.controls.ControlsMapPanTool;
import com.esri.arcgis.controls.ControlsMapZoomInTool;
import com.esri.arcgis.controls.ControlsMapZoomOutTool;
import com.esri.arcgis.controls.ControlsOpenDocCommand;
import com.esri.arcgis.controls.ControlsPagePanTool;
import com.esri.arcgis.controls.ControlsPageZoomInTool;
import com.esri.arcgis.controls.ControlsPageZoomOutTool;
import com.esri.arcgis.controls.ControlsPageZoomPageToLastExtentBackCommand;
import com.esri.arcgis.controls.ControlsPageZoomPageToLastExtentForwardCommand;
import com.esri.arcgis.controls.ControlsPageZoomWholePageCommand;
import com.esri.arcgis.systemUI.esriCommandStyles;
In the buildAndShow() method, add the prebuilt commands to the toolbar before the addEventListeners() call. See the following code example:
[Java]
// Add generic commands to the toolbar.
toolbar.addItem(new ControlsOpenDocCommand(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsPageZoomInTool(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsPageZoomOutTool(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsPagePanTool(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsPageZoomWholePageCommand(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsPageZoomPageToLastExtentBackCommand(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsPageZoomPageToLastExtentForwardCommand(), 0,  - 1, false,
    0, esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsMapZoomInTool(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsMapZoomOutTool(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsMapPanTool(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new ControlsMapFullExtentCommand(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
addEventListeners();
// Load a preauthored map document on the pageLayout component.
  1. Run the application. The map document is loaded into the pageLayout component and the TOC component lists the data layers in the map document as shown in the following screen shot. Use the TOC component to toggle layer visibility. By default, the focus map of the map document is loaded into the map component and the commands have been added to the toolbar component.

Creating a popup menu using ToolbarMenu

ArcGIS Engine provides a ToolbarMenu component that can be used to add pop-up menus to other components, such as MapBean and PageLayoutBean. In this section, you will add a pop-up menu to the pageLayout. The pop-up menu contains prebuilt commands from the com.esri.arcgis.controls package.
 
To display the pop-up menu, an event handler will be added to the pageLayout component for the onMouseDown event. The menu appears when right-clicked.
  1. Add the following imports to MapViewerFrame.java:

[Java]
import com.esri.arcgis.controls.ToolbarMenu;
import com.esri.arcgis.controls.IPageLayoutControlEventsOnMouseDownEvent;
import com.esri.arcgis.controls.ControlsPageZoomInFixedCommand;
import com.esri.arcgis.controls.ControlsPageZoomOutFixedCommand;
  1. Add a member variable for the ToolbarMenu. See the following code example:

[Java]
public class MapViewerFrame extends JFrame{
    PageLayoutBean pageLayout;
    MapBean map;
    TOCBean toc;
    ToolbarBean toolbar;
    JLabel statusLabel;
    ToolbarMenu popupMenu;
  1. Construct the popupMenu object in a try/catch block. See the following code example:

[Java]
// Constructor.
public MapViewerFrame(){
    setTitle("MapViewer");
    pageLayout = new PageLayoutBean();
    map = new MapBean();
    toc = new TOCBean();
    toolbar = new ToolbarBean();
    statusLabel = new JLabel(" ");
    try{
        popupMenu = new ToolbarMenu();
    }
    catch (IOException e){
        e.printStackTrace();
    }
}
  1. Add prebuilt commands from the com.esri.arcgis.controls package to the popupMenu component before adding commands to the toolbar in the buildAndShow() method. See the following code example:

[Java]
// Add popup menu items.
popupMenu.addItem(new ControlsPageZoomInFixedCommand(), 0,  - 1, false,
    esriCommandStyles.esriCommandStyleIconAndText);
popupMenu.addItem(new ControlsPageZoomOutFixedCommand(), 0,  - 1, false,
    esriCommandStyles.esriCommandStyleIconAndText);
popupMenu.addItem(new ControlsPageZoomWholePageCommand(), 0,  - 1, false,
    esriCommandStyles.esriCommandStyleIconAndText);
popupMenu.addItem(new ControlsPageZoomPageToLastExtentBackCommand(), 0,  - 1, false,
    esriCommandStyles.esriCommandStyleIconAndText);
popupMenu.addItem(new ControlsPageZoomPageToLastExtentForwardCommand(), 0,  - 1,
    false, esriCommandStyles.esriCommandStyleIconAndText);
// Add generic commands to the toolbar.
. . .
  1. Associate the popupMenu with the pageLayout component, along with the code that sets up the buddy controls, in the buildAndShow() method. See the following code example:

[Java]
// Set buddy controls to wire up the TOC and ToolbarBean
// with the pageLayout object.
toc.setBuddyControl(pageLayout);
toolbar.setBuddyControl(pageLayout);
popupMenu.setHook(pageLayout);
}

this.setVisible(true);
  1. In the addEventListeners() method, add an event listener to the pageLayout component for the onMouseDown event, as an anonymous inner-class, using IPageLayoutControlEventsAdapter. See the following code example:

[Java]
pageLayout.addIPageLayoutControlEventsListener(new IPageLayoutControlEventsAdapter(){
    public void onPageLayoutReplaced
        (IPageLayoutControlEventsOnPageLayoutReplacedEvent evt)throws IOException{
        map.loadMxFile(pageLayout.getDocumentFilename(), null, null); map.setExtent
            (map.getFullExtent()); 
    }
    public void onMouseDown(IPageLayoutControlEventsOnMouseDownEvent evt)throws
        IOException{
        // If the right mouse button is clicked, display the popup menu.
        if (evt.getButton() == 2){
            popupMenu.popupMenu(evt.getX(), evt.getY(), pageLayout.getHWnd()); 
        }
    }
}

    ;
  1. Run the application. Right-click the pageLayout component to display the pop-up menu and navigate around the page layout. See the following screen shot:

Controlling label editing in the TOCBean

By default, the TOCBean allows users to automatically toggle the visibility of layers and to change map and layer names as they appear in the TOC. You will add code to prevent users from editing a name and replacing it with an empty string.
  1. Add the following imports to MapViewerFrame.java for classes used in this step:

[Java]
import com.esri.arcgis.controls.ITOCControlEventsAdapter;
import com.esri.arcgis.controls.ITOCControlEventsOnEndLabelEditEvent;
import com.esri.arcgis.controls.esriTOCControlEdit;
  1. In the buildAndShow() method, set the labelEdit to manual. See the following code example

[Java]
// Set label editing to manual.
toc.setLabelEdit(esriTOCControlEdit.esriTOCControlManual);
// Add popup menu items.
. . .
  1. In the addEventListeners() method, add an event listener to the TOC component for the onEndLabelEdit event, as an anonymous inner class, using ITOCControlEventsAdapter. See the following code example:

[Java]
private void addEventListeners()throws IOException{
    . . . toc.addITOCControlEventsListener(new ITOCControlEventsAdapter(){
        public void onEndLabelEdit(ITOCControlEventsOnEndLabelEditEvent labelEditEvt)
            throws IOException{
            String newLabel = labelEditEvt.getNewLabel(); 
            // If the new label is an empty string, prevent the edit.
            if (newLabel.equals("")){
                labelEditEvt.setCanEdit(false); 
            }
        }
    }
        ;
}
  1. Run the application. To edit a map, click the layer, heading, or legend class label in the TOC component, then click again to invoke label editing. Replace the label with an empty string. You can replace the label with strings other than an empty string. To cancel, press Esc any time during the edit. See the following screen shot:

Drawing an overview rectangle on the MapBean

Next, use the map component as an overview window and draw on its display the current extent of the focus map within the pageLayout component. Navigate around the data within the data frame of the pageLayout component to see the map component's overview window update.
 
  1. Add the following imports to MapViewerFrame.java for classes used in this step:

[Java]
import com.esri.arcgis.controls.IMapControlEvents2Adapter;
import com.esri.arcgis.controls.IMapControlEvents2OnAfterDrawEvent;
import com.esri.arcgis.controls.IPageLayoutControlEventsOnPageLayoutReplacedEvent;
import com.esri.arcgis.carto.Map;
import com.esri.arcgis.carto.esriViewDrawPhase;
import com.esri.arcgis.display.DisplayTransformation;
import com.esri.arcgis.display.ITransformEventsAdapter;
import com.esri.arcgis.display.ITransformEventsVisibleBoundsUpdatedEvent;
import com.esri.arcgis.display.RgbColor;
import com.esri.arcgis.display.SimpleFillSymbol;
import com.esri.arcgis.display.SimpleLineSymbol;
import com.esri.arcgis.geometry.IEnvelope;
  1. Add the following class members to MapViewerFrame:

[Java]
public class MapViewerFrame extends JFrame{
    SimpleFillSymbol fillSymbol; // The symbol used to draw the envelope.
    IEnvelope currentExtent; // The envelope drawn on the MapBean.
    Map focusMap; // The PageLayoutBean's focus map.
    PageLayoutBean pageLayout;
    . . .
  1. Create a createOverviewSymbol() private method. This is where you will create the symbol used in the map control to represent the extent of the data in the pageLayout Bean. See the following code example:

[Java]
private void createOverviewSymbol()throws IOException{
    RgbColor color = new RgbColor();
    color.setRed(255);
    color.setGreen(0);
    color.setBlue(0);
    color.setTransparency((byte)255);
    SimpleLineSymbol outline = new SimpleLineSymbol();
    outline.setColor(color);
    fillSymbol = new SimpleFillSymbol();
    color.setTransparency((byte)0);
    fillSymbol.setColor(color);
    fillSymbol.setOutline(outline);
}
Call createOverviewSymbol from the buildAndShow() method after the call that sets label editing to manual. See the following code example:
[Java]
// Set label editing to manual.
toc.setLabelEdit(esriTOCControlEdit.esriTOCControlManual);
// Create symbol used to draw overview on the MapBean.
createOverviewSymbol();
// Add popup menu items.
. . .
  1. In the event listener for IPageLayoutControlEvents (that you previously added to the addEventListeners() method), get a reference to the pageLayout component's focus map. Store the extent of the focusMap in the currentExtent member variable. This extent will be used to draw the overview rectangle on the map component. To achieve this, add the following code example after loading the map document and setting its extent in the onPageLayoutReplaced event handler:

 

[Java]
pageLayout.addIPageLayoutControlEventsListener(new IPageLayoutControlEventsAdapter(){
    public void onPageLayoutReplaced
        (IPageLayoutControlEventsOnPageLayoutReplacedEvent evt)throws IOException{
        map.loadMxFile(pageLayout.getDocumentFilename(), null, null); map.setExtent
            (map.getFullExtent()); focusMap = new Map(pageLayout.getActiveView()
            .getFocusMap()); currentExtent = focusMap.getExtent(); 
    }
}

);
  1. The default events of the PageLayoutBean are the IPageLayoutControlEvents. These events do not tell you when the extent of the map within the data frame changes. To do this, trap the ITransformEvents of the PageLayoutBean focus map. Add the following event listeners to listen to the DisplayTransformation object's visibleBoundsUpdated event.

    The visibleBoundsUpdated event is triggered when the extent of the map is changed and is used to set the IEnvelope to the new visible bounds of the map. By refreshing the MapBean, you force it to redraw the shape on its display. Modify the listener you edited in the preceding step. See the following code example:

[Java]
pageLayout.addIPageLayoutControlEventsListener(new IPageLayoutControlEventsAdapter(){
    public void onPageLayoutReplaced
        (IPageLayoutControlEventsOnPageLayoutReplacedEvent evt)throws IOException{
        map.loadMxFile(pageLayout.getDocumentFilename(), null, null); map.setExtent
            (map.getFullExtent()); focusMap = new Map(pageLayout.getActiveView()
            .getFocusMap()); currentExtent = focusMap.getExtent();
            DisplayTransformation dt = new DisplayTransformation
            (focusMap.getScreenDisplay().getDisplayTransformation());
            dt.addITransformEventsListener(new ITransformEventsAdapter(){
            public void visibleBoundsUpdated
                (ITransformEventsVisibleBoundsUpdatedEvent evt)throws IOException{
                // Set currentExtent to the new visible extent.
                currentExtent = evt.getSender().getVisibleBounds(); 
                // Refresh the map components foreground phase.
                map.refresh(esriViewDrawPhase.esriViewForeground, null, null); 
            }
        }
        ); 
    }
    public void onMouseDown(IPageLayoutControlEventsOnMouseDownEvent evt)throws
        IOException{
  1. Add IMapControlEvents2Listener to the map component that draws the updated bounds when a map refresh is triggered by the visibleBoundsUpdated event handler, added in the preceding step. Add the following code example to the addEventListeners() method:

[Java]
map.addIMapControlEvents2Listener(new IMapControlEvents2Adapter(){
    public void onAfterDraw(IMapControlEvents2OnAfterDrawEvent evt)throws
        IOException{
        if (evt.getViewDrawPhase() == esriViewDrawPhase.esriViewForeground){
            try{
                // Draw the shape on the MapBean.
                map.drawShape(currentExtent, fillSymbol); 
            }
            catch (Exception e){
                System.err.println("Error in drawing shape on MapBean"); 
                // e.printStackTrace();
            }
        }
    }
}

    ;
  1. Run the application. Use the map navigation tools previously added to change the extent of the focus map in the pageLayout component and observe that the new extent is drawn on the map component as a red rectangle. See the following screen shot:
Navigating the focus map using the map navigation tools changes the extent of the focus map in the PageLayoutBean and causes the MapBean to update. Navigating the page layout with the page layout navigation tools changes the extent of the page layout (not the extent of the focus map in thePageLayoutBean), resulting in the MapBean not updating.

Creating a custom tool

Create a custom tool to add to the ToolbarBean. This tool adds today's date as a text element to the PageLayoutBean at the location of a mouse click. The tool will be built as a generic tool so it can work with MapBean and ToolbarBean, as well as the PageLayoutBean. Custom tools can be built as Java classes that extend com.esri.arcgis.controls.BaseTool.
The BaseTool class makes it easier to create custom tools than implementing com.esri.arcgis.systemUI.ICommand and com.esri.arcgis.systemUI.ITool directly. By extending a base class, you can avoid writing empty implementation methods for the ICommand and ITool interfaces.
Create an AddDateTool.java file. In the default constructor, set the values for some of BaseTool's protected fields. See the following code example:
[Java]
// AddDateTool.java.
import com.esri.arcgis.controls.BaseTool;
public class AddDateTool extends BaseTool{
    public AddDateTool(){
        //Set various protected properties specified by BaseTool.
        name = "CustomCommands_Add Date";
        caption = "Add date";
        toolTip = "Add date";
        message = "Adds a date element to the page layout";
        category = "CustomCommands";
        enabled = true;
    }
} // End AddDateTool class.
  1. The onCreate method is passed a reference to the control in which the command works. In this case, it can be a MapBean, PageLayoutBean, or ToolbarBean. Rather than adding logic in the onCreate method to determine the type of object passed to the hook method, use theHookHelper class to handle this. A command or tool needs to know how to handle the hook it gets passed, so a check is needed to determine the type of ArcGIS control that has been passed. The HookHelper is used to hold the hook and return the ActiveView regardless of the type of hook (in this case either a MapBean, PageLayoutBean, or ToolbarBean). Import the HookHelper class and add the HookHelper member variable to the AddDateTool class. See the following code example:

[Java]
import com.esri.arcgis.controls.HookHelper;
public class AddDateTool extends BaseTool{
    HookHelper hookHelper;
    . . .
  1. Override the BaseTool.onCreate method. In it, construct the HookHelper and use the setHookByRef method to pass the controls object. BaseTool.onCreate is not declared as throwing any exceptions, but HookHelper can throw IOException or AutomationException. Thus, the code in your onCreate method must trap and handle these exceptions. This simple example handles an exception by encapsulating it in a RuntimeException and throwing it up the stack. See the following code example:

[Java]
public void onCreate(Object obj){
    try{
        hookHelper = new HookHelper();
        hookHelper.setHookByRef(obj);
    }
    catch (IOException ex){
        System.out.println(
            "Exception caught inside AddDateTool.onCreate(). Throwing as new RuntimeException.");
        throw new RuntimeException(ex);
    }
}
  1. Add import statements for classes and interfaces that will be used by the onMouseDown method. See the following code example:

[Java]
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.esri.arcgis.carto.IActiveView;
import com.esri.arcgis.carto.TextElement;
import com.esri.arcgis.carto.esriViewDrawPhase;
import com.esri.arcgis.display.TextSymbol;
import com.esri.arcgis.geometry.IPoint;
import com.esri.arcgis.support.ms.stdole.StdFont;
  1. Override the onMouseDown method, which creates a TextElement using the current date as its text and adds it to the graphics container of the hook object. See the following code example:

[Java]
public void onMouseDown(int button, int shift, int x, int y){
    try{
        Date today = new Date();
        // Format the date in the form of "Wed 25 Aug, 2004".
        SimpleDateFormat formatter;
        formatter = new SimpleDateFormat("EEE d MMM, yyyy");
        String dateString = formatter.format(today);
        // Create a font.
        StdFont font = new StdFont();
        font.setName("Arial");
        font.setBold(true);
        // Create a text symbol.
        TextSymbol textSymbol = new TextSymbol();
        textSymbol.setFont(font);
        textSymbol.setSize(15);
        // Create a text element to add to the graphics container.
        TextElement textElement = new TextElement();
        textElement.setSymbol(textSymbol);
        textElement.setScaleText(false);
        textElement.setText(dateString);
        // Add the text element to the graphics container.
        IActiveView activeView = hookHelper.getActiveView();
        IPoint pt = activeView.getScreenDisplay().getDisplayTransformation()
            .toMapPoint(x, y);
        textElement.setGeometry(pt);
        activeView.getGraphicsContainer().addElement(textElement, 0);
        // Refresh the view.
        activeView.partialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
    }
    catch (IOException ex){
        System.out.println(
            "Exception caught inside AddDateTool.onCreate(). Throwing as new RuntimeException.");
        throw new RuntimeException(ex);
    }
}
  1. The AddDateTool class is complete and can be compiled.
  2. In MapViewerFrame, add an instance of the AddDateTool to the toolbar component in the buildAndShow() method after the lines of code that add prebuilt commands to the toolbar. See the following code example:

[Java]
toolbar.addItem(new ControlsMapFullExtentCommand(), 0,  - 1, false, 0,
    esriCommandStyles.esriCommandStyleIconOnly);
toolbar.addItem(new AddDateTool(), 0,  - 1, true, 0,
    esriCommandStyles.esriCommandStyleTextOnly);
Recompile and launch MapViewer class. A new Add Date tool appears on the toolbar. Click the tool and click the page layout to add today's date at that point. See the following screen shot:

Customizing the ToolbarBean

In addition to adding ArcGIS Engine commands and tools at design time to the ToolbarBean—using addItem() as shown in the preceding code example—you can also add them by customizing the ToolbarBean at run time using the Customize dialog box. To enable this, place the toolbar component in customize mode and display the Customize dialog box.
  1. Add the following imports to MapViewerFrame.Java. See the following code example:

[Java]
import javax.swing.JCheckBox;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import com.esri.arcgis.controls.CustomizeDialog;
import com.esri.arcgis.controls.ICustomizeDialogEvents;
import com.esri.arcgis.controls.ICustomizeDialogEventsOnCloseDialogEvent;
import com.esri.arcgis.controls.ICustomizeDialogEventsOnStartDialogEvent;
Only tools and commands that are registered on the system as Component Object Model (COM) components can be added to the toolbar using the Customize dialog box. Java commands and tools (see the one built in the preceding step) do not appear on the Customize dialog box, since they are not registered as COM components in the system registry.
  1. Add the class members. See the following code example:

[Java]
. . . public class MapViewerFrame extends JFrame{
    JCheckBox customizeCB; // JCheckbox to control toolbar customization.
    CustomizeDialog customizeDialog;
    // The Customize dialog box used by the ToolbarBean constructor.
  1. Create a createCustomizeDialog() method, to instantiate the Customize dialog box. See the following code example

[Java]
private void createCustomizeDialog()throws IOException{
    customizeDialog = new CustomizeDialog();
    customizeDialog.setDialogTitle("Customize Toolbar Items");
    customizeDialog.setShowAddFromFile(true);
    // Set the toolbar in which to add new items.
    customizeDialog.setDoubleClickDestination(toolbar);
}
  1. In the buildandShow() method, call the createCustomizeDialog() method to instantiate the Customize dialog box. Also instantiate the customizeCB JCheckBox. See the following code example:

[Java]
public void buildAndShow()throws IOException{
    JPanel mapTOCPanel = buildMapTOCPanel();
    createCustomizeDialog();
    customizeCB = new JCheckBox("Customize");
  1. In the addEventListeners method, add a listener to the customizeCB JCheckBox to open and close the Customize dialog box. See the following code example:

[Java]
private void addEventListeners()throws IOException{
    ... customizeCB.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            try{
                if (customizeCB.isSelected()){
                    customizeDialog.startDialog(toolbar.getHWnd()); 
                }
                else{
                    customizeDialog.closeDialog(); 
                }
            }
            catch (Exception ee){
                ee.printStackTrace(); 
            }
        }
    }
    );
    ...
  1. Add the Customize check box to the GUI by creating a JPanel in the buildAndShow method. Move the toolbar into this JPanel, along with the new check box. Place the JPanel in the application's BorderLayout.NORTH position, where the toolbar used to be. See the following code example:

[Java]
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
topPanel.add(toolbar, BorderLayout.CENTER);
topPanel.add(customizeCB, BorderLayout.EAST);

this.getContentPane().add(topPanel, BorderLayout.NORTH);
this.getContentPane().add(toolbar, BorderLayout.NORTH);
this.getContentPane().add(pageLayout, BorderLayout.CENTER);
this.getContentPane().add(mapTOCPanel, BorderLayout.WEST);
  1. In the addEventListeners method, add an event listener to the Customize dialog box to put the toolbar in the customize state when the dialog box is started and in the normal state when it is closed. Since these events are not generated by Java's event dispatching thread, modifications to the customizeCB check box should be made via the SwingUtilities class. See the following code example:

[Java]
private void addEventListeners()throws IOException{
    ... customizeDialog.addICustomizeDialogEventsListener(new ICustomizeDialogEvents
        (){
        public void onStartDialog(ICustomizeDialogEventsOnStartDialogEvent arg0)
            throws IOException{
            toolbar.setCustomize(true); 
        }
        public void onCloseDialog(ICustomizeDialogEventsOnCloseDialogEvent arg0)
            throws IOException{
            toolbar.setCustomize(false); java.awt.EventQueue.invokeLater(new
                Runnable(){
                public void run(){
                    customizeCB.setSelected(false); 
                }
            }
            ); 
        }
    }
    );
    ...
  1. Run the application and check the Customize check box to put the toolbar into customize mode and open the Customize dialog box.
  2. On the Commands tab, click the Graphic Element category and drag the Select Elements command to add to the the toolbar. Right-click an item on the toolbar to adjust the style and grouping. See the following screen shot:
  3. Close the Customize Toolbar Item dialog box to stop customizing the application. Click the Select tool to move the text element containing today's date. See the following screen shot:

Deployment

To successfully deploy this application on a user's machine, create an executable Java Archive (JAR) file. Users can then launch the application using a Java Runtime Environment (JRE).
 
Do the following steps to create an executable JAR:
  1. In the directory where the compiled Java class files are present, create a manifest.txt file.
  2. Add the following code example to the manifest.txt file:

Main - Class: MapViewer
  1. Press Enter at the end of the first line.
  2. Save the file and open a command window. Use the cd command to change to the directory containing the manifest.txt file.
  3. Create an executable JAR file. See the following code example:

jar cmf manifest.txt mapviewer.jar *.class
  1. After you create an executable JAR file, a mapviewer.jar file will be created. This is the executable JAR that can be launched using a command. This command can be bundled in a batch file or shell script to provide a launch script. See the following code example:

java -jar mapviewer.jar

Additional resources

Use the following resources to understand and apply the concepts and techniques outlined in this scenario: