Назад | Начало урока | Вперед
Содержание

Глава 10 (продолжение )

Графика и пользовательские интерфейсы


Вверх

10.1 Введение в awt и Swing

Структура пакета awt

Классы пакета awt можно разделить на следующие группы:

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

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

Подпакет java.awt.event предназначен для обработки внешних событий (нажатий кнопок. перемещения мыши и тд) с помощью обработчиков событий, слушателей и адаптеров.

Подпакет java.awt.image используется пакетом awt для предоставления изображений в различных форматах. Общая схема главного пакета awt воспроизведена на рис 10.1.

Главными абстрактными классами являются Component, Container, MenuComponent и Graphics. Наряду с ними существуют классы FontMetrics, Image, PrintJob и ToolKit.

Класс LayoutManager - это интерфейс, а остальные представляют собой классы. унаследованные от тех, которые изображены выше. Таким образом класс Frame - это наследник класса Windows, являющегося потомком класса Container, предок которого называется Component.

Мы воспользуемся для примера простой программой из гл 2, которая выводит на экран изображение флага. чтобы представить различные части пакета awt.

Swing

Вверх

10.2 Размещение графики в окне

Графический интерфейс реализуется посредством окон. В Java имеется класс Window, но на практике обычно используется один из его подклассов - Frame.

Frame - базисное окно

Приложение может иметь несколько окон, для каждого из которых объявляется класс, который наследует классу Frame и включает вызовы методов, необходимых для вызова информации в окно и выполнения других операций. Если используется одно окно (как в примере 2.2, когда мы выводим на экран флаг), главный класс программы и будет тем классом, который объявляет его. В следующем примере показано, как создается простое окно.

Создание окна(определение класса, наследующего класс Frame)
import java.awt.*;

class Classid extends Frame {

Classid {
setTitle("title"); //дополнительный метод
setSize (width, height);
setVisible(true);
}

... где-нибудь, например в методе main должен быть оператор:

new Classid();

}

Сначала импортируется пакет java.awt.
Затем класс, который должен содержать объект "фрейм", наследует классу Frame.
В завершение класс создает объект(экземпляр самого себя), а его конструктор выполняет три основные функции: подготавливает к выводу заголовок окна (метод setTitle), задает его размеры (метод setSize) и активизирует процесс вывода фрейма с помощью метода setVisible.

В классах Frame и Component обновляются три метода. Ниже показана часть объявления класса и конструктор для объекта, создающего флаг (пример 2.2).

class FlagMaker extends Frame {

FlagMaker () {

add ("Center", new Flags());

// Set the frame's title and size and activate the drawing
// described by the paint method.
setTitle ("A Flag");
setSize (300, 200);
setVisible (true);

}

public void paint (Graphics g) {

...
}
public static void main (String [ ] args) {
new FlagMaker ();
}
}

Добавление графики в окно

На данном этапе выполнения программы пакет awt использует метод paint для добавления в окно графики. Метод paint определяется:

Вот описание метода paint

Переопределение метода paint
public void paint (Graphics g) {
Вызывает методы, определенные в Graphics,
которые будут иметь префикс g)
}

public void repaint (Graphics g) {

Вызывает методы, определенные в Graphics,
которые будут иметь префикс g)
}
Метод paint вызывается когда компонент становится видимым, а так же когда окно, в котором он находится, скрыто и должно быть выведено заново.

Метод repaint может быть вызван программой для той же цели.

В процессе выполнения метод paint использует объект Graphics, адаптированный для платформы, на которой запущена программа. Это одно из преимуществ языка Java: используются графические элементы конкретной платформы, то есть пакет awt выводит на экран компоненты, знакомые пользователю.

Класс Graphics довольно обширен, поэтому мы смогли дать характеристику только для некоторых из его методов:

Спецификация класса Graphics
clearRect (int x, int y, int width, int height);
copyArea (int x, int y, int height, int width, int dx, int dy);
drawChars (char [] data, int offset, int length, int x, int y);
drawLine (int x1, int y1, int x2, int y2);
drawOval (int x, int y, int width, int height);
drawRect (int x, int y, int width, int height);
drawString (string str, int x, int y);
fillOval (int x, int y, int width, int height);
fillRect (int x, int y, int width, int height);
setColor (color c);
setFont(Font f);
//плюс 38 других методов

К числу тринадцати стандартных цветов относятся следующие: black, blue, cyan, darkGray, gray, lightGray, magenta, orange, pink, red, white, yellow. Например для черчения красного прямоугольника служит такой метод:

public void repaint (Graphics g) {

g.getColor(Color.red);
g.fillRect(10, 10, 200, 100);
}

Вывод текста в окне awt с помощью метода drawString

В процессе работы с пакетом Graphics используется метод drawString, который эквивалентен методу println. Например оператор

g.drawString("Hello Pierres:", 30, 15);

