3. Рисование в окне аплета

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

Контекст отображения

Способ, которым аплет выполняет рисование в своем окне, полностью отличается от того, которым пользуются программы MS-DOS. Вместо того чтобы обращаться напрямую или через драйвер к регистрам видеоконтроллера, аплет пользуется методами из класса Graphics. Эти методы инкапсулируют все особенности аппаратуры, предоставляя в распоряжение программиста платформно-независимое средство рисования.

Для окна аплета создается объект класса Graphics, ссылка на который передается методу paint. В предыдущей главе мы уже пользовались этим объектом, вызывая для него метод drawString, рисующий в окне текстовую строку. Объект, ссылка на который передается методу paint, и есть контекст отображения. Сейчас мы займемся контекстом отображения вплотную.

Полотно для рисования

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

Методы класса Graphics

В качестве базового для класса Graphics (полное название класса java.awt.Graphics) выступает классс java.lang.Object. В виду важности класса Graphics мы приведем его определение с комментариями:

public abstract class java.awt.Graphics
  extends java.lang.Object
{
  // -----------------------------------------------------
  // Конструктор
  // -----------------------------------------------------
  
  protected Graphics();	

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Стирание содержимого прямоугольной области
  public abstract void 
    clearRect(int x, int y, int width, int height);

  // Задание области ограничения вывода
  public abstract void 
    clipRect(int x, int y, int width, int height);

  // Копирование содержимого прямоугольной области
  public abstract void	
    copyArea(int x, int y, int width,
             int height, int dx, int dy);

  // Создание контекста отображения
  public abstract Graphics create();

  // Создание контекста отображения
  public Graphics create(int  x, int  y,	
    int  width, int  height);    

  // Удаление контекста отображения
  public abstract void dispose();
  
  // Рисование прямоугольной области с трехмерным 
  // выделением
  public void draw3DRect(int  x, int  y, int  width,	
    int  height, boolean  raised);

  // Рисование сегмента
  public abstract void drawArc(int x, int y, 
    int width, int height, int startAngle, int arcAngle);

  // Рисование текста из массива байт
  public void drawBytes(byte data[], int offset,	
    int length, int x, int y);

  // Рисование текста из массива символов
  public void drawChars(char  data[], int  offset,	
    int length, int x, int y);

  // Рисование растрового изображения
  public abstract boolean	
    drawImage(Image img, int x, int y, Color bgcolor,
      ImageObserver observer);

  // Рисование растрового изображения
  public abstract boolean	
    drawImage(Image img, int x, int y,
      ImageObserver observer);

  // Рисование растрового изображения
  public abstract boolean	
    drawImage(Image img, int x, int y,
      int width, int height, Color bgcolor,
      ImageObserver observer);

  // Рисование растрового изображения
  public abstract boolean	
    drawImage(Image  img, int  x, int  y,
      int  width, int  height, ImageObserver  observer);

  // Рисование линии
  public abstract void drawLine(int x1, int y1,	
    int x2, int y2);

  // Рисование овала
  public abstract void drawOval(int x, int y,	
    int width, int height);

  // Рисование многоугольника
  public abstract void	
    drawPolygon(int xPoints[], int yPoints[], int nPoints);

  // Рисование многоугольника
  public void drawPolygon(Polygon p);	

  // Рисование прямоугольника
  public void drawRect(int x, int y,	
    int width, int height);

  // Рисование прямоугольника с круглыми углами
  public abstract void
    drawRoundRect(int  x, int  y, int  width,
      int height, int arcWidth, int arcHeight);

  // Рисование текстовой строки
  public abstract void	
    drawString(String str, int x, int y);

  // Рисование заполненного прямоугольника с
  // трехмерным выделением
  public void
    fill3DRect(int x, int y, int width,
      int height, boolean raised);

  // Рисование заполненного сегмента круга
  public abstract void	
    fillArc(int x, int y, int width,
      int height, int startAngle, int arcAngle);

  // Рисование заполненного овала
  public abstract void
    fillOval(int x, int y, int width, int height);

  // Рисование заполненного многоугольника
  public abstract void
    fillPolygon(int xPoints[], int yPoints[], int nPoints);

  // Рисование заполненного многоугольника
  public void fillPolygon(Polygon p);	

  // Рисование заполненного прямоугольника
  public abstract void	
    fillRect(int x, int y, int width, int height);

  // Рисование заполненного прямоугольника
  // с круглыми углами
  public abstract void	
    fillRoundRect(int x, int y, int width, int height, 
      int arcWidth, int arcHeight);

  // Прослеживание вызова метода dispose
  public void finalize();	

  // Определение границ области ограничения вывода
  public abstract Rectangle getClipRect();	

  // Определение цвета, выбранного в контекст отображения
  public abstract Color getColor();

  // Определение шрифта, выбранного в контекст отображения
  public abstract Font getFont();

  // Определение метрик текущего шрифта
  public FontMetrics getFontMetrics();	

  // Определение метрик заданного шрифта
  public abstract FontMetrics getFontMetrics(Font f);	

  // Установка цвета для рисования в контексте отображения
  public abstract void setColor(Color c);

  // Установка текущего шрифта в контексте отображения
  public abstract void setFont(Font font);	

  // Установка режима рисования
  public abstract void setPaintMode();	

  // Установка маски для рисования
  public abstract void setXORMode(Color c1);	

  // Получение текстовой строки, представляющей
  // данный контекст отображения
  public String toString();	

  // Сдвиг начала системы координат 
  // в контексте отображения
  public abstract void translate(int x, int y);	
}

Рассмотрим назначение основных методов, сгруппировав их по выполняемым функциям.

Установка атрибутов контекста отображения

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

Выбор цвета

Изменение цвета, выбранного в контекст отображения, выполняется достаточно часто. В классе Graphics для изменения цвета определен метод setColor, прототип которого представлен ниже:

public abstract void setColor(Color c);

В качестве параметра методу setColor передается ссылка на объект класса Color, с помощью которого можно выбрать тот или иной цвет.

Как задается цвет?

Для этого можно использовать несколько способов.

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

Объект Цвет
public final static Color black; черный
public final static Color blue; голубой
public final static Color cyan; циан
public final static Color darkGray; темно-серый
public final static Color gray; серый
public final static Color green; зеленый
public final static Color lightGray; светло-серый
public final static Color magenta; малиновый
public final static Color orange; оранжевый
public final static Color pink; розовый
public final static Color red; красный
public final static Color white; белый
public final static Color yellow; желтый

Этим набором цветов пользоваться очень просто:

public void paint(Graphics g)
{
  // Выбираем в контекст отображения желтый цвет
  g.setColor(Color.yellow);
  g.drawString("Привет из аплета!", 10, 20);
  . . .
}

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

