Программирование на Java
Шрифт:
Затем необходимо установить clip в соответствии с размером очередного компонента. Необходимо выставить значения по умолчанию для цвета и шрифта, тем более что предыдущий компонент мог изменить их непредсказуемым образом.
В итоге получается более удобным создать новый экземпляр Graphics для каждого компонента. Для этого существует метод create, который порождает копию Graphics, причем ему можно передать аргументы ( int x, int y, int width, int height ). В результате у нового Graphics будет смещен центр координат в точку ( x, y ), а clip -область будет получена пересечением существующего ограничителя
Такие копии бывает удобно порождать и в рамках одного вызова метода paint, если в нем описан слишком сложный алгоритм. После использования такого объекта Graphics его необходимо особым образом освобождать – вызовом метода dispose. Если необходимо только сместить точку отсчета координат, можно использовать метод translate (int x, int y).
Таким образом, контейнер своим методом paint отрисовывает себя и все вложенные в него компоненты. Если какие-то из них, в свою очередь, являются контейнерами, то процесс иерархически продолжается вглубь. В итоге весь AWT интерфейс, каким бы сложным он ни был, состоит из дерева контейнеров и компонент, отрисовка которых начинается с самого верхнего контейнера и по ветвям развивается вглубь до каждого видимого компонента.
Отдельный интерес представляет этот самый верхний контейнер. Как правило, это окно операционной системы, одновременно являющееся контейнером для Java-компонент. Именно операционная система инициализирует процесс отрисовки, отвечает за сворачивание и разворачивание окна, изменение его размера и так далее. Со стороны Java для работы с окном используется класс Window, который является наследником Container и рассматривается ниже.
Наследники класса Component
Теперь, когда рассмотрены основные принципы работы классов Component и Container, рассмотрим их наследников, с помощью которых и строится функциональный пользовательский интерфейс.
Начнем с наследников класса Component.
Класс Canvas
Класс Canvas является простейшим наследником Component. Он не добавляет никакой новой функциональности, но именно его нужно использовать в качестве суперкласса для создания пользовательского компонента с некоторым нестандартным внешним видом.
Ниже приведен пример определения компонента, который отображает график функции sin(x):
public class SinCanvas extends Canvas {
public void paint(Graphics g) {
int height = getHeight, width = getWidth;
// Вычисляем масштаб таким образом,
// чтобы на компоненте всегда умещалось
// 5 периодов
double k=2*Math.PI*5/width;
int sy = calcY(0, width, height, k);
for (int i=1; i<width; i++) {
int nsy = calcY(i, width, height, k);
g.drawLine(i-1, sy, i, nsy);
sy=nsy;
}
}
// метод, вычисляющий значение функции
// для отображения на экране
private int calcY(int x, int width,
int height, double k) {
double dx = (x-width/2.)*k;
return (int)(height/2.*(1-Math.sin(dx)));
}
}
Как видно из примера, достаточно лишь переопределить
Класс Label
Как понятно из названия, этот компонент отображает надпись. Соответственно, и его основной конструктор принимает один аргумент типа String – текст надписи. С помощью стандартных свойств класса Component – шрифт, цвет, фоновый цвет – можно менять вид надписи. Текст можно сменить и после создания Label с помощью метода setText.
Обратите внимание, что при этом компонент сам обновляет свой вид на экране. Такой особенностью обладают все стандартные компоненты AWT.
Класс Button
Этот компонент позволяет добавить в интерфейс стандартные кнопки. Основной конструктор принимает в качестве аргумента String – надпись на кнопке. Как обрабатывать нажатие на кнопку и другие пользовательские события, рассматривается ниже.
Классы Checkbox и CheckboxGroup
Компонент Checkbox имеет два способа применения.
Когда он используется сам по себе, он представляет checkbox – элемент, который может быть выделен или нет (например, нужна доставка для оформляемой покупки или нет). В этом случае в конструктор передается лишь текст – подпись к checkbox.
Рассмотрим пример, в котором в теле контейнера добавляется два checkbox:
Checkbox payment = new Checkbox("Оплата в кредит");
payment.setBounds(10, 10, 120, 20);
add(payment);
Checkbox delivery = new Checkbox("Доставка");
delivery.setBounds(10, 30, 120, 20);
add(delivery);
Ниже приведен внешний вид такого контейнера:
Обратите внимание, что размер Checkbox должен быть достаточным для размещения не только поля для "галочки", но и для подписи.
Второй способ применения компонент Checkbox предназначен для организации "переключателей" ( radio buttons ). В этом случае несколько экземпляров объединяются в группу, причем лишь один из переключателей может быть выбран. В роли такой группы выступает класс CheckboxGroup. Он не является визуальным, то есть никак не отображается на экране. Его задача – логически объединить несколько Checkbox. Группу, к которой принадлежит переключатель, можно указывать в конструкторе:
CheckboxGroup delivery = new CheckboxGroup;
Checkbox fast = new Checkbox(
"Срочная (1 день)", delivery, true);
fast.setBounds(10, 10, 150, 20);
add(fast);
Checkbox normal = new Checkbox(
"Обычная (1 неделя)", delivery, false);
normal.setBounds(10, 30, 150, 20);
add(normal);
Checkbox postal = new Checkbox(
"По почте (до 1 месяца)", delivery, false);
postal.setBounds(10, 50, 150, 20);
add(postal);