2a9cfd0b

Метод 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.




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

С этим, однако, есть небольшая сложность - метод drawString не может отображать отдельные символы. Поэтому мы должны создать строку, состоящую из одного символа и передать эту строку методу drawString.

Эта задача решается достаточно просто.

Прежде всего, мы определяем массив, состоящий из одного символа, и временную текстовую строку s:

char[] ch;

String s;

ch = new char[1];

В самый первый элемент массива мы записываем текущий символ:

ch[0] = m_Str.charAt(nCurrentChar);

Затем мы создаем строку из массива, пользуясь конструктором, специально предусмотренным для этой цели в классе String:

s = new String(ch);

Все! Теперь можно отображать строку, состоящую из одного символа, в текущей позиции:

g.drawString(s, nCurrentXPos, yPos);

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

nCurrentXPos += nCurrentCharWidth;

nCurrentChar++;

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

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


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