Если необходима более точная установка цвета, вы можете воспользоваться одним из трех конструкторов объекта Color:

public Color(float r, float g, float b);
public Color(int r, int g, int b);
public Color(int rgb);

Первые два конструктора позволяют задавать цвет в виде совокупности значений трех основных цветовых компонент - красной, желтой и голубой (соотвестсвенно, параметры r, g и b). Для первого конструктора диапазон возможных значений компонент цвета находится в диапазоне от 0.0 до 1.0, а для второго - в диапазоне от 0 до 255.

Третий конструктор также позволяет задавать отдельные компоненты цвета, однако они должны быть скомбинированы в одной переменной типа int. Голубая компонента занимает биты от 0 до 7, зеленая - от 8 до 15, красная - от 16 до 23.

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

g.setColor(new Color(0, 128, 128));

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

Метод Описание
public Color brighter(); Установка более светлого варианта того же цвета
public Color darker(); Установка более темного варианта того же цвета
public boolean equals(
Object obj);
Проверка равенства цветов текущего объекта и объекта, заданного параметром
public int getBlue(); Определение голубой компоненты цвета (в диапазоне от 0 до 255)
public int getRed(); Определение красной компоненты цвета (в диапазоне от 0 до 255)
public int getGreen(); Определение зеленой компоненты цвета (в диапазоне от 0 до 255)
getHSBColor(float h, float s,
float b);
Определение компонент оттенка, насыщенности и яркости (схема HSB)
public int getRGB(); Определение компонент RGB для цвета, выбранного в контекст отображения
public static int
HSBtoRGB(float hue,
float saturation,
float brightness);
Преобразование цветового представления из схемы HSB в схему RGB
public static float[]
RGBtoHSB(int r, int g,
int b, float hsbvals[]);
Преобразование, обратное выполняемому предыдущей функцией
public String toString(); Получение текстовой строки названия цвета

Второй способ установки цвето фона и изображения заключается в вызове методов setBackground и setForeground, например:

setBackground(Color.yellow);
setForeground(Color.black);

Здесь мы устанавливаем для окна аплета желтый цвет фона и черный цвет изображения.

Выбор шрифта

С помощью метода setFont из класса Graphics вы можете выбрать в контекст отображения шрифт, который будет использоваться методами drawString, drawBytes и drawChars для рисования текста. Вот прототип метода setFont:

public abstract void setFont(Font font);

В качестве параметра методу setFont следует передать объект класса Font:

public class java.awt.Font
  extends java.lang.Object
{
  // -----------------------------------------------------
  // Поля класса
  // -----------------------------------------------------
  protected String name;	
  protected int size; 
  protected int style; 

  // Битовые маски стиля шрифта  
  public final static int BOLD;	
  public final static int ITALIC;	
  public final static int PLAIN	

  // -----------------------------------------------------
  // Конструктор
  // -----------------------------------------------------
  public Font(String  name, int  style, int  size);

  // -----------------------------------------------------
  // Методы  
  // -----------------------------------------------------
  
  // Сравнение шрифтов
  public boolean equals(Object  obj);	

  // Определение названия семейства шрифтов
  public String getFamily();

  // Получение шрифта по его характеристикам
  public static Font getFont(String  nm); 
  public static Font getFont(String  nm, Font  font);

  // Определение названия шрифта
  public String getName();

  // Определение размера шрифта
  public int getSize();

  // Определение стиля шрифта
  public int getStyle();	

  // Получение хэш-кода шрифта
  public int hashCode();

  // Определение жирности шрифта
  public boolean isBold();

  // Проверка, является ли шрифт наклонным
  public boolean isItalic();

  // Проверка, есть ли шрифтовое выделение
  public boolean isPlain();

  // Плучение текстовой строки для объекта
  public String toString();
}

Создавая шрифт конструктором Font, вы должны указать имя, стиль и размер шрифта.

В качестве имени можно указать, например, строки Arial или Courier. Учтите, что в системе удаленного пользователя, загрузившего ваш аплет, может не найтись шрифта с указанным вами именем. В этом случае навигатор заменит его на наиболее подходящий (с его точки зрения).

Стиль шрифта задается масками BOLD, ITALIC и PLAIN, которые можно комбинировать при помощи логической операции “ИЛИ”:

Маска Описание
BOLD Утолщенный шрифт
ITALIC Наклонный шрифт
PLAIN Шрифтовое выделение не используется

Что же касается размера шрифта, то он указывается в пикселах.

Установка режима рисования

Метод setPaintMode устанавливает в контексте отображения режим рисования, при котором выполняется замещение изображения текущим цветом, установленном в контексте отображения.

Прототип метода setPaintMode приведен ниже:

public abstract void setPaintMode();

Установка маски для рисования

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

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

Прототип метода setXORMode:

public abstract void setXORMode(Color c1);

Сдвиг начала системы координат

Метод translate сдвигает начало системы координат в контексте отображения таким образом, что оно перемещается в точку с координатами (x, y), заданными через параметры метода:

public abstract void translate(int x, int y);	

Определение атрибутов контекста отображения

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

Рассмотрим методы, позволяющие определить атрибуты контекста отображения.

Определение границ области ограничения вывода

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

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

public abstract Rectangle getClipRect();

Метод возвращает ссылку на объект класса Rectangle, который, в частности, имеет поля класса с именами x, y, height и width. В этих полях находится, соответственно, координаты верхнего левого угла, высота и ширина прямоугольной области.

Определение цвета, выбранного в контекст отображения

Метод getColor возвращает ссылку на объект класса Color, представляющий текущий цвет, выбранный в контекст отображения:

public abstract Color getColor();

Определение шрифта, выбранного в контекст отображения

С помощью метода getFont, возвращающего ссылку на объект класса Font, вы можете определить текущий шрифт, выбранный в контекст отображения:

public abstract Font getFont();

Определение метрик текущего шрифта

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

Метрики текущего шрифта в контексте отображения вы можете узнать при помощи метода getFontMetrics, прототип которого приведен ниже:

public FontMetrics getFontMetrics();	

Метод getFontMetrics возвращает ссылку на объект класса FontMetrics. Ниже мы привели список наиболее важных методов этого класса, предназначенных для получения отдельных параметров шрифта:

Метод Описание
public Font getFont(); Определение шрифта, который описывается данной метрикой
public int bytesWidth(
byte data[],
int off, int len);
Метод возвращает ширину строки символов, расположенных в массиве байт data. Параметры off и len задают, соответственно, смещение начала строки в массиве и ее длину
public int charsWidth(
char data[],
int off, int len);
Метод возвращает ширину строки символов, расположенных в массиве символов data. Параметры off и len задают, соответственно, смещение начала строки в массиве и ее длину
public int charWidth(
char ch);
Метод возвращает ширину заданного символа
public int charWidth(
int ch);
Метод возвращает ширину заданной строки символов
public int getAscent(); Определение расстояния от базовой линии до верхней выступающей части символов
public int getDescent(); Определение расстояния от базовой линии до нижней выступающей части символов
public int getLeading(); Расстояние между строками текста
public int getHeight(); Определение полной высоты символов, выполняется по формуле:
getLeading() + getAscent() + getDescent()
public int
getMaxAdvance();
Максимальная ширина символов в шрифте
public int getMaxAscent(); Максимальное расстояние от базовой линии до верхней выступающей части символов для символов данного шрифта
public int
getMaxDescent();
Максимальное расстояние от базовой линии до нижней выступающей части символов для символов данного шрифта
public int[] getWidths(); Массив ширин первых 256 символов в шрифте
public int
stringWidth(String str);
Ширина строки, передаваемой методу в качестве параметра
public String toString(); Тектовая строка, которая представляет данную метрику шрифта

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

Для определения полной высоты строки символов вы можете воспользоваться методом getHeight.

Определение метрик заданного шрифта

Метод getFontMetrics с параметром типа Font позволяет определить метрики любого шрифта, передаваемого ему в качетсве параметра:

public abstract FontMetrics getFontMetrics(Font f);

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

Рисование геометрических фигур

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

Линии

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

public abstract void drawLine(int x1, int y1,	
  int x2, int y2);

Концы линии имеют координаты (x1, y1) и (x2, y2), как это показано на рис. 3.1.

Рис. 3.1. Рисование прямой линии

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

Прямоугольники и квадраты

Среди методов класса Graphics есть несколько, предназначенных для рисования прямоугольников. Первый из них, с именем drawRect, позволяет нарисовать прямоугольник, заданный координатами своего левого вернего угла, шириной и высотой:

public void drawRect(int x, int y,	
    int width, int height);

Параметры x и y задают, соответственно, координаты верхнего левого угла, а параметры width и height - высоту и ширину прямоугольника (рис. 3.2).

Рис. 3.2. Рисование прямоугольника

В отличие от метода drawRect, рисующего только прямоугольную рамку, метод fillRect рисует заполненный прямоугольник. Для рисования и заполнения прямоугольника используется цвет, выбранный в контекст отображения (рис. 3.3).

Прототип метода fillRect приведен ниже:

public abstract void	
    fillRect(int x, int y, int width, int height);

Рис. 3.3. Рисование заполненного прямоугольника

Метод drawRoundRect позволяет нарисовать прямоугольник с закругленными углами:

public abstract void
    drawRoundRect(int  x, int  y, int  width,
      int height, int arcWidth, int arcHeight);

Параметры x и y определяют координаты верхнего левого угла прямоугольника, параметры width и height задают, соответственно его ширину и высоту.

Размеры эллипса, образующего закругления по углам, вы можете задать с помощью параметров arcWidth и arcHeight. Первый из них задает ширину эллипса, а второй - высоту (рис. 3.4).

Рис. 3.4. Рисование прямоугольника с закругленными углами

Метод fillRoundRect позволяет нарисовать заполненный прямоугольник с закругленными углами (рис. 3.5). Назначение параметров этого метода аналогично назначению параметров только что рассмотренного метода drawRoundRect:

public abstract void	
    fillRoundRect(int x, int y, int width, int height, 
      int arcWidth, int arcHeight);

Рис. 3.5. Рисование заполненного прямоугольника с закругленными углами

Метод fill3Drect предназначен для рисования выступающего или западающего прямоугольника:

public void
  fill3DRect(int x, int y, int width,
    int height, boolean raised);

Если значение параметра raised равно true, рисуется выступающий прямоугольник, если false - западающий. Назначение остальных параметров аналогично назначению параметров метода drawRect.

Многоугольники

Для рисования многоугольников в классе Graphics предусмотрено четыре метода, два из которых рисуют незаполненные многоугольники, а два - заполненные.

Первый метод рисует незаполненный многоугольник, заданный массивами координат по осям X и Y:

public abstract void	
    drawPolygon(int xPoints[], int yPoints[], int nPoints);

Через параметры xPoints и yPoints передаются, соответственно, ссылки на массивы координат по оис X и Y. Параметр nPoints задает количество точек в массивах.

На рис. 3.6 показан многоугольник, нарисованный методом drawPolygon.

Рис. 3.6. Многоугольник, нарисованный методом drawPolygon

В этом многоугольнике шесть вершин с координатами от (x0, y0) до (x5, y5), причем для того чтобы он стал замкнутым,координаты первой и последней вершины совпадают.

Второй метод также рисует незаполненный многоугольник, однако в качетсве параметра методу передается ссылка на объект Polygon:

public void drawPolygon(Polygon p);

Класс Polygon достаточно прост, поэтому мы приведем его описание полностью:

public class java.awt.Polygon
  extends java.lang.Object
{
  // -----------------------------------------------------
  // Поля класса
  // -----------------------------------------------------
  public int npoints;    // количество вершин
  public int xpoints[];  // массив координат по оси X
  public int ypoints[];  // массив координат по оси Y

  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------
  public Polygon();
  public Polygon(int xpoints[], int ypoints[], int npoints);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Добавление вершины 
  public void addPoint(int  x, int  y);

  // Получение координат охватывающего прямоугольника
  public Rectangle getBoundingBox();

  // Проверка, находится ли точка внутри многоугольника
  public boolean inside(int x, int y);
}

Ниже мы показали фрагмент кода, в котором создается многоугольник, а затем в него добавляется несколько точек. Многоугольник рисуется методом drawPolygon:

Polygon p = new Polygon();
p.addPoint(270, 239);
p.addPoint(350, 230);
p.addPoint(360, 180);
p.addPoint(390, 160);
p.addPoint(340, 130);
p.addPoint(270, 239);
g.drawPolygon(p);

Если вам нужно нарисовать заполненный многоугольник (рис. 3.7), то для этого вы можете воспользоваться методами, приведенными ниже:

public abstract void
    fillPolygon(int xPoints[], int yPoints[], int nPoints);
public void fillPolygon(Polygon p);

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

Рис. 3.6. Многоугольник, нарисованный методом drawPolygon

Овалы и круги

Для рисования окружностей и овалов вы можете воспользоваться методом drawOval:

public abstract void drawOval(int x, int y,	
    int width, int height);

Параметры этого методы задают координаты и размеры прямоугольника, в который вписывается рисуемый овал (рис. 3.7).

Рис. 3.7. Рисование овала

Метод fillOval предназначен для рисования заполненного овала (рис. 3.8). Назначение его параметров аналогично назначению параметров метода drawOval:

public abstract void
    fillOval(int x, int y, int width, int height);