выведет на экран строку Hello Pierres, в которой левая нижняя точка буквы H находится на расстоянии 30 пикселей по горизонтали и 15 пикселей по вертикали от левого верхнего угла экрана.

Отличие между методами println и drawString состоит в том, что последний позволяет выбрать шрифт, а так же его начертание и размер. Впоследствии позиционирование начала строки может оказаться сложной задачей. Для создания универсальной программы, выводящей данные в удобочитаемом виде, следует опираться на относительные размеры символов. Абстрактный класс FontMetrics из пакета awt содержит методы, определяющие подходящие размеры символов, однако иногда в простых программах можно задавать и абсолютные размеры в пикселах. Теперь мы готовы к рассмотрению первого в этой главе примера.

Вверх

Пример 10.1 Вывод предупреждения о возможном заражении вирусом

Задача. Вывести на экран окно с предупреждающим сообщением.

Подсказка

На рис 10.3 показан результат работы программы

Решение. Мы воспользуеся окном, созданным при помощи пакета awt, методом drawString и описанными выше средствами для работы с прямоугольником. Чтобы сделать прямоугольник более броским, нам потребуется найти цветовое решение. Для работы с цветом предназначены методы setForeground и setBackground класса Component, а так же цветовые константы, определенные в классе Color. Мы остановим выбор на бирюзовом цвете, который соответствет константе Color.cyan

Программа. Программа очень проста


import java.awt.*;
import java.awt.event.*;

