Статьи

Учебное пособие по OpenMap, часть 2. Создание базового приложения для карты с помощью MapHandler. Часть 1.

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 :

  1. Измените MapFrame так, чтобы он OpenMapFrame вместо javax.swing.JFrame .
  2. Исправить импорт (Ctrl + I). При желании вы можете запустить приложение, чтобы убедиться, что оно работает как прежде.
  3. Переключитесь в представление «Дизайн», нажав кнопку «Дизайн».
  4. Выберите и удалите экземпляр MapBean (из окна навигации ).
  5. Перетащите элемент BasicMapPanel на OpenMapFrame из группы палитр OpenMap .
  6. Переименуйте его в mapPanel .
  7. Измените направление макета на Центр из окна Свойства .
  8. Вернуться к исходному виду, изменить строку mapBean.add(shapeLayer); to mapPanel.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
public class MapFrame extends OpenMapFrame {
 
   /** Creates new form MapFrame */
   public MapFrame() {
      super("Simple Map");
      initComponents();
      initMap();
   }
 
  @SuppressWarnings("unchecked")                        
   private void initComponents() {
      mapPanel = new com.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 */
   public static void main(String args[]) {
       
      /* Create and display the form */
      java.awt.EventQueue.invokeLater(
          () -> new MapFrame().setVisible(true)
      );
   }
 
   // Variables declaration - do not modify                    
   private com.bbn.openmap.gui.BasicMapPanel mapPanel;
   // End of variables declaration 
 
   private void initMap() {
      CompletableFuture.supplyAsync(() -> getShapeLayer())
           .thenAcceptAsync(
                shapeLayer -> {
                   // Add the political layer to the map
                   mapPanel.getMapBean().add(shapeLayer);
                   MapFrame.this.revalidate();
      });
   }
   // ...
}
Рисунок 1: Диаграмма классов основных классов OpenMap

Рисунок 1: Диаграмма классов основных классов OpenMap

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
private void initMap() {
   try {
      // Get the default MapHandler the BasicMapPanel created.
      MapHandler mapHandler = mapPanel.getMapHandler();
      // Set the map's center
      mapPanel.getMapBean().setCenter(new LatLonPoint.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(new LayerHandler());
 
       CompletableFuture.supplyAsync(() -> getShapeLayer())
          .thenAcceptAsync(
             shapeLayer -> {
                  // Add the political layer to the map
                  mapHandler.add(shapeLayer);
                  mapHandler.add(new GraticuleLayer());
                  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
private void initMap() {
   //...
   // Add MouseDelegator, which handles mouse modes (managing mouse
   // events)
   mapHandler.add(new MouseDelegator());    
   // Add OMMouseMode, which handles how the map reacts to mouse
   // movements
   mapHandler.add(new OMMouseMode());
   //...
}

До сих пор мы видели, как использовать: MapBean, MapHandler, LayerHandler, PropertyHandler, ShapeLayer, GraticuleLayer, OpenMapFrame .

4. openmap.properties

Тем не менее, OpenMap является еще более гибким, чем это. С помощью технологии BeanContext мы можем определить компоненты, которые составляют наше приложение, в файле свойств openmap.properties . Мы уже создали openmap.properties в нашем приложении, которое содержит свойства для слоев формы ESRI. Файл свойств может содержать свойства, определенные для определенного компонента. Определение области действия выполняется с использованием префикса свойства, поэтому свойства могут быть определены как:

prefix.property=value

Давайте начнем с префикса наших существующих свойств и посмотрим, какие изменения требуются в нашем коде.

Листинг 4: openmap.properties

1
2
3
4
5
shapePolitical.prettyName=Political Solid
shapePolitical.lineColor=000000
shapePolitical.fillColor=BDDE83
shapePolitical.shapeFile=resources/map/shape/dcwpo-browse.shp
shapePolitical.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
private ShapeLayer getShapeLayer() {
   PropertyHandler propertyHandler = null;
   try {
      propertyHandler = new PropertyHandler.Builder().setPropertiesFile("./openmap.properties").setPropertyPrefix("shapePolitical").build();
   } catch (IOException ex) {
      Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);
   }
   //ShapeLayer:
   ShapeLayer shapeLayer = new ShapeLayer();
   if (propertyHandler != null) {
        shapeLayer.setProperties(propertyHandler.getPropertyPrefix(), propertyHandler.getProperties(propertyHandler.getPropertyPrefix()));
   }
   return shapeLayer;
}

5. Заключение

В этом уроке мы узнали, как использовать: MapBean, MapHandler, LayerHandler, PropertyHandler, ShapeLayer, GraticuleLayer, OpenMapFrame . Мы также увидели гибкость, обеспечиваемую файлом openmap.properties . Новые приложения могут быть настроены там без перекомпиляции. В следующем уроке мы увидим, как это сделать без необходимости перекомпилировать наше приложение.

использованная литература

  1. Руководство разработчика OpenMap
  2. OpenMap Developer Советы