Рис. 3.7. Рисование заполненного овала

Сегменты

Метод drawArc предназначен для рисования незаполненного сегмента (рис. 3.8). Прототип этого метода приведен ниже:

public abstract void drawArc(int x, int y, 
    int width, int height, int startAngle, int arcAngle);

Рис. 3.8. Рисование незаполненного сегмента

Параметры x, y, width и height задают координаты прямоугольника, в который вписан сегмент.

Параметры startAngle и arcAngle задаются в градусах. Они определяют, соответственно, начальный угол и угол разворота сегмента.

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

public abstract void	
    fillArc(int x, int y, int width,
      int height, int startAngle, int arcAngle);

Задание области ограничения

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

public abstract void 
    clipRect(int x, int y, int width, int height);

Параметры x, y, width и height задают координаты прямоугольной области ограничения.

Копирование содержимого прямоугольной области

Метод copyArea позволяет скопировать содержимое любой прямоугольной области окна аплета:

public abstract void	
  copyArea(int x, int y, int width,
    int height, int dx, int dy);

Параметры x, y, width и height задают координаты копируемой прямоугольной области. Область копируется в другую прямоугольную область такого же размера, причем параметры dx и dy определяют координаты последней.

Приложение Painter

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

Внешний вид окна аплета при просмотре соответствующего документа HTML навигатором Microsoft Internet Explorer показано на рис. 3.9.

Рис. 3.9. Окно аплета Painter

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

Исходные файлы приложения Painter

В листинге 3.1 мы привели исходный текст аплета Painter.

Листинг 3.1. Файл Painter\Painter.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 Painter extends Applet
{
  // -------------------------------------------------------
  // Painter
  // Конструктор не используется
  // -------------------------------------------------------
  public Painter()
  {
  }

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: Painter\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";
  }

  // -------------------------------------------------------
  // init
  // Вызывается во время инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Для того чтобы размеры окна аплета можно было
    // задавать в документе HTML, закрываем следующую
    // строку символом комментария

    // resize(320, 240);
  }

  // -------------------------------------------------------
  // destroy
  // Метод destroy не используется
  // -------------------------------------------------------
  public void destroy()
  {
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();

    // Эта строка будет удалена из окна аплета
    // методом clearRect
    g.drawString("Невидимая строка", 10, 20);
 
    // Стираем содержимое окна аплета. Цвет окна
    // становится таким же, как и цвет фона
    // окна навигатора
    g.clearRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);
    
    // Выбираем в контекст отображения желтый цвет
    g.setColor(Color.yellow);
    
    // Закрашиваем внутреннюю область окна аплета
    g.fillRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Пишем строку в верхнем левом углу окна аплета
    g.drawString("Привет из аплета!", 10, 20);

    // Рисуем в цикле пять горизонтальных линий
    for(int i = 0; i < 5; i++)
    {
      g.drawLine(10, 30 + (i * 10), 200, 30 + (i * 10));
    }

    // Копируем область окна, занятую 
    // нарисованными линиями
    g.copyArea(10, 30, 200, 50, 220, 0);

    // Выбираем в контекст отображения белый цвет
    g.setColor(Color.white);

    // Закрашиваем белвым цветом нижнюю часть окна
    g.fillRect(1, 80, 
      dimAppWndDimension.width  - 2, 
      dimAppWndDimension.height - 81);
    
    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем два трехмерных прямоугольника
    g.draw3DRect(10,  100, 100, 20, true);
    g.draw3DRect(120, 100, 100, 20, false);
  
    // Выбираем в контекст отображения красный цвет
    g.setColor(Color.red);
    
    // Рисуем рамку, в которую будет вписан сегмент
    g.drawRect(10, 140, 200, 100);
    g.drawLine(10, 190, 210, 190);
    g.drawLine(110, 140, 110, 240);

    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем сегмент
    g.drawArc(10, 140, 200, 100, -25, 320);

    // Создаем многоугольник
    Polygon p = new Polygon();
  
    // Добавляем в многоугольник несколько вершин
    p.addPoint(270, 239);
    p.addPoint(350, 230);
    p.addPoint(360, 180);
    p.addPoint(390, 160);
    p.addPoint(340, 130);
    p.addPoint(270, 239);

    // Рисуем многоугольник
    g.drawPolygon(p);

    // Рисуем прямоугольник с закругленными углами
    g.drawRoundRect(10, 250, 200, 100, 60, 40);

    // Выбираем в контекст отображения красный цвет
    g.setColor(Color.red);

    // Задаем область ограничения вывода
    g.clipRect(260, 250, 200, 100);
 
    // Рисуем круг, пересекающий область ограничения
    g.fillOval(300, 200, 170, 170);
  }

  // -------------------------------------------------------
  // start
  // Метод start не используется
  // -------------------------------------------------------
  public void start()
  {
  }
	
  // -------------------------------------------------------
  // stop
  // Метод stop не используется
  // -------------------------------------------------------
  public void stop()
  {
  }
}

Листинг 3.2 содержит исходный текст документа HTML, в который встроен данный аплет.

Листинг 3.2. Файл Painter\Painter.html

<html>
<head>
<title>Painter</title>
</head>
<body>
<hr>
<applet
    code=Painter.class
    id=Painter
    width=500
    height=400>
</applet>
<hr>
<a href="Painter.java">The source.</a>
</body>
</html>

Мы внесли небольшие изменения в файл Painter.html, подготовленный системой Java Applet Wizard. Эти изменения заключаются в увеличении размеров окна аплета, задаваемых параметрами WIDTH и HEIGHT оператора <APPLET>.

Метод init

Аплет Painter был создан с помощью системы Java Applet Wizard. Мы выполнили изменения методов init, getAppletInfo и paint.

Изменения метода init заключаются в том, что мы закрыли символом комментария строку установки размеров окна аплета:

public void init()
  {
    // resize(320, 240);
  }

Это позволяет задавать размеры окна аплета не в исходном тексте приложения, а в параметрах оператора <APPLET>, с помощью которого аплет встраивается в документ HTML.

Метод getAppletInfo

В методе getAppletInfo изменения невелики: в описание аплета был добавлен наш почтовый адрес E-mail и адрес нашего сервера WWW:

public String getAppletInfo()
{
  return "Name: Painter\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";
}

Метод paint

В обработчик метода paint мы добавили функции рисования.

В самом начале своей работы метод определяет текущие размеры окна аплета, вызывая для этого метод size:

Dimension dimAppWndDimension = size();

Метод size определен в классе Component, от которого в конечном счете наследуется класс Applet и класс нашего приложения Painter. Этот метод возвращает ссылку на объект класса Dimension, хранящего высоту и ширину объекта:

