Microsoft Visual J++. Создание приложений и аплетов на языке Java. Часть 2© Александр Фролов, Григорий ФроловТом 32, М.: Диалог-МИФИ, 1997, 288 стр. Приложение CDRotationЗадача отображения видеофильмов в окне Java настолько важна, что Microsoft включил в Visual J++ специальные средства для создания шаблона исходных текстов аплета с анимацией. Если на третьем шаге системы автоматизированной создания исходных текстов аплетов Java Applet Wizard включить переключатель Yes в поле Would you like your applet to be multi-threaded, а также переключатель Yes в поле Would you like support for animation (рис. 4.3), для вас будут созданы исходные тексты аплета, в окне которого находится изображение земного шара, вращающегося вдоль вертикальной оси. Рис. 4.3. Включение исходного текста для работы с анимацией в создаваемый аплет Все, что вам остается сделать, это изменить созданные для вас исходные тексты таким образом, чтобы они соответствовали вашим потребностям. Именно так мы создали исходные тексты приложения CDRotation, в окне которого изображается вращающийся компакт-диск. Когда будете запускать приложение CDRotation, обратите внимание, что в левом верхнем углу каждого кадра отображается его порядковый номер. Этот номер не нарисован в файлах кадров, а надписывается приложением после рисования очередного кадра. Такое невозможно, если располагать в документе HTML файл AVI или многосекционный файл GIF. Исходные тексты приложенияГлавный файл исходных текстов приложения CDRotation представлен в листинге 4.7. Листинг 4.7. Файл CDRotation\CDRotation.java // ========================================================= // Рисование вращающегося компакт-диска // // (C) Фролов А.В, 1997 // // E-mail: frolov@glas.apc.org // WWW: http://www.glasnet.ru/~frolov // или // http://www.dials.ccas.ru/frolov // ========================================================= import java.applet.*; import java.awt.*; public class CDRotation extends Applet implements Runnable { // Ссылка на задачу рисования // вращающегося компакт-диска Thread m_CDRotation = null; // Контекст отображения для рисования private Graphics m_Graphics; // Массив изображений компакт-диска private Image m_Images[]; // Номер текущего изображения private int m_nCurrImage; // Ширина изображения private int m_nImgWidth = 0; // Высота изображения private int m_nImgHeight = 0; // Флаг загрузки всех изображений private boolean m_fAllLoaded = false; // Общее количество изображений private final int NUM_IMAGES = 11; // ------------------------------------------------------- // getAppletInfo // Метод, возвращающей строку информации об аплете // ------------------------------------------------------- public String getAppletInfo() { return "Name: CDRotation\r\n" + "Author: Alexandr Frolov\r\n" + "E-mail: frolov@glas.apc.org" + "WWW: http://www.glasnet.ru/~frolov" + "Created with Microsoft Visual J++ Version 1.0"; } // ------------------------------------------------------- // displayImage // Рисование текущего изображения, если все изображения // уже загружены // ------------------------------------------------------- private void displayImage(Graphics g) { // Если не все изображения загружены, // ничего не делаем if (!m_fAllLoaded) return; // Рисуем текущее изображение в центре окна аплета g.drawImage(m_Images[m_nCurrImage], (size().width - m_nImgWidth) / 2, (size().height - m_nImgHeight) / 2, null); // Рисуем в вернем левом углу кадра его порядковый номер g.drawString((new Integer(m_nCurrImage)).toString(), (size().width - m_nImgWidth) / 2, ((size().height - m_nImgHeight) / 2) + 10); } // ------------------------------------------------------- // paint // Метод paint, выполняющий рисование в окне аплета // ------------------------------------------------------- public void paint(Graphics g) { // Определяем текущие размеры окна аплета Dimension dimAppWndDimension = size(); // Выбираем в контекст отображения белый цвет g.setColor(Color.white); // Закрашиваем внутреннюю область окна аплета g.fillRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); // Выбираем в контекст отображения черный цвет g.setColor(Color.black); // Рисуем рамку вокруг окна аплета g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); // Если все изображения загружены, рисуем // текущее изображение if (m_fAllLoaded) { displayImage(g); } // Если не загружены, рисуем сообщение // о загрузке else g.drawString("Подождите, идет загрузка...", 10, dimAppWndDimension.height / 2); } // ------------------------------------------------------- // start // Метод вызывается при первом отображении окна аплета // ------------------------------------------------------- public void start() { if (m_CDRotation == null) { m_CDRotation = new Thread(this); m_CDRotation.start(); } } // ------------------------------------------------------- // stop // Метод вызывается, когда окно аплета исчезает с экрана // ------------------------------------------------------- public void stop() { if (m_CDRotation != null) { m_CDRotation.stop(); m_CDRotation = null; } } // ------------------------------------------------------- // run // Метод, который работает в рамках отдельной задачи // Он рисует в окне аплета изображения - кадры // клипа "вращающийся компакт-диск" // ------------------------------------------------------- public void run() { // Инициализируем номер текущего изображения m_nCurrImage = 0; // Проверяем, все ли изображения загружены. // Если нет, загружаем их if (!m_fAllLoaded) { // Перерисовываем окно аплета repaint(); // Получаем контекст отображения для окна m_Graphics = getGraphics(); // Создаем массив изображений m_Images = new Image[NUM_IMAGES]; // Создаем объект MediaTracker для контроля // загружки изображений MediaTracker tracker = new MediaTracker(this); // Переменная для хранения имени файла изображения String strImage; // Цикл загрузки изображений for (int i = 0; i < NUM_IMAGES; i++) { // Записываем в строку strImage имя текущего файла // с изображением strImage = "images/cdimg0" + ((i < 10) ? "0" : "") + i + ".gif"; // Инициируем получение изображения m_Images[i] = getImage(getDocumentBase(), strImage); // Добавляем изображение в объект MediaTracker tracker.addImage(m_Images[i], 0); } // Ожидаем окончание загрузки всех изображений try { tracker.waitForAll(); // Если не было ошибок, устанавливаем флаг // окончания загрузки m_fAllLoaded = !tracker.isErrorAny(); } catch (InterruptedException e) { } // Если при загрузке изображений произошла ошибка, // останавливаем задачу и рисуем сообщение об // ошибке if (!m_fAllLoaded) { stop(); m_Graphics.drawString( "При загрузке изображений произошла ошибка", 10, size().height / 2); return; } // Сохраняем ширину и высоту первого изображения m_nImgWidth = m_Images[0].getWidth(this); m_nImgHeight = m_Images[0].getHeight(this); } // Перерисовываем окно аплета repaint(); // Запускаем цикл рисования изображений while (true) { try { // Рисуем текущее изображение displayImage(m_Graphics); // Увеличиваем номер текущего изображения m_nCurrImage++; // Если достигли максимального номера, // начинаем с самого начала if(m_nCurrImage == NUM_IMAGES) m_nCurrImage = 0; // Выполняем задержку в 30 миллисекунд Thread.sleep(30); } // Если в процессе рисования возникло // исключение, останавливаем задачу catch (InterruptedException e) { stop(); } } } } Листинг 4.8 содержит исходный текст документа HTML, созданного для аплета CDRotation. Листинг 4.8. Файл CDRotation\CDRotation.html <html> <head> <title>CDRotation</title> </head> <body> <hr> <applet code=CDRotation.class id=CDRotation width=320 height=240 > </applet> <hr> <a href="CDRotation.java">The source.</a> </body> </html> Описание исходных текстовРассмотрим наиболее важные методы нашего приложения. Метод startВ задачу метода start, который получает управление при отображении окна аплета, входит создание и запуск задачи, отображающий кадры видеофильма с изображением вращающегося компакт-диска: if (m_CDRotation == null) { m_CDRotation = new Thread(this); m_CDRotation.start(); } Задача создается как объект класса Thread, причем конструктору передается ссылка на главный класс аплета. Поэтому при запуске задачи управление получит метод run, определенный в классе аплета. Метод stopМетод stop останавливает работу задачи, когда окно аплета исчезает с экрана: if(m_CDRotation != null) { m_CDRotation.stop(); m_CDRotation = null; } Для остановки вызывается метод stop. Метод paintСразу после получения управления, метод paint закрашивает окно аплета белым цветом и рисует вокруг него черную рамку. Затем метод проверяет содержимое флага m_fAllLoaded. Этот флаг установлен в значение true, когда все кадры видеофильма загружены и сброшен в значение false, когда загрузка кадров еще не завершена. Последняя ситуация возникает всегда при первом вызове метода paint. Если все изображения загружены, метод paint вызывает метод displayImage, определенный в нашем приложении: if(m_fAllLoaded) { displayImage(g); } Этот метод, о котором мы еще расскажем подробнее, отображает в окне аплета текущий кадр видеофильма. Если же кадры видеофильма еще не загружены, в окне аплета отображается соответствующее сообщение: else g.drawString("Подождите, идет загрузка...", 10, dimAppWndDimension.height / 2); Метод runМетод run работает в рамках отдельной задачи. Он занимается последовательным рисованием кадров нашего видеофильма. Прежде всего метод run записывает нулевое значение в поле m_nCurrImage, хранящее номер текущего отображаемого кадра: m_nCurrImage = 0; Далее выполняется проверка, загружены ли все кадры видеофильма, для чего анализируется содержимое флага m_fAllLoaded. Если изображения не загружены (а в самом начале так оно и есть) метод run перерисовывает окно аплета и получает контекст отображения для этого окна. Затем создается массив объектов Image для хранения кадров видеофильма: m_Images = new Image[NUM_IMAGES]; Метод run создает также объект класса MediaTracker для ожидания загрузки всех кадров видеофильма: MediaTracker tracker = new MediaTracker(this); Далее метод run в цикле загружает изображения и добавляет их в объект класса MediaTracker для того чтобы можно было дождаться загрузки всех кадров: for (int i = 0; i < NUM_IMAGES; i++) { strImage = "images/cdimg0" + ((i < 10) ? "0" : "") + i + ".gif"; m_Images[i] = getImage(getDocumentBase(), strImage); tracker.addImage(m_Images[i], 0); } Здесь предполагается, что файлы изображений находятся в каталоге images, который, в свою очередь, размещен там же, где и двоичный файл аплета. Имена файлов, составляющих отдельные кадры, начинаются с префикса cdimg0, вслед за которым идет номер кадра (00, 01, 02, и так далее), и расширение имени .gif. Ожидание загрузки кадров выполняется с помощью метода waitForAll, о котором мы вам уже рассказывали: try { tracker.waitForAll(); m_fAllLoaded = !tracker.isErrorAny(); } catch (InterruptedException e) { } После окончания ожидания флаг завершения загрузки устанавливается только в том случае, если метод isErrorAny вернул значение false, то есть если не было никаких ошибок. Если же произошла ошибка, в окне аплета отображается соответствующее сообщение, после чего работа метода run (и, следовательно, работа созданной для него задачи) заканчивается: if(!m_fAllLoaded) { stop(); m_Graphics.drawString( "При загрузке изображений произошла ошибка", 10, size().height / 2); return; } В случае удачной загрузки всех кадров метод run получает ширину и высоту первого кадра видеофильма и сохраняет эти значения в переменных m_nImgWidth и m_nImgHeight: m_nImgWidth = m_Images[0].getWidth(this); m_nImgHeight = m_Images[0].getHeight(this); Далее окно аплета перерисовывается: repaint(); При этом метод paint отображает в окне аплета первый кадр видеофильма. На следующем этапе работы метода run запускается цикл отображения кадров фильма: while (true) { try { displayImage(m_Graphics); m_nCurrImage++; if(m_nCurrImage == NUM_IMAGES) m_nCurrImage = 0; Thread.sleep(30); } catch (InterruptedException e) { stop(); } } В этом бесконечном цикле вызывается метод displayImage, рисующий текущий кадр видеофильма, после чего номер текущего кадра увеличивается на единицу. Если показаны все кадры, номер текущего кадра становится равным нулю, а затем процесс продолжается. Между отображением кадров выполняется задержка величиной 30 миллисекунд. Метод displayImageМетод displayImage вызывается из двух мест - из метода paint при перерисовке окна аплета и из метода run (периодически). Если кадры видеофильма не загружены, содержимое флага m_fAllLoaded равно false и метод displayImage просто возвращает управление, ничего не делая: if(!m_fAllLoaded) return; Если же загрузка изображений завершена, этот метод рисует в центре окна текущий кадр видеофильма, вызывая для этого знакомый вам метод drawImage: g.drawImage(m_Images[m_nCurrImage], (size().width - m_nImgWidth) / 2, (size().height - m_nImgHeight) / 2, null); После того как кадр нарисован, мы надписываем на нем его порядковый номер, вызывая для этого метод drawString: g.drawString((new Integer(m_nCurrImage)).toString(), (size().width - m_nImgWidth) / 2, ((size().height - m_nImgHeight) / 2) + 10); |