1. Введение
 В первом уроке мы создали базовое ГИС-приложение OpenMap, которое отображает карту с одним слоем фигур , загруженным из файловой системы, внутри JFrame .  Этот учебник был основан на com.bbn.openmap.app.example.SimpleMap .  В этом руководстве мы использовали следующие классы OpenMap: MapBean, PropertyHandler, ShapeLayer, com.bbn.openmap.util.SwingWorker . 
  Мы добавили MapBean в MapBean .  Тем не менее, OpenMap предоставляет собственный OpenMapFrame , OpenMapFrame , который может содержать MapPanel .  MapPanel — это интерфейс (см. Рисунок 1), описывающий компонент, который содержит MapBean, MapHandler , виджеты меню и все другие компоненты, связанные для создания виджета карты OpenMap .  MapPanel — это автономный компонент OpenMap Swing.  Ожидается, что MapPanel будет расширяться от java.awt.Container , в противном случае он может не быть автоматически добавлен в OpenMapFrame если он найден в MapHandler (мы поговорим о MapHandler позже в этой статье). 
  com.bbn.openmap.BufferedMapBean расширяет MapBean , заставляя его слои рисовать свои элементы карты в буферизованном изображении.  Этот буфер рисования затем визуализируется всякий раз, когда вызывается поток Java AWT для рисования слоев.  Это значительно повышает производительность, поскольку позволяет избежать (потенциально дорогого) процесса покраски Layer .  Если слой требует рисования, тогда буфер рисования восстанавливается слоями и рисуется в окне карты. 
  com.bbn.openmap.BufferedLayerMapBean расширяет BufferedMapBean специальным внутренним буфером изображений, который содержит все слои, которые были обозначены как фоновые.  Этот буфер особенно полезен, когда некоторые слои анимируют движущиеся объекты карты и карту часто перекрашивают.  Использование отдельного буферизованного изображения для фоновых слоев значительно сокращает время и объем работы, необходимые для рендеринга карты, увеличивая скорость обновления карты.  По умолчанию приложение OpenMap использует BufferedLayerMapBean вместо MapBean из-за этой повышенной производительности. 
2. OpenMapFrame и MapPanel
  Давайте посмотрим, как мы можем изменить наш MapFram e из предыдущего урока, чтобы воспользоваться вышеупомянутыми классами OpenMap : 
-   Измените MapFrameтак, чтобы онOpenMapFrameвместоjavax.swing.JFrame.
- Исправить импорт (Ctrl + I). При желании вы можете запустить приложение, чтобы убедиться, что оно работает как прежде.
- Переключитесь в представление «Дизайн», нажав кнопку «Дизайн».
-   Выберите и удалите экземпляр MapBean(из окна навигации ).
-   Перетащите элемент BasicMapPanelнаOpenMapFrameиз группы палитр OpenMap .
-   Переименуйте его в mapPanel.
- Измените направление макета на Центр из окна Свойства .
-   Вернуться к исходному виду, изменить строку mapBean.add(shapeLayer);tomapPanel.getMapBean().add(shapeLayer);,
Результат показан в листинге 1 (при условии, что вы выбрали последнюю реализацию из учебника 1 ).
  В качестве упражнения замените BasicMapPanel на OverlayMapPanel в шаге 5 выше.  Различные MapPanel (см. Рисунок 1) содержат BufferedLayerMapBean поэтому вам не нужно ничего делать для повышения производительности. 