public class java.awt.Dimension
  extends java.lang.Object 
{
  // -----------------------------------------------------
  // Поля класса
  // -----------------------------------------------------
  public int height; // высота
  public int width;  // ширина

  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------
  public Dimension();
  public Dimension(Dimension  d);
  public Dimension(int  width, int  height);

  // -----------------------------------------------------
  // Метод
  // -----------------------------------------------------
  public String toString();
}

На следующем шаге после определения размеров окна наше приложение рисует в окне строку, а затем стирает содержимое всего окна:

g.drawString("Невидимая строка", 10, 20);
g.clearRect(0, 0, 
   dimAppWndDimension.width  - 1, 
   dimAppWndDimension.height - 1);

В качестве начальных координат стираемой области мы указали точку (0, 0) - это верхний левый угол окна аплета. Ширина и высота стираемой области задана исходя из размеров аплета, полученных от метода size.

Для того чтобы изменить цвет фона окна, ме его закрашиваем (хотя могли бы воспользоваться и методом setBackground). Это можно сделать методом fillRect. Вначале при помощи метода setColor мы выбираем в контекст отображения желтый цвет, а затем закрашиваем всю внутреннюю область окна аплета методом fillRect:

g.setColor(Color.yellow);
g.fillRect(0, 0, 
  dimAppWndDimension.width  - 1, 
  dimAppWndDimension.height - 1);

На следующем этапе метод paint выбирает в контекст отображения черный цвет и рисует черную рамку вокруг окна аплета, вызывая для этого метод drawRect:

g.setColor(Color.black);
g.drawRect(0, 0, 
  dimAppWndDimension.width  - 1, 
  dimAppWndDimension.height - 1);

Далее при помощи метода drawString обработчик метода paint пишет в верхней части окна аплета строку, которая останется на экране:

g.drawString("Привет из аплета!", 10, 20);

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

for(int i = 0; i < 5; i++)
{
  g.drawLine(10, 30 + (i * 10), 200, 30 + (i * 10));
}
g.copyArea(10, 30, 200, 50, 220, 0);

Для рисования линий мы здесь вызываем метод drawLine.

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

g.setColor(Color.white);
g.fillRect(1, 80, 
  dimAppWndDimension.width  - 2, 
  dimAppWndDimension.height - 81);

Ширина и высота закрашиваемой области здесь указана с учетом наличия черной рамки толщиной в 1 пиксел вокруг окна аплета.

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

g.setColor(Color.black);
g.draw3DRect(10,  100, 100, 20, true);
g.draw3DRect(120, 100, 100, 20, false);

Затем мы приступаем к рисованию сегмента.

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

g.setColor(Color.red);
g.drawRect(10, 140, 200, 100);
g.drawLine(10, 190, 210, 190);
g.drawLine(110, 140, 110, 240);

Рамка разделена по горизонтали и по вертикали красными линиями.

Далее мы выбираем в контекст отображения черный цвет и рисуем сегмент:

g.setColor(Color.black);
g.drawArc(10, 140, 200, 100, -25, 320);

Обратите внимание, что начальный угол сегмента имеет отрицательное значение. Угол сегмента составляет 320 градусов.

Следующий шаг - создание и рисование многоугольника.

Многоугольник создается как объект класса Polygon. К этому объекту с помощью метода addPoint мы добавляем несколько точек:

Polygon p = new Polygon();
p.addPoint(270, 239);
p.addPoint(350, 230);
p.addPoint(360, 180);
p.addPoint(390, 160);
p.addPoint(340, 130);
p.addPoint(270, 239);

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

После подготовки многоугольника он рисуется при помощи метода drawPolygon:

g.drawPolygon(p);

Наш аплет рисует также прямоугольник с закругленными углами, вызыая метод drawRoundRect:

g.drawRoundRect(10, 250, 200, 100, 60, 40);

Ширина и высота эллипсов закругления составляет, соответственно, 60 и 40 пикселов.

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

g.clipRect(260, 250, 200, 100);

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

g.fillOval(300, 200, 170, 170);

Приложение FontList

Наше следующее приложение отображает список шрифтов, доступных в системе. Окно аплета этого приложения, запущенного в среде Microsoft Internet Explorer, работающего в Microsoft Windows NT версии 4.0, показано на рис. 3.10.

Рис. 3.10. Окно аплета со списком доступных шрифтов

Возможно, этот список покажется вам несколько необычным. В самом деле, давайте заглянем в папку Fonts, которую можно найти в папке Control Panel XE "Control Panel" . Беглого взгляда достаточно для того, чтобы убедиться - список шрифтов, доступных аплету XE "список шрифтов, доступных аплету" , не совпадает со списком шрифтов, установленных в системе (рис. 3.11).

Рис. 3.11. Список шрифтов, установленных в системе Microsoft Windows NT

Задавая имена шрифтов в конструкторе класса Font, вы должны использовать имена шрифтов, доступные аплету, а не имена шрифтов, установленных в системе. Наш аплет FontList извлекает и отображает список доступных для него шрифтов.

Исходный текст приложения

Исходный текст приложения представлен в листинге 3.3.

Листинг 3.3. Файл FontList\FontList.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 FontList extends Applet
{
  // -------------------------------------------------------
  // Поля класса
  // -------------------------------------------------------
  Toolkit toolkit;   // ссылка на Toolkit
  String  fntlist[]; // список шрифтов
  int yStart = 20;  // координата Y начала области вывода
  int yStep;        // шаг вывода строк с названиями шрифтов

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: FontList\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";
  }

  // -------------------------------------------------------
  // init
  // Вызывается во время инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Получаем ссылку на Toolkit
    toolkit = Toolkit.getDefaultToolkit();
    
    // Получаем список доступных шрифтов
    fntlist = toolkit.getFontList();
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем метрики шрифта
    FontMetrics fm = g.getFontMetrics();

    // Устанавливаем шаг вывода строк по вертикали
    // равным полной высоте символов текущего шрифта
    yStep = fm.getHeight();

    // Устанавливаем новую высоту аплета исходя
    // из количества элементов в списке шрифтов
    resize(150, 20 + yStep * fntlist.length);

    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения желтый цвет
    g.setColor(Color.yellow);
    
    // Закрашиваем внутреннюю область окна аплета
    g.fillRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);
    
    // Выводим в цикле список установленных шрифтов
    for(int i = 0; i < fntlist.length; i++)
    {
      g.drawString(fntlist[i], 10, yStart + yStep * i);
    }
  }
}

В листинге 3.4 вы найдете исходный текст документа HTML, в который встроен наш аплет.

Листинг 3.4. Файл FontList\FontList.html

<html>
<head>
<title>FontList</title>
</head>
<body>
<hr>
<applet
    code=FontList.class
    id=FontList
    width=320
    height=240 >