class VirusWarning extends Frame {

/* The Graphic warning Program by J M Bishop Oct 1996
* Java 1.1 by T Abbott Oct 1997
* updated 1.2 by J Bishop May 2000
* produces a warning message on the screen in cyan
* and black.
* Illustrates setting up a window, painting in it
* and enabling the close box.
*/

VirusWarning () {

setTitle("Draw Warning");
setSize(220,150);
setBackground(Color.cyan);
setForeground(Color.black);
addWindowListener(new WindowAdapter () {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setVisible(true);
}

public void paint(Graphics g) {

g.setColor(Color.pink);
g.fillRect(25, 30, 150, 90);
g.setColor(Color.black);
g.drawString("W A R N I N G", 70, 60);
g.drawString("Possible virus detected", 45, 75);
g.drawString("Reboot and run virus", 50, 90);
g.drawString("remover software", 60, 105);
}

public static void main(String[] args) {

new VirusWarning ();
}
}

Тестирование

Подсказка

На рис 10.3 показан результат работы программы

Закрытие окна

Далее пойдет речь о том, как завершается выполнение программы, работающей в окне. Один из способов - закрыть окно, щелкнув на кнопке в его правом углу. Щелчок мышью - это событие, которое может быть воспринято слушателем из подпакета Event пакета awt.

В главном методе мы задаем ссылку на такой слушатель окна путем вызова метода addWindowListener и создания экземпляра новой версии адаптера окна WindowAdapter. В реализации адаптера, которая рассматривается ниже, переопределяется метод класса WindowAdapter, называемый WindowClosing, и выполняется соответствующее действие, в данном случае - вызов метода System.exit(0).

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

Закрытие окна
addWindowListener(new WindowAdapter () {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
Класс WindowAdapter - это простой абстрактный класс, который реализует интерфейс WindowListener и предоставляет абстрактные методы для различных содержащихся в нем методов. Мы можем решить, какой из них переопределить. В данном случае из семи имеющихся методов нас интересует только WindowClosing, Создание экземпляра объекта WindowAdapter и переопределение метода WindowClosing осуществляется при передаче параметра методу addWindowListener.

В этом описании все слова являются или ключевыми (выделены жирным шрифтом) или идентификаторами, которые уже определены в пакете awt, за исключением параметра (событие "e"), который не используется, поэтому всегда может оставаться неизменным. Код описания можно рассматривать как мантру и помещать в главный метод любых GUI-программ. В коде используется анонимный класс, представленный в разделе 8.2.

Применению анонимного класса существует альтернатива: методу addWindowListener в качестве параметра можно передавать выражение new x(), а затем определить x как локальный класс с заголовком, в котором указано, что данный класс расширяет класс WindowAdapter, и телом, являющимся реализацией WindowClosing. Очевидно, что в любом случае код анонимного класса выглядит компактнее.

Вверх

Пример 10.2 Гистограмма уровней осадков в Саванне

Задача.

Решение.

Алгоритм.

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

Конструктор будет иным. Мы воспользуемся им для ввода всех данных, необходимых для решения текущей задачи (ранее с этой целью применялся метод readIn). ОДнако содержимое не меняется. Наиболее важная часть программы связана с отображением диаграммы. Необходимо получить на выходе такую же гистограмму, как на рис 10.4

Рассмотрим составные части диаграммы поочередно:

  1. Оси Точка отсчета имеет следующие координаты: x = 50, y = 300. Данные значения выражены в пикселах. Направление отсчета то же, что и на рис 10.2

  2. Столбцы Для вывода столбцов применяется метод fillRect. Мы должны предоставить параметры, указанные в таб "Спецификация класса Graphics", которая опубликована в начале данного раздела. Другими словами нам нужны: точка в основании столбца, ширина и высота столбца. Шириной будет некоторая константа(не число, объявленное как константа, а повторяющееся значение для вывода столбцов одинаковой ширины), например 20. Высотой - фактическое значение уровня осадков за месяц. умноженное на 10 (значение переменной "а"). Таким образом обеспечивается и легкость восприятия диаграммы (10 мм осадков соответствует 100 пикселей). Начальной точкой прямоугольника служит координата "y-a", где "y" соответствует координате базовой линии (то есть 300. как определено выше). Сложность при нахождении начальной точки координаты "x" связана с тем, что она специфична для каждого месяца. Формула, в которой учитывается ширина столбцов и интервалы между ними. выглядит следующим образом:

    g.fillRect(month*(width+gap)+gap+x, y-a,width,a);

  3. Метки Градуировка осей осуществляется посредством двух циклов, принципы работы которых легко понять. Однако их самостоятельная разработка потребует некоторых усилий. Для градуировки оси x используется массив строк, в которых хранятся названия месяцев.

    // labelling the axes
    for (int m = 0; m < 12; m++)

    g.drawString(months[m],m*(width+gap)+gap+x,y+20);
    for (int i = 0; i < y; i+=100)
    g.drawString(String.valueOf(i),20,y-i);

  4. Заголовок При выводе не экран заголовка мы увидим, как изменять шрифты средствами Java. Имеется класс Font, экземпляр которого может быть создан с тремя параметрами: название шрифта, начертание и размер. Доступны такие шрифты: Serif, SansSerif, Monospaced, Dialog и DialogInput. Применяться будут стили: PLAIN, BOLD, ITALIC.

    Размер шрифта выражается в пунктах. Нормальным считается размер 12 пунктов. Если же текст должен быть крупным, можно установить размер 24 пункта. Не рекомендуется применять шрифт, размер которого меньше 8 пунктов. Поскольку измененный шрифт используется последним из используемых в программе методом drawString, восстанавливать его не потребуется.

Подсказка

Рис 10.4 Результат выполнения программы "Гистограмма уровней осадков в Саванне"

Программа

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


import java.io.*;
import javagently.*;
import java.awt.*;
import java.awt.event.*;
import myutilities.*; // for the Stats class

class WeatherChart extends Frame {

/* The Weather Charting program by J M Bishop Dec 1997
* Java 1.1
* updated May 2000
* Draws a histogram of monthly rainfall
* from data taken over a few years.
* The data must be in the form:
* year followed by the 12 rainfall figures for
* the months of that year.
* Illustrates simple graphics.
* Uses the Stats class from myutilities.
*/

int base = 1950;
int startYear, endYear, nYears = 0;
double[][] rainTable = new double[12][70];
String months [] = {

"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"
};

WeatherChart () throws IOException {

getData ();
setTitle("Weather Chart");
setSize(400,350);
setVisible(true);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}

public void paint (Graphics g) {

int x = 50;
int y = 300;
int width = 20;
int gap = 5;

// the axes
g.drawLine (x,y,x+12*(width+gap),y);
g.drawLine (x,y,x,30);

// labelling the axes
for (int m = 0; m < 12; m++)

g.drawString(months[m],m*(width+gap)+gap+x,y+20);
for (int i = 0; i < y; i+=100)
g.drawString(String.valueOf(i),20,y-i);

// the title
Font heading = new Font("SansSerif",Font.BOLD,14);
g.setFont(heading);
g.drawString("Savanna Rainfall Chart",120,40);
g.setColor(Color.cyan);

// the bars
for (int month = 0; month < 12; month++) {

int a = (int) Stats.mean (rainTable[month], nYears)*10;
g.fillRect(month*(width+gap)+gap+x, y-a,width,a);
}
}

void getData () throws IOException {

Stream fin = new Stream ("rain.dat", Stream.READ);

int actualYear = 0; /* e.g. 1997 */
int yearIndex = 0; /* e.g. 0 */
try {

while (true) {
actualYear = fin.readInt();
if (yearIndex == 0)
startYear = actualYear;
for (int m = 0; m < 12; m++)
rainTable[m][yearIndex] = fin.readDouble();
yearIndex++;
}
}
catch (EOFException e) {
/* Pick up the last year of data read in. */
endYear = actualYear;
nYears = endYear-startYear+1;
}
}

public static void main(String[] args) throws IOException {

new WeatherChart ();
}

}


В функции getData происходит считывание данных из текстового файла в поток:

Stream fin = new Stream ("rain.dat", Stream.READ);

Затем из потока в цикле в двумерный массив rainTable.

for (int m = 0; m < 12; m++)

rainTable[m][yearIndex] = fin.readDouble();
yearIndex++;


Назад | Начало урока | Вверх | Вперед
Содержание

Hosted by uCoz