Листинг 1. MapFrame Basic OpenMap-приложение
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | publicclassMapFrame extendsOpenMapFrame {   /** Creates new form MapFrame */   publicMapFrame() {      super("Simple Map");      initComponents();      initMap();   }  @SuppressWarnings("unchecked")                            privatevoidinitComponents() {      mapPanel = newcom.bbn.openmap.gui.BasicMapPanel();      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);      getContentPane().add(mapPanel, java.awt.BorderLayout.PAGE_END);      pack();   }     /** @param args the command line arguments */   publicstaticvoidmain(String args[]) {            /* Create and display the form */      java.awt.EventQueue.invokeLater(          () -> newMapFrame().setVisible(true)      );   }   // Variables declaration - do not modify                        privatecom.bbn.openmap.gui.BasicMapPanel mapPanel;   // End of variables declaration     privatevoidinitMap() {      CompletableFuture.supplyAsync(() -> getShapeLayer())           .thenAcceptAsync(                shapeLayer -> {                   // Add the political layer to the map                   mapPanel.getMapBean().add(shapeLayer);                   MapFrame.this.revalidate();      });   }   // ...} | 
3. MapHandler
  MapHandler — это java.beans.beancontext.BeanContext который можно рассматривать как большую MapHandler , в которую можно добавлять или удалять объекты.  Преимущество наличия объекта BeanContext в качестве центра архитектуры состоит в том, что он отправляет события слушателям, когда изменяется его членство в объекте.  Любой java.beans.beancontext.BeanContextMembershipListener добавленный в BeanContext , получит эти события и может использовать события для установки или обслуживания соединений с добавляемыми или удаляемыми объектами. 
  MapHandler может рассматриваться как карта, в комплекте с MapBean , MapBean и другими компонентами управления, содержащимися в ней.  Он может использоваться теми компонентами, которым необходимо получить указатель на другие объекты и сервисы.  Его можно использовать для добавления или удаления компонентов в приложении во время выполнения, а все другие объекты, добавленные в MapHandler получают уведомление о добавлении / удалении. 
  Давайте посмотрим, как мы можем воспользоваться MapHandler .  Модифицированный initMap() показан в листинге 2 .  Как уже упоминалось, MapHandler можно рассматривать как большую MapHandler в которую можно добавлять или удалять объекты.  Мы получаем MapHandler от MapPanel .  Чтобы иметь возможность добавлять слои к нему, нам нужно добавить LayerHandler в MapHandler .  Мы добавляем к нему shapeLayer и GraticuleLayer .  Порядок важен, то есть слой, добавленный последним, является тем, который появляется сверху.  Наконец, нам нужно добавить OpenMapFrame в MapHandler .  MapHandler — это вещество, которое склеивает все это.  Проверьте com.bbn.openmap.app.example.SimpleMap2 , тоже. 
  Причина, по MapHandler существует MapHandler , в отличие от простого использования BeanContext , заключается в том, что это расширенный BeanContext который отслеживает SoloMapComponent s ( com.bbn.openmap.SoloMapComponents ).  SoloMapComponent — это интерфейс, который можно использовать для объекта, чтобы указать, что в BeanContext одновременно имеется только один экземпляр этого типа компонента.  Например, MapBean является SoloMapComponent , и в SoloMapComponent может быть только один MapBean (Highlander!).  MapHandler имеет com.bbn.openmap.SoloMapComponentPolicy который говорит ему, что делать, если он попадает в ситуацию, когда добавляются дублирующиеся экземпляры SoloMapComponent .  В зависимости от политики MapHandler отклонит второй экземпляр SoloMapComponent ( com.bbn.openmap.SoloMapComponentRejectPolicy ) или заменит предыдущий компонент ( com.bbn.openmap.SoloMapComponentReplacePolicy ). 