</applet>
<hr>
<a href="FontList.java">The source.</a>
</body>
</html>

Описание исходного текста

Наиболее важными для нас являются методы init и paint.

Метод init

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

Toolkit toolkit;   // ссылка на Toolkit
String  fntlist[]; // список шрифтов
. . .
public void init()
{
  toolkit = Toolkit.getDefaultToolkit();
  fntlist = toolkit.getFontList();
}

Аплет вызывает статический метод getDefaultToolkit из класса Toolkit и затем, пользуясь полученной ссылкой, извлекает список шрифтов, записывая его в массив fntlist.

Для чего еще можно использовать класс Toolkit?

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

Создавая свои аплеты, вы будете редко прибегать к услугам этого класса. Однако в нем есть несколько полезных методов, прототипы которых мы перечислим ниже:

public  abstract  class  java.awt.Toolkit
    extends  java.lang.Object
{
  // -----------------------------------------------------
  // Конструктор
  // -----------------------------------------------------
  public Toolkit();

  // -----------------------------------------------------
  // Методы (сокращенный список)
  // -----------------------------------------------------
  . . .

  // Получение ссылки на Toolkit
  public static Toolkit getDefaultToolkit();	

  // Определение текущей цветовой модели,
  // выбранной в контекст отображения
  public abstract ColorModel getColorModel();	

  // Получение списка шрифтов, доступных аплету 
  public abstract String[] getFontList();

  // Получение метрик заданного шрифта
  public abstract FontMetrics getFontMetrics(Font  font);

  // Получение растрового изображения по имени файла
  public abstract Image getImage(String  filename);

  // Получение растрового изображения по адресу URL
  public abstract Image getImage(URL  url);	

  // Определение разрешения экрана в точках на дюйм
  public abstract int getScreenResolution();

  // Размеры экрана в пикселах
  public abstract Dimension getScreenSize();

  // Подготовка растрового изображения для вывода
  public abstract boolean
    prepareImage(Image image, int width, int height,
      ImageObserver observer);

  // Синхронизация состояния Toolkit
  public abstract void sync();
}

Наиболее интересны, с нашей точки зрения, методы getFontList, getScreenResolution и getScreenSize, с помощью которых аплет может, соответственно, плучить список шрифтов, определить разрешение и размер экрана. Последние два параметра позволяют сформировать содержимое окна аплета оптимальным образом исходя из объема информации, который может в нем разместиться.

Метод paint

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

FontMetrics fm = g.getFontMetrics();
yStep = fm.getHeight();

Зная высоту шрифта и количество элементов в списке доступных шрифтов, мы можем изменить размер окна аплета по вертикали таким образом, чтобы в нем поместились все строки. Количество элементов в массиве fntlist равно fntlist.length, а полную высоту шрифта мы только что определили. Для изменения высоты окна аплета мы используем метод resize:

resize(150, 20 + yStep * fntlist.length);

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

Dimension dimAppWndDimension = size();
g.setColor(Color.yellow);
g.fillRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);
g.setColor(Color.black);
g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

Эту операцию мы уже выполняли в предыдущем приложении.

Список установленных шрифтов выводится достаточно просто в цикле:

for(int i = 0; i < fntlist.length; i++)
{
  g.drawString(fntlist[i], 10, yStart + yStep * i);
}

Здесь содержимое параметра цикла (переменной i) меняется от 0 до количества элементов в массиве length. Каждая новая строка рисуется со смещением, равным полной высоте символов текущего шрифта, выбранного в контекст отображения.

Приложение TextOut

До сих пор наши аплеты не получали параметров из документов HTML, в которые мы их встраивали. Конечно, все константы, текстовые строки, адреса URL и другую информацию можно закодировать непосредственно в исходном тексте аплета, однако, очевидно, это очень неудобно.

Пользуясь операторами <PARAM>, расположенными в документе HTML сразу после оператора <APPLET>, можно передать аплету произвольное количество параметров, например, в виде текстовых строк:

<applet
    code=TextOut.class
    id=TextOut
    width=320
    height=240 >
    <param name=ParamName1 value="Param Value 1">
    <param name=ParamName2 value="Param Value 2">
    <param name=ParamName3 value="Param Value 3">
    <param name=ParamName4 value="Param Value 4">
     . . .
</applet>

Здесь через параметр NAME оператора <PARAM> передается имя параметра аплета, а через параметр VALUE - значение соответствующего параметра.

Как параметр может получить значение параметров?

Для получения значения любого параметра аплет должен использовать метод getParameter. В качестве единственного параметра этому методу передается имя параметра аплета в виде строки типа String, например:

private String m_ParamName1;
private final String PARAM_ ParamName1= "ParamName1";
String param;

param = getParameter(PARAM_ParamName1);
if (param != null)
  m_ParamName1 = param;

Если вы создаете аплет с помощью системы Java Applet Wizard, то в четвертой диалоговой панели вам предоставляется возможность определить все параметры, передаваемые аплету (рис. 3.12).

Рис. 3.12. Определение параметров аплета (список параметров уже заполнен)

Первоначально список параметров, отображаемых в четвертой диалоговой панели системы Java Applet Wizard, пуст. Такую панель мы показывали раньше на рис. 2.11.

Для добавления нового параметра сделайте щелчок левой клавишей мыши в столбце Name по свободному полю, отмеченному пунктирным прямоугольником. На месте этого прямоугольника появится поле редактирования, в котором вы должны ввести имя параметра. После ввода сделайте щелчок вне поля, после чего в списке параметров появится новая строка.

Создавая проект TextOut, мы выполнили эту операцию для всех параметров, за исключением параметра Font4. Этот параметр мы добавили позже в ручном режиме, когда все файлы проекта уже были созданы.

Обратите внимание, что в столбце Member при заполнении списка автоматически появляются имена полей класса, в которые попадут значения параметров.

После завершения формирования списка параметров мы заполнили столбцы Def-Value и Description (рис. 3.13).

Рис. 3.13. Заполнение столбцов Def-Value и Description

Значения из столбца Def-Value будут использованы для инициализации соответствующих полей класса. Что же касается столбца описаний Description, о эта информация может быть извлечена аплетом и проанализирована. Если в документе HTML находится несколько аплетов (что вполне допустимо), другие аплеты также могут получить описание параметров нашего аплета.

Какие параметры получает наш аплет и что он делает, кроме получения значения параметров?

Через параметры с именами Str1 - Str5 передается пять строк, который аплет отображает в своем окне (рис. 3.14).

Рис. 3.14. Отображение строк в окне аплета TextOut

Параметры Font1 - Font5 задают имена шрифтов для отображения этих строк. С помощью параметра Type1 можно задать стиль шрифта первой и второй строки, с помощью параметра Type2 - третьей и четвертой, а с помощью параметра Type3 - стиль шрифта для пятой строки.

