Аплет 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);
|