Microsoft Visual J++. Создание приложений и аплетов на языке Java

Метод run


Метод run получает управление при запуске задачи методом start. Если этот метод возвращает управление, соответствующая задача завершает свою работу.

Наша реализация метода run состоит из бесконечного цикла, в котором периодически с задержкой 50 миллисекунд вызывается метод repaint:

public void run()

{

  while(true)

  {

    try

    {

      repaint();

      Thread.sleep(50);

    }

    catch(InterruptedException e)

    {



      stop();

    }

  }

}

Метод repaint вызывает принудительную перерисовку окна аплета, выполняемую методом paint. В нашем приложении этот метод отображает текстовую строку и случайное число.

Для выполнения задержки метод run вызывает метод sleep из класса Thread. Так как метод sleep может вызывать исключение InterruptedException, мы его обрабатываем с помощью операторов try и catch. Если произошло исключение, мы завершаем задачу, вызывая метод stop.

Заметим, что периодическая перерисовка окна аплета может привести к неприятному миганию, поэтому использованный здесь метод периодического обновления содержимого окна аплета нельзя назвать оптимальным. Позже мы рассмотрим другой метод, при котором такой перерисовки не происходит.


Программный код метода run работает в рамках отдельной задачи. Он рисует в окне аплета закрашенные прямоугольники. Прямоугольники имеют случайные координаты, расположение и цвет.

Для того чтобы рисовать, необходимо получить контекст отображения. Так как наша задача, точнее, метод run определен в классе аплета, то он может получить контекст отображения, вызвав метод getGraphics:

Graphics g = getGraphics();

Для рисования нам также нужно знать размеры окна аплета. Мы получаем эти размеры при помощи метода size:

Dimension dimAppWndDimension = size();

Вооружившись контекстом отображения и размерами окна аплета, задача входит в бесконечный цикл рисования прямоугольников.

В качестве генератора случайных чисел мы используем метод random из класса Math, который при каждом вызове возвращает новое случайное число типа double, лежащее в диапазоне значений от 0.0 до 1.0.

Координаты по осям X и Y рисуемого прямоугольника определяются простым умножением случайного числа, полученного от метода random, соответственно, на ширину и высоту окна аплета:

x = (int)(dimAppWndDimension.width  * Math.random());

y = (int)(dimAppWndDimension.height * Math.random());

Аналогично определяются размеры прямоугольника, однако чтобы прямоугольники не были слишком крупными, мы делим полученные значения на 2:

width  = (int)(dimAppWndDimension.width * Math.random())/2;

height = (int)(dimAppWndDimension.height * Math.random())/2;

Так как случайное число имеет тип double, в обоих случаях мы выполняем явное преобразование результата вычислений к типу int.

Для случайного выбора цвета прямоугольника мы вычисляем отдельные цветовые компоненты, умножая значение, полученное от метода random, на число 255:

rColor = (int)(255 * Math.random());

gColor = (int)(255 * Math.random());

bColor = (int)(255 * Math.random());

Полученные значения цветовых компонент используются в конструкторе Color для получения цвета. Этот цвет устанавливается в контексте отображения методом setColor:

g.setColor(new Color(rColor, gColor, bColor));

Теперь все готово для рисования прямоугольника, которое мы выполняем при помощи метода fillRect:

g.fillRect(x, y, width, height);

После рисования прямоугольника метод run задерживает свою работу на 50 миллисекунд, вызывая метод sleep:

try

{

  Thread.sleep(50);

}

catch (InterruptedException e)

{

  stop();

}

Для обработки исключения InterruptedException, которое может возникнуть во время работы этого метода, мы предусмотрели блок try - catch. При возникновении указанного исключения работа задачи останавливается вызовом метода stop.




Внутри метода run мы определили массив строк, проинициализировав его значениями, полученными из параметров аплета:

String s[] = new String[6];

s[0] = m_String1;

s[1] = m_String2;

s[2] = m_String3;

s[3] = m_String4;

s[4] = m_String5;

s[5] = m_String6;

Задача, выполняющаяся в рамках метода run одновременно с кодом аплета, будет по очереди извлекать строки из этого массива и отображать их в нижней части окна аплета.

Так как для рисования строк текста нужно знать контекст отображения, мы получаем его при помощи метода getGraphics:

Graphics g = getGraphics();

Мы также определяем размеры окна аплета, знание которых необходимо для организации сдвига содержимого окна:

Dimension dimAppWndDimension = size();