Рассмотрим исходный тексты приложения TextOut.

Исходные тексты приложения TextOut

Файл исходного текста приложения TextOut представлен в листинге 3.5.

Листинг 3.5. Файл TextOut\TextOut.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 TextOut extends Applet
{
  // -------------------------------------------------------
  // Поля класса.
  // Создаются автоматически для всех параметров аплета
  // -------------------------------------------------------
  private String m_Str1 = "Hello 1";
  private String m_Str2 = "Hello 2";
  private String m_Str3 = "Hello 3";
  private String m_Str4 = "Hello 4";
  private String m_Str5 = "Hello 5";
  private String m_Font1 = "Arial";
  private String m_Font2 = "Courier";
  private String m_Font3 = "Times";
  private String m_Font4 = "Helvetica";
  private String m_Font5 = "Undefined";
  private String m_Type1 = "Bold";
  private String m_Type2 = "Italic";
  private String m_Type3 = "Plain";

  // -------------------------------------------------------
  // Имена параметров
  // -------------------------------------------------------
  private final String PARAM_Str1 = "Str1";
  private final String PARAM_Str2 = "Str2";
  private final String PARAM_Str3 = "Str3";
  private final String PARAM_Str4 = "Str4";
  private final String PARAM_Str5 = "Str5";
  private final String PARAM_Font1 = "Font1";
  private final String PARAM_Font2 = "Font2";
  private final String PARAM_Font3 = "Font3";
  private final String PARAM_Font4 = "Font4";
  private final String PARAM_Font5 = "Font5";
  private final String PARAM_Type1 = "Type1";
  private final String PARAM_Type2 = "Type2";
  private final String PARAM_Type3 = "Type3";

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: TextOut\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";
  }

  // -------------------------------------------------------
  // getParameterInfo
  // Метод, возвращающий описание параметров
  // -------------------------------------------------------
  public String[][] getParameterInfo()
  {
    String[][] info =
      {
        { PARAM_Str1, "String", "Text string to write" },
        { PARAM_Str2, "String", "Text string to write" },
        { PARAM_Str3, "String", "Text string to write" },
        { PARAM_Str4, "String", "Text string to write" },
        { PARAM_Str5, "String", "Text string to write" },
        { PARAM_Font1, "String", "Text font" },
        { PARAM_Font2, "String", "Text font" },
        { PARAM_Font3, "String", "Text font" },
        { PARAM_Font4, "String", "Text font" },
        { PARAM_Font5, "String", "Text font" },
        { PARAM_Type1, "String", "Font type" },
        { PARAM_Type2, "String", "Font type" },
        { PARAM_Type3, "String", "Font type" },
      };
    return info;		
  }

  // -------------------------------------------------------
  // init
  // Вызывается во время инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Рабочая переменная для получения параметров
    String param;

    // Получение параметров и сохранение
    // их значений в полях класса

    // Строки, которые будут выведены в окно аплета
    param = getParameter(PARAM_Str1);
    if (param != null)
      m_Str1 = param;

    param = getParameter(PARAM_Str2);
    if (param != null)
      m_Str2 = param;

    param = getParameter(PARAM_Str3);
    if (param != null)
      m_Str3 = param;

    param = getParameter(PARAM_Str4);
    if (param != null)
      m_Str4 = param;

    param = getParameter(PARAM_Str5);
    if (param != null)
      m_Str5 = param;

    // Шрифты для отображения строк
    param = getParameter(PARAM_Font1);
    if (param != null)
      m_Font1 = param;

    param = getParameter(PARAM_Font2);
    if (param != null)
      m_Font2 = param;

    param = getParameter(PARAM_Font3);
    if (param != null)
      m_Font3 = param;

    param = getParameter(PARAM_Font4);
    if (param != null)
      m_Font4 = param;

    param = getParameter(PARAM_Font5);
    if (param != null)
      m_Font5 = param;

    // Начертание шрифтов
    param = getParameter(PARAM_Type1);
    if (param != null)
      m_Type1 = param;

    param = getParameter(PARAM_Type2);
    if (param != null)
      m_Type2 = param;

    param = getParameter(PARAM_Type3);
    if (param != null)
      m_Type3 = param;
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Начальная координата для вывода по вертикали
    int yStart   = 20;

    // Текущая координата для вывода строки
    int yCurrent = 20;

    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения желтый цвет
    g.setColor(Color.yellow);
    
    // Закрашиваем внутреннюю область окна аплета
    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_Type1.equals("Bold"))
      g.setFont(new Font(m_Font1, Font.BOLD, 25));

    else if(m_Type1.equals("Italic"))
      g.setFont(new Font(m_Font1, Font.ITALIC, 25));

    else if(m_Type1.equals("Plain"))
      g.setFont(new Font(m_Font1, Font.PLAIN, 25));

    // Отступ для первой строки
    yCurrent += yStart;

    // Рисуем первую строку
    g.drawString(m_Str1, 10, yCurrent);

    // Определяем метрики шрифта
    FontMetrics fm = g.getFontMetrics();

    // Устанавливаем новую текущую позицию для
    // вывода очередной строки
    yCurrent += fm.getHeight();

    // Выбираем шрифт в контекст отображения
    if(m_Type1.equals("Bold"))
      g.setFont(new Font(m_Font2, Font.BOLD, 25));

    else if(m_Type1.equals("Italic"))
      g.setFont(new Font(m_Font2, Font.ITALIC, 25));

    else if(m_Type1.equals("Plain"))
      g.setFont(new Font(m_Font2, Font.PLAIN, 25));

    // Рисуем вторую строку
    g.drawString(m_Str2, 10, yCurrent);

    // Устанавливаем новую текущую позицию для
    // вывода очередной строки
    fm = g.getFontMetrics();
    yCurrent += fm.getHeight();

    // Выбираем шрифт в контекст отображения
    if(m_Type2.equals("Bold"))
      g.setFont(new Font(m_Font3, Font.BOLD, 25));

    else if(m_Type2.equals("Italic"))
      g.setFont(new Font(m_Font3, Font.ITALIC, 25));

    else if(m_Type2.equals("Plain"))
      g.setFont(new Font(m_Font3, Font.PLAIN, 25));

    // Рисуем третью строку
    g.drawString(m_Str3, 10, yCurrent);

    // Устанавливаем новую текущую позицию для
    // вывода очередной строки
    fm = g.getFontMetrics();
    yCurrent += fm.getHeight();

    // Выбираем шрифт в контекст отображения
    if(m_Type2.equals("Bold"))
      g.setFont(new Font(m_Font4, Font.BOLD, 25));

    else if(m_Type2.equals("Italic"))
      g.setFont(new Font(m_Font4, Font.ITALIC, 25));

    else if(m_Type2.equals("Plain"))
      g.setFont(new Font(m_Font4, Font.PLAIN, 25));

    // Рисуем четвертую строку
    g.drawString(m_Str4, 10, yCurrent);

    // Устанавливаем новую текущую позицию для
    // вывода очередной строки
    fm = g.getFontMetrics();
    yCurrent += fm.getHeight();

    // Выбираем шрифт в контекст отображения
    if(m_Type3.equals("Bold"))
      g.setFont(new Font(m_Font5, Font.BOLD, 25));

    else if(m_Type3.equals("Italic"))
      g.setFont(new Font(m_Font5, Font.ITALIC, 25));

    else if(m_Type3.equals("Plain"))
      g.setFont(new Font(m_Font5, Font.PLAIN, 25));

    // Рисуем пятую строку
    g.drawString(m_Str5, 10, yCurrent);
  }
}

