Для зарегистрированных пользователей |
|
Создание Java-апплета для отображения географических карт
Алексей Смирнов
Многие начинающие Java-программисты, после знакомства с базовыми возможностями и методами создания Java-апплетов, пробуют применить полученные знания для написания уже собственных апплетов - небольших программ, добавляемых к веб-странице. Итак, если вы тоже один из них, то сегодня мы попробуем вместе создать свой несложный апплет для отображения географической карты. Целью создания данного приложения будет то, что часто требуется разместить план или карту того или иного объекта больших размеров. И поскольку детальное изображение не будет вписываться в дизайн и приведет к медленной загрузке веб-странички, то большинство HTML-программистов прибегает к использованию тега
Листинг 1. Файл Map.dat Используя знак "#" можно будет отделять комментарии от остального содержания файла. Теперь начнем проектировать непосредственно сам Java-апплет. Создайте файл нашего будущего класса Map.java. И поместите туда следущее: import java.applet.*;public class Map extends Applet /** * Initialization. public void init() Прочитать файл конфигурации Отобразить карту
Листинг 2. Класс Map.java Как видите из комментариев (Листинг 2) дело осталось за малым: прочитать файл конфигурации и в соответствии с полученными значениями отобразить карту. Начнем с первого. Создадим метод getData() для чтения файла конфигурации Map.dat. Для доступа к файловой системе (чтение файла) нам потребуется использовать классы InputStream и StreamTokenizer из пакета java.io. Класс StreamTokenizer реализует простой лескический сканер, который разбивает поток символов InputStream на лексемы (слова). Это полезно для нас так как наш файл Map.dat содержит различные лексемы: координаты областей в виде чисел и названия файлов. Создав фильтр, можно воспользоваться методом nextToken() для чтения лексем. Он возвращает либо символ, либо константу: StreamTokenizer.TT_EOF, StreamTokenizer.TT_NUMBER, StreamTokenizer.TT_WORD. Фильтрацию комментариев, которые у нас начинаются с символа "#", можно просто осуществить при помощи метода commentChar().
Текст метода будет следующим: /** * Read the data file Map.dat. */ protected void getData() { InputStream is=null; int i=0; int ix=0; int x=0,y=0,w=0,h=0; try { try { is = new URL(getCodeBase(), "Map.dat").openStream(); StreamTokenizer st = new StreamTokenizer(is); st.eolIsSignificant(false); st.commentChar('#'); while (st.ttype != StreamTokenizer.TT_EOF) { st.nextToken(); if (st.ttype==st.TT_NUMBER) { int n = (int) st.nval; switch (i) { case 0: x = n; break; case 1: y = n; break; case 2: w = n; break; case 3: h = n; break; } i++; if (i==4) { lPoint[ix] = new Point(x,y); rPoint[ix] = new Point(w,h); i=0; } //continue; } if(st.ttype==st.TT_WORD) { mapFile[ix]=st.sval; ix++; } } /* while */ } catch (MalformedURLException e) {} } catch (IOException e) {} count=ix; }
Листинг 3. Метод getData Вы должны были заметить, что в приведенном коде встретились еще необъясненные поля lPoint и rPoint. Это массивы класса Point в которых мы будем хранить точки, считанные из файла. Класс Point, описанный как часть пакета awt, представляет собой структуру данных, которая может хранить координаты X,Y. mapFile - строковый массив для хранения имен файлов. Теперь приступим к getMap(). В качестве параметра вызова этого метода будет имя файла pic, который требуется показать. После загрузки картинки не забудем перерисовать апплет при помощи repaint(); /** * Get file of map picture from URL. */ private void getMap(String pic) { map = getImage(getCodeBase(), pic); repaint(); } /** * Update applet. **/ public void update(Graphics g) { paint(g); } public void paint(Graphics g) { g.drawImage(map,0,0,this); g.setColor(Color.black); g.drawRect(0,0,size().width-1, size().height-1); if (!isZoom & curId!=0) { g.setColor(Color.red); g.drawRect(lPoint[curId].x, lPoint[curId].y, rPoint[curId].x, rPoint[curId].y); } }
Листинг 4. Методы getMap(), update() и paint() Для переключения между общим и детальным планом будем использовать булеву переменную isZoom, которая будет true, тогда когда нам потребуется увеличивать нашу карту, т.е. показать картинку детального плана. Увеличение/уменьшение будет происходить при помощи щелчка мыши по карте. Для того, чтобы пользователь, использующий наш апплет, смог определить куда ему нажимать (возможно, что не все области общего плана можно будет увеличить), при наведении курсора мыши на "кликабельную" область будем показывать ее прямоугольную рамку красного цвета. Таким образом вам осталось только добавить методы, которые будут отвечать за обработку событий мыши. public boolean mouseUp(Event evt, int x, int y) { if (isZoom) { isZoom=false; getMap(mapFile[0]); } else { if (curId == 0) { showStatus("This area have not zoom."); } else { isZoom=true; getMap(mapFile[curId]); } } return true; } public boolean mouseMove(Event evt, int x, int y) { int i; i = getIndex(x,y); if (!isZoom) { if (curId != i) { if (curId != 0) repaint(lPoint[curId].x, lPoint[curId].y,rPoint[curId].x+1, rPoint[curId].y+1); if (i != 0) showArea(i); curId = i; } } return true; } /** * Show area under mouse pointer. **/ private void showArea(int i) { Graphics g = null; g = this.getGraphics(); g.setColor(Color.red); g.drawRect(lPoint[i].x, lPoint[i].y, rPoint[i].x, rPoint[i].y); } /** * Get index of map image. **/ private int getIndex(int x, int y) { for (int i=1; i=lPoint[i].x & x<=(lPoint[i].x+rPoint[i].x) & y>=lPoint[i].y & y<=(lPoint[i].y+rPoint[i].y)) return i; return 0; }
Листинг 5. Обработка событий мыши Ну и наконец, сделаем более дружественный интерфейс - добавим простой метод, который будет отображать сообщения в строке статуса браузера. /** * Show message in status line. **/ private void zoomStatus() { String msg; if (isZoom) msg="Click for unzoom"; else msg="Click for zoom"; showStatus(msg); }
Листинг 5. Метод zoomStatus() Теперь, естественно, не забыв добавить все поля и классы, которые используем, получим следущее: import java.awt.*; import java.awt.image.*; import java.applet.*; import java.net.*; import java.io.*; public class Map extends Applet { int max=100; Image map; int count; Point lPoint[]; Point rPoint[]; String mapFile[]=new String[max]; int curId; boolean isZoom; /** * Initialization. */ public void init() { lPoint = new Point[max]; rPoint = new Point[max]; getData(); getMap(mapFile[0]); }
Листинг 6. Окончательный вид начала файла класса Откомпилировав код и получив файл апплета Map.class попробуем вызвать его из HTML-страницы. Вызов класса из страницы будет следующим:
Не забудьте поместить файлы вашей карты в тот же каталог, где находятся апплет, HTML-страница и Map.dat.
|