Оглавление
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation
Аплет CDRotation
В этом разделе мы расскажем об аплете CDRotation, в
окне которого вращается компакт-диск.
В левом верхнем углу каждого кадра
отображается его порядковый номер (рис. 1). Этот
номер не нарисован в файлах кадров, а
надписывается приложением после рисования
очередного кадра. Такое невозможно, если
располагать в документе HTML файл AVI или
многосекционный файл GIF.

Рис. 1. Изображение вращающегося
компакт-диска в окне аплета CDRotation
Исходные тексты приложения
Главный файл исходных текстов приложения CDRotation
представлен в листинге 1. Листинг
1. Файл CDRotation.java 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;
public String getAppletInfo() { return "Name:
CDRotation"; } 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); }
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("Please, wait...",
10, dimAppWndDimension.height / 2); }
public void start() {
if (m_CDRotation == null) { m_CDRotation = new Thread(this);
m_CDRotation.start(); } }
public void stop() {
if (m_CDRotation != null) { m_CDRotation.stop();
m_CDRotation = null; } }
public void run() {
m_nCurrImage = 0;
if (!m_fAllLoaded) { repaint(); m_Graphics = getGraphics();
m_Images = new Image[NUM_IMAGES];
MediaTracker tracker =
new MediaTracker(this);
String strImage;
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); }
try { tracker.waitForAll();
m_fAllLoaded = !tracker.isErrorAny(); }
catch (InterruptedException e) { }
if (!m_fAllLoaded) { stop();
m_Graphics.drawString( "Load error", 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;
Thread.sleep(30); }
catch (InterruptedException e) { stop(); } } }}
Листинг 2 содержит исходный текст документа HTML,
созданного для аплета CDRotation. Листинг 2.
Файл CDRotation.tmp.html
<applet name="CDRotation" code="CDRotation"
codebase="file:/e:/sun/articles/vol13/src/CDRotation"
width="500" height="600" align="Top"
alt="If you had a java-enabled browser, you would see an applet
here."></applet> Описание исходных текстов
Рассмотрим наиболее важные методы нашего аплета. Метод 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("Please, wait...",
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(
"Load error", 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);
|