Исходный текст документа HTML, в который встроен аплет TextOut, приведен в листинге 3.6.

Листинг 3.6. Файл TextOut\TextOut.html

<html>
<head>
<title>TextOut</title>
</head>
<body>
<hr>
<applet
    code=TextOut.class
    id=TextOut
    width=320
    height=240 >
    <param name=Str1 value="Hello 1">
    <param name=Str2 value="Hello 2">
    <param name=Str3 value="Hello 3">
    <param name=Str4 value="Hello 4">
    <param name=Str5 value="Hello 5">
    <param name=Font1 value="Dialog">
    <param name=Font2 value="Courier">
    <param name=Font3 value="TimesRoman">
    <param name=Font4 value="Helvetica">
    <param name=Font5 value="Undefined">
    <param name=Type1 value="Bold">
    <param name=Type2 value="Italic">
    <param name=Type3 value="Plain">
</applet>
<hr>
<a href="TextOut.java">The source.</a>
</body>
</html>

Описание исходных текстов

Если при создании шаблона аплета с помощью системы Java Applet Wizard вы указываете, что аплету передаются параметры и определяете их список, система Java Applet Wizard организует для вас прием и хранение параметров. Поэтому обработка параметров аплета не отнимет у вас много сил.

Какие строки добавляются системой Java Applet Wizard для обработки параметров?

Поля класса TextOut

Прежде всего, создаются поля класса для хранения значений параметров:

private String m_Str1 = "Hello 1";
. . .
private String m_Str5 = "Hello 5";
private String m_Font1 = "Arial";
. . .
private String m_Font5 = "Undefined";
private String m_Type1 = "Bold";
private String m_Type2 = "Italic";
private String m_Type3 = "Plain";

Поля инициализируются значениями по умолчанию, которые вы ввели при заполнении таблицы, показанной на рис. 3.13.

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

private final String PARAM_Str1 = "Str1";
. . .
private final String PARAM_Str5 = "Str5";
private final String PARAM_Font1 = "Font1";
. . .
private final String PARAM_Font5 = "Font5";
private final String PARAM_Type1 = "Type1";
private final String PARAM_Type2 = "Type2";
private final String PARAM_Type3 = "Type3";

Названия параметров будут нужны для извлечения значений параметров методом getParameter класса Applet.

Метод getParameterInfo

Система Java Applet Wizard переопределяет метод getParameterInfo, который возвращает ссылку на массив массивов с описаниями параметров:

public String[][] getParameterInfo()
{
  String[][] info =
  {
    { PARAM_Str1, "String", "Text string to write" },
     . . .
    { PARAM_Str5, "String", "Text string to write" },
    { PARAM_Font1, "String", "Text font" },
     . . .
    { PARAM_Font5, "String", "Text font" },
    { PARAM_Type1, "String", "Font type" },
    { PARAM_Type2, "String", "Font type" },
    { PARAM_Type3, "String", "Font type" },
  };
  return info;		
}

Как мы уже говорили, эта информация может использоваться другими аплетами, размещенными в том же документе HTML и работающими одновременно с нашим аплетом.

Метод init

При инициализации аплета метод init читает все параметры и записывает их значения в соответствующие поля класса, как это показано ниже:

public void init()
{
    String param;

    param = getParameter(PARAM_Str1);
    if (param != null)
      m_Str1 = param;
. . .
    param = getParameter(PARAM_Str5);
    if (param != null)
      m_Str5 = param;

    // Шрифты для отображения строк
    param = getParameter(PARAM_Font1);
    if (param != null)
      m_Font1 = param;
. . .
    param = getParameter(PARAM_Font5);
    if (param != null)
      m_Font5 = param;

    // Начертание шрифтов
    param = getParameter(PARAM_Type1);
    if (param != null)
      m_Type1 = param;
. . .
    param = getParameter(PARAM_Type3);
    if (param != null)
      m_Type3 = param;
}

Здесь все просто. Метод init по очереди получает значения параметров методом getParameter, которому в качестве параметра передается имя параметра аплета. Полученное значение сохраняется в рабочей переменной param и, если оно отлично от значения null, сохраняется в соответствующем поле класса.

Метод paint

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

if(m_Type1.equals("Bold"))
  g.setFont(new Font(m_Font1, Font.BOLD, 25));

else if(m_Type1.equals("Italic"))
  g.setFont(new Font(m_Font1, Font.ITALIC, 25));

else if(m_Type1.equals("Plain"))
  g.setFont(new Font(m_Font1, Font.PLAIN, 25));

Для сравнения строк класса String мы используем метод equals, который возвращает значение true при совпадении с заданной строкой и false в противном случае.

Методу выбора шрифта setFont мы передаем объект класса Font, созданный конструктором.

Конструктор получает в качетсве первого параметра содержимое поля класса m_Font1, которое соответствует значению параметра аплета с именем Font1.

Значение второго параметра (стиль шрифта) выбирается исходя из значения параметра аплета с именем m_Type1. Здесь мы указываем константы, определенные в классе Font.

И, наконец, третий параметр конструктора класса Font задает размер символов шрифта, равный 25 пикселам.

После выбора шрифта мы выполняем отступ от верхней границы окна и рисуем первую строку в позиции (0, yCurrent):

yCurrent += yStart;
g.drawString(m_Str1, 10, yCurrent);

На следующем этапе метод paint получает метрику только что выбранного шритфа и увеличивает текущую позицию yCurrent на величину полной высоты символов шрифта, полученную с помощью метода getHeight:

FontMetrics fm = g.getFontMetrics();
yCurrent += fm.getHeight();

Далее эта же процедура повторяется для остальный четырех отображаемых в окне аплета строк.

Экспериментируя с аплетом, попробуйте изменить параметры, передаваемые аплету в документе HTML. Укажите, например, несуществующий шрифт и посмотрите, какой шрифт будет выбран навигатором для отображения.