Reset a map is a basic functionnality in most applications.In my case, I needed it because end-user will have possibilities to change the map context and content without exiting the application. But removing all layers before adding a new one is not enough as spatial reference can change, or tiling scheme and extent can vary from on layer to another (switch from one Tiled Package to another one).So I've implemented a "reset map" sample application (disconnected scenario), but I'm not sure it's best practice so I hope to have some comments on it to improve it if necessary (is dispose() correctly used ?)...and more importantly: I'm not satisfied because I have to create new JMap component each time I reset the map... it's the only way I found to reset the spatial reference and map extent properties (like min/max scale).So is it possible to properly reset a map, with the same JMap object (without new instanciation) ?Sample code (tpk used are from arcgis samples):public class ResetMapApplication {
/**
* Layer initialize complete listener
*/
public class LayerListener implements LayerInitializeCompleteListener {
@Override
public void layerInitializeComplete(LayerInitializeCompleteEvent e) {
Layer layer = e.getLayer();
if (layer.getStatus() == LayerStatus.INITIALIZED) {
System.out.println(String.format("-LayerInitializeCompleteEvent- Layer '%s' is initialized on map '%s' !", layer.getName(), map.getName()));
} else {
System.out.println(String.format("-LayerInitializeCompleteEvent- ERROR: Layer '%s' is NOT initialized on map '%s' !", layer.getName(), map.getName()));
System.out.println(" initialization error: " + e.getLayer().getInitializationError());
}
}
}
/**
* Map event listener
*/
public class MapListener implements MapEventListener {
@Override
public void mapDispose(MapEvent event) {
System.out.println(String.format("-MapEventListener- Map '%s' is disposed !", map.getName()));
}
@Override
public void mapReady(final MapEvent event) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println(String.format("-MapEventListener- Map '%s' is ready !", map.getName()));
}
});
}
@Override
public void mapExtentChanged(MapEvent event) {
// do nothing
}
}
/**
* Main : application's entry
* @param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
// instance of this application
ResetMapApplication layerApp = new ResetMapApplication();
// create the UI, including the map, for the application.
JFrame appWindow = layerApp.createWindow();
appWindow.add(layerApp.createUI());
appWindow.setVisible(true);
} catch (Exception e) {
// on any error, display the stack trace.
e.printStackTrace();
}
}
});
}
// content pane
private JLayeredPane contentPane;
// map
private JMap map;
// map count
private int count = 1;
// base layer TILED PACKAGE 1
private static final String TPK_BASEMAP_1 = "C:\\temp\\Topographic.tpk";
// base layer TILED PACKAGE 2
private static final String TPK_BASEMAP_2 = "C:\\temp\\SanFrancisco.tpk";
/**
* Creates a window.
* @return a window.
*/
private JFrame createWindow() {
JFrame window = new JFrame("Test - Reset a Map");
window.setBounds(100, 100, 1000, 700);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setLayout(new BorderLayout(0, 0));
window.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent windowEvent) {
super.windowClosing(windowEvent);
if (map != null) {
map.dispose();
}
}
});
return window;
}
/**
* Creates application content with ToolBar and Map's container
* @return
*/
private JComponent createUI() {
// application content
JPanel applicationPanel = new JPanel();
applicationPanel.setLayout(new BorderLayout(0, 0));
// button toolbar
final JToolBar toolBar = this.createToolBar();
// panel for the map : map will be created later...
this.contentPane = this.createContentPane();
applicationPanel.add(toolBar, BorderLayout.NORTH);
applicationPanel.add(this.contentPane, BorderLayout.CENTER);
return applicationPanel;
}
/**
* Create a toolbar with buttons
* @return toolBar - the toolBar
*/
private JToolBar createToolBar() {
JToolBar toolBar = new JToolBar();
toolBar.setLayout(new FlowLayout(FlowLayout.CENTER));
// button add TPK 1
JButton buttonTPK1 = new JButton("Add TPK Topographic");
buttonTPK1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// reset the map
resetMap();
// add tiled layer
ArcGISLocalTiledLayer tiledLayer = new ArcGISLocalTiledLayer(TPK_BASEMAP_1);
tiledLayer.setName(TPK_BASEMAP_1);
tiledLayer.addLayerInitializeCompleteListener(new LayerListener());
map.getLayers().add(tiledLayer);
}
});
toolBar.add(buttonTPK1);
// button Add TPK 2
JButton buttonTPK2 = new JButton("Add TPK SanFrancisco");
buttonTPK2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// reset the map
resetMap();
// add tiled layer
ArcGISLocalTiledLayer tiledLayer = new ArcGISLocalTiledLayer(TPK_BASEMAP_2);
tiledLayer.setName(TPK_BASEMAP_2);
tiledLayer.addLayerInitializeCompleteListener(new LayerListener());
map.getLayers().add(tiledLayer);
}
});
toolBar.add(buttonTPK2);
return toolBar;
}
/**
* Creates a content pane.
* @return a content pane.
*/
private JLayeredPane createContentPane() {
JLayeredPane contentPane = new JLayeredPane();
contentPane.setLayout(new BorderLayout(0, 0));
contentPane.setVisible(true);
return contentPane;
}
/**
* Reset the map :
* - remove and dispose resources
* - create new map
* - remove and add on panel (container)
*/
private void resetMap() {
System.out.println("-actionPerformed - RESET MAP !");
if (map != null) {
// remove all layers
for (int i = (this.map.getLayers().size() - 1) ; i == 0 ; i--) {
this.map.getLayers().remove(i);
}
// dispose data ressources
this.map.dispose();
// =>> ISSUE HERE : dispose() seems to be fired on the new map after createMap() below (see Console prints)
// remove map from content pane
this.contentPane.remove(map);
}
// re-create the map
this.map = createMap();
// =>> ISSUE HERE : can I avoid a new JMap to re-initialize the map (no spatial ref, no fullextent, etc.) ??
// add new map to the content pane
this.contentPane.add(map);
// Revalidate the map to perform a hierarchical refresh of all components
this.map.revalidate();
}
/**
* Create a map with navigator overlay
* @return JMap - the map
*/
private JMap createMap() {
JMap jMap = new JMap();
// give an incremental name
jMap.setName("map " + count ++);
// Add map event listner
jMap.addMapEventListener(new MapListener());
// Add NavigatorOverlay
NavigatorOverlay navigator = new NavigatorOverlay();
jMap.addMapOverlay(navigator);
return jMap;
}
}source code also available in zip file