Листинг 2: initMap () с использованием MapHandler
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | privatevoidinitMap() {   try{      // Get the default MapHandler the BasicMapPanel created.      MapHandler mapHandler = mapPanel.getMapHandler();      // Set the map's center      mapPanel.getMapBean().setCenter(newLatLonPoint.Double(38.0, 24.5));      // Set the map's scale 1:120 million      mapPanel.getMapBean().setScale(120000000f);      /*       * Create and add a LayerHandler to the MapHandler. The LayerHandler       * manages Layers, whether they are part of the map or not.       * layer.setVisible(true) will add it to the map. The LayerHandler       * has methods to do this, too. The LayerHandler will find the       * MapBean in the MapHandler.       */       mapHandler.add(newLayerHandler());       CompletableFuture.supplyAsync(() -> getShapeLayer())          .thenAcceptAsync(             shapeLayer -> {                  // Add the political layer to the map                  mapHandler.add(shapeLayer);                  mapHandler.add(newGraticuleLayer());                  MapFrame.this.revalidate();             });         // Add the map to the frame         mapHandler.add(this);    } catch(MultipleSoloMapComponentException msmce) {         // The MapHandler is only allowed to have one of certain         // items. These items implement the SoloMapComponent         // interface. The MapHandler can have a policy that         // determines what to do when duplicate instances of the         // same type of object are added - replace or ignore.         // In this example, this will never happen, since we are         // controlling that one MapBean, LayerHandler,         // MouseDelegator, etc is being added to the MapHandler.      }} | 
  Однако многие вещи отсутствуют в этом базовом приложении.  Например, никакие действия на карте, такие как увеличение / уменьшение масштаба, панорамирование и т. Д., Не могут быть выполнены.  Но они могут быть легко добавлены с помощью MapHandler .  Просто добавьте соответствующие обработчики в MapHandler внутри блока try-catch функции initMap() как показано в листинге 3. Теперь вы можете увеличивать или уменьшать масштаб с помощью среднего колесика мыши и перемещать карту левой кнопкой мыши. 
Листинг 3: initMap () с добавлением событий мыши
| 01 02 03 04 05 06 07 08 09 10 | privatevoidinitMap() {   //...   // Add MouseDelegator, which handles mouse modes (managing mouse   // events)   mapHandler.add(newMouseDelegator());        // Add OMMouseMode, which handles how the map reacts to mouse   // movements   mapHandler.add(newOMMouseMode());   //... } | 
  До сих пор мы видели, как использовать: MapBean, MapHandler, LayerHandler, PropertyHandler, ShapeLayer, GraticuleLayer, OpenMapFrame . 
4. openmap.properties
  Тем не менее, OpenMap является еще более гибким, чем это.  С помощью технологии BeanContext мы можем определить компоненты, которые составляют наше приложение, в файле свойств openmap.properties .  Мы уже создали openmap.properties в нашем приложении, которое содержит свойства для слоев формы ESRI.  Файл свойств может содержать свойства, определенные для определенного компонента.  Определение области действия выполняется с использованием префикса свойства, поэтому свойства могут быть определены как: 
 prefix.property=value 
Давайте начнем с префикса наших существующих свойств и посмотрим, какие изменения требуются в нашем коде.
| 1 2 3 4 5 | shapePolitical.prettyName=Political SolidshapePolitical.lineColor=000000shapePolitical.fillColor=BDDE83shapePolitical.shapeFile=resources/map/shape/dcwpo-browse.shpshapePolitical.spatialIndex=resources/map/shape/dcwpo-browse.ssx | 
  PropertyHandler поддерживает префиксы, как показано жирным шрифтом в листинге 5. В следующем уроке мы увидим, насколько полезна область видимости свойств.  Поскольку следующая часть будет довольно обширной, лучше разбить ее здесь. 
Листинг 5: PropertyHandler с поддержкой префиксов
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | privateShapeLayer getShapeLayer() {   PropertyHandler propertyHandler = null;   try{      propertyHandler = newPropertyHandler.Builder().setPropertiesFile("./openmap.properties").setPropertyPrefix("shapePolitical").build();   } catch(IOException ex) {      Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);   }   //ShapeLayer:    ShapeLayer shapeLayer = newShapeLayer();    if(propertyHandler != null) {        shapeLayer.setProperties(propertyHandler.getPropertyPrefix(), propertyHandler.getProperties(propertyHandler.getPropertyPrefix()));   }   returnshapeLayer;} | 
5. Заключение
  В этом уроке мы узнали, как использовать: MapBean, MapHandler, LayerHandler, PropertyHandler, ShapeLayer, GraticuleLayer, OpenMapFrame .  Мы также увидели гибкость, обеспечиваемую файлом openmap.properties .  Новые приложения могут быть настроены там без перекомпиляции.  В следующем уроке мы увидим, как это сделать без необходимости перекомпилировать наше приложение. 
