Метод paint
Наиболее интересен для нас метод paint, который выполняет рисование в окне аплета. Вот его исходный текст, созданный системой Java Applet Wizard:
public void paint(Graphics g)
{
g.drawString(
"Created with Microsoft Visual J++ Version 1.0",
10, 20);
}
Если посмотреть определение класса Applet, то в нем нет метода paint. В каком же классе определен этот метод?
Взглянем на определение класса Applet:
public class java.applet.Applet
extends java.awt.Panel
{
. . .
}
Во-первых, вы видите, что полное имя класса Applet есть java.applet.Applet. Включая оператором import библиотеку классов java.applet.*, мы включали и определение класса Applet.
Во-вторых, из определения класса можно заключить, что класс java.applet.Applet произошел от класса java.awt.Panel. Напомним, что определение классов java.awt.* также было включено в исходный текст нашего аплета оператором import.
Если класс java.applet.Applet был создан на базе класса java.awt.Panel, то нет ли в базовом классе определения метода paint?
Изучив исходный текст класса java.awt.Panel, убеждаемся, что такого метода там нет, однако сам класс java.awt.Panel произошел от класса java.awt.Container:
public class java.awt.Panel
extends java.awt.Container
{
. . .
}
Продолжим наши исследования. В классе java.awt.Container снова нет метода paint, но сам этот класс создан на базе класса java.awt.Component:
public abstract class java.awt.Container
extends java.awt.Component
{
. . .
}
Но и здесь метода paint нет. Этот метод определен в классе java.awt.Component, который, в свою очередь, произошел от класса java.lang.Object и реализует интерфейс java.awt.image.ImageObserver:
public abstract class java.awt.Component
extends java.lang.Object
implements java.awt.image.ImageObserver
{
. . .
}
Мы проследили иерархию классов от класса java.applet.Applet, на базе которого создан наш аплет, до класса java.lang.Object, который является базовым для всех классов в Java.
В обработчик метода 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 прежде всего мы определяем полную высоту символов шрифта, которая будет использована при выводе строк. Высота шрифта определяется следующим образом:
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. Каждая новая строка рисуется со смещением, равным полной высоте символов текущего шрифта, выбранного в контекст отображения.
После закрашивания фона желтым цветом и рисования вокруг окна аплета черной рамки метод 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. Укажите, например, несуществующий шрифт и посмотрите, какой шрифт будет выбран навигатором для отображения.
В начале своей работы метод paint определяет текущие размеры окна аплета, закрашивает это окно в желтый цвет и рисует вокруг него тонкую рамку черного цвета. Все это делается исключительно для того чтобы выделить аплет в документе HTML и обозначить его границы.
Далее метод paint отображает текущие координаты курсора мыши, взяв их из переменной ev:
g.drawString("(" + ev.x + "," + ev.y + ")", ev.x, ev.y);
После обычной для наших аплетов раскраски фона и рисования рамки метод paint перебирает в цикле все элементы массива lines, рисуя линии:
for (int i=0; i < lines.size(); i++)
{
Rectangle p = (Rectangle)lines.elementAt(i);
g.drawLine(p.width, p.height, p.x, p.y);
}
Для объектов класса Vector можно использовать метода size, возвращающий количество элементов в массиве, чем мы воспользовались для проверки условия выхода из цикла.
Чтобы извлечь элемент массива по его номеру, мы воспользовались методом elementAt, передав ему через единственный параметр номер извлекаемого элемента.
Так как в массиве хранятся объекты класса Rectangle, перед инициализацией ссылки p мы выполняем преобразование типов.
Перед завершением работы метод paint сбрасывает признак рисования, записывая в поле bDrawing значение false:
bDrawing = false;
Метод paint закрашивает окно аплета желтым цветом и обводит его рамкой. Никакой другой работы этот метод не выполняет.
Метод paint не содержит никакого кода для рисования кнопок, так как эта задача решается в рамках класса Button. После раскрашивания фона окна аплета и рисования рамки вокруг него, метод paint пишет название нажатой кнопки в окне аплета с помощью метода drawString:
g.drawString("Button (\"" + sTextLabel + "\") pressed",
10, 70);
В методе paint мы не закрашиваем желтым цветом окно аплета, так как на этапе инициализации в обработчике метода init был установлен желтый цвет фона окна. Однако черную рамку вокруг границы окна аплета мы все же рисуем.
Основная задача метода paint заключается в отображении в нижней части окна аплета списка включенных переключателей. Для формирования этой строки мы создаем объект s класса String:
String s = new String("> ");
Далее мы проверяем по очереди состояние всех переключателей с независимой фиксацией, дописывая к строке s название включенных переключателей:
if(chbox1.getState())
s = s + chbox1.getLabel() + ", ";
if(chbox2.getState())
s = s + chbox2.getLabel() + ", ";
if(chbox3.getState())
s = s + chbox3.getLabel() + ", ";
Для определения текущего состояния переключателей мы вызываем метод getState. Этот метод возвращает значение true для включенного переключателя и false - для выключенного. Название переключателя легко определить с помощью метода getLabel.
Проверка состояний переключателей с зависимой фиксацией выполняется аналогично, но с учетом того, что одновременно может быть включен только один такой пеерключатель:
if(rdbox1.getState())
s = s + rdbox1.getLabel();
else if(rdbox2.getState())
s = s + rdbox2.getLabel();
else if(rdbox3.getState())
s = s + rdbox3.getLabel();
else if(rdbox4.getState())
s = s + rdbox4.getLabel();
После завершения формирования строки s она отображается в окне аплета методом drawString:
g.drawString(s, 10, 150);
Обработчик метода paint рисует рамку вокруг окна аплета и текстовую строку в средней части этого окна.
Dimension dimAppWndDimension = size();
g.drawRect(0, 0,
dimAppWndDimension.width - 1,
dimAppWndDimension.height - 1);
g.drawString("Смотри на цвет фона и текста!", 10, 50);
При этом мы не указали цвет фона, а также цвет изображения. При этом используются цвета, установленные методом action при выборе соответствующих строк из списков.
Обработчик метода paint рисует рамку вокруг окна аплета и текстовую строку в средней части этого окна.
В нижней части окна аплета метод paint отображает выделенные в списках цвета фона и изображения:
g.drawString("Background: " + sSelBackground, 10, 160);
g.drawString("Foreground: " + sSelForeground, 10, 190);
Единственное, что делает метод paint, - это рисование рамки черного цвета вокруг окна аплета.
После рисования рамки черного цвета вокруг окна аплета метод paint отобаржает текущее содержимое строки str в нижней части окна:
g.drawString("> " + str, 10, 100);
После рисования рамки черного цвета вокруг окна аплета метод paint отобаржает текущее содержимое строки str в нижней части окна:
g.drawString("> " + str, 10, 100);
Метод paint рисует в окне панели pDraw, а не в главном окне аплета. Для этого метод paint получает контекст отображения этой панели, вызывая для этого метод getGraphics:
Graphics gpDraw;
gpDraw = pDraw.getGraphics();
Далее метод paint определяет размеры панели pDraw и рисует рамку вокруг окна этой панели:
Dimension dimAppWndDimension = pDraw.size();
gpDraw.drawRect(0, 0, dimAppWndDimension.width - 1,
dimAppWndDimension.height - 1);
После того как рамка будет нарисована, метод paint устанавливает в панели pDraw шрифт, название которого хранится в староке sFontName. Для этого используется контекст отображения gpDraw, полученный нами ранее для панели pDraw:
gpDraw.setFont(new Font(sFontName, Font.PLAIN, 12));
Текстовая строка отображается с использованием текущего цвета изображения и текущего шрифта, установленного в контексте отображения gpDraw, при помощи метода drawString:
gpDraw.drawString("Смотри на шрифт, цвет фона и текста!",
10, 50);
Затем метод paint обводит панель блокнота рамкой. Вначале он получает контекст отображения для панели блокнота, как это показано ниже:
gpDraw = pCardPanel.getGraphics();
После получения контекста отображения метод paint определяет размеры панели блокнота и рисует рамку вокруг его окна:
dimAppWndDimension = pCardPanel.size();
gpDraw.drawRect(0, 0, dimAppWndDimension.width - 1,
dimAppWndDimension.height - 1);