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
|
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(); }); } // ...} |
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
Давайте начнем с префикса наших существующих свойств и посмотрим, какие изменения требуются в нашем коде.
|
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
|
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 . Новые приложения могут быть настроены там без перекомпиляции. В следующем уроке мы увидим, как это сделать без необходимости перекомпилировать наше приложение.