Перед тем как запустить бесконечный цикл, мы также определяем метрики текущего шрифта и высоту символов шрифта:

FontMetrics fm = g.getFontMetrics();

yChar = fm.getHeight();

В рамках бесконечного цикла мы подсчитываем количество сдвигов (в счетчике ShiftsCounter), а также сдвинутые строки (в счетчике CurrentStr). Заметим, что для обеспечения плавности сдвига мы перемещаем строки по одному пикселу. Когда величина сдвига достигает высоты символов yChar плюс 5, метод run рисует новую строку.

Перед рисованием строки мы выбираем в контекст отображения красный или черный цвет, в зависимости от номера строки:

if(CurrentStr == 0)

  g.setColor(Color.red);

else

  g.setColor(Color.black);

Вы можете выделять нужные вам строки любым другим способом, например, наклоном или жирным шрифтом.

Для рисования строки мы вызываем метод drawString:

g.drawString(s[CurrentStr],

  10, dimAppWndDimension.height - 10);

Строка будет нарисована на десять пикселов выше нижней границы окна аплета.

После рисования строки мы проверяем, последняя она, или нет:

CurrentStr++;

if(CurrentStr > 5)

  CurrentStr = 0;

Если строка последняя, мы сбрасываем счетчик текущей строки, после чего перебор строк начнется с самого начала.

Для выполнения свертки мы вызываем метод copyArea, знакомый вам по 30 тому “Библиотеки системного программиста”:

yShift = 1;

g.copyArea(0, yShift + 1,

  dimAppWndDimension.width  - 1,

  dimAppWndDimension.height - 1,

  0, -yShift);

Этот метод сдвигает содержимое прямоугольной области экрана, заданной первыми четырьмя параметрами. Величина сдвига определяются двумя последними параметрами метода. В нашем случае сдвиг выполняется по вертикальной оси на значение -1, то есть на один пиксел вверх.

После сдвига освободившаяся область закрашивается желтым цветом:

g.setColor(Color.yellow);

g.fillRect(1, dimAppWndDimension.height - yShift - 1,

  dimAppWndDimension.width  - 2,

  dimAppWndDimension.height - 1);

Далее выполняется задержка на 50 миллисекунд, после чего работа бесконечного цикла возобновляется с самого начала:

Thread.sleep(50);




Перед запуском бесконечного цикла отображения символов строки метод run получает контекст отображения и устанавливает в нем параметры шрифта в соответствии со значениями, переданными аплету через документ HTML.

Прежде всего, метод run получает контекст отображения:

Graphics g = getGraphics();

Затем в этом контексте отображения устанавливается шрифт с жирным, наклонным или обычным начертанием:

if(m_style.equals("BOLD"))

  g.setFont(new Font(m_Fnt, Font.BOLD, m_size));

else if(m_style.equals("ITALIC"))

  g.setFont(new Font(m_Fnt, Font.ITALIC, m_size));

else

  g.setFont(new Font(m_Fnt, Font.PLAIN, m_size));

Обратите внимание, что название шрифта передается конструктору класса Font через первый параметр, а размер символов - через последний.

В зависимости от содержимого поля m_color метод run устанавливает один из трех цветов для отображения символов текстовой строки:

if(m_color.equals("red"))

  g.setColor(Color.red);

else if(m_color.equals("green"))

  g.setColor(Color.green);

else

  g.setColor(Color.black);

Помимо этого, до запуска цикла метод run получает размеры окна аплета и метрики шрифта, только что установленного в контексте отображения:

Dimension dimAppWndDimension = size();

FontMetrics fm = g.getFontMetrics();

В переменную nCurrentChar, хранящую номер текущего отображаемого символа, записывается нулевое значение.

Кроме того, вычисляется позиция для рисования строки по вертикальной оси yPos и устанавливается начальная позиция первого символа строки по горизонтальной оси nCurrentXPos:

int yPos = fm.getHeight() + 5;

int nCurrentXPos = 10;

Далее метод run запускает бесконечный цикл рисования символов.

Первое, что метод run делает в этом цикле, это вычисление ширины текущего символа, сохраняя ее в переменной nCurrentCharWidth:

nCurrentCharWidth =

  fm.charWidth(m_Str.charAt(nCurrentChar));

Текущий символ извлекается из строки при помощи метода charAt, определенном в классе String. Ширина извлеченного таким образом символа символа определяется методом charWidth из класса метрик шрифта FontMetrics.




Метод 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 (и, следовательно, работа созданной для него задачи) заканчивается:



Содержание раздела