Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Секреты программирования для Internet на Java

.pdf
Скачиваний:
181
Добавлен:
02.05.2014
Размер:
3.59 Mб
Скачать

выполнить интерфейс Observer так, чтобы каждый объект в нашей системе мог быть легко информирован о ходе игры. Затем мы напишем наш игровой класс, который, когда что-нибудь происходит, сообщает объекту Observable информацию для всех других объектов.

Пример 6-13a. Использование класса Observable. public class BigGame {

private Observable onlookers; private int teamAScore; private int teamBScore; private String teamWinning; // переменные, конструкторы

public void setObservable(Observable o) { onlookers=o;}

public void updateScore(int teamA, int teamB) { teamAScore=teamA;

teamBScore=teamB;

//должен быть выполнен, когда счет изменен onlookers.notifyObservers(this);

//передаем игру всем зрителям

}

public String getWinningTeam() { return new String("Carolina");}

}

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

Пример 6-13b. Использование интерфейса Observer. class UNCFan implements Observer{

// переменные, конструкторы

public void update(Observable o, Object Game) { BigGame BG=(BigGame)Game;

String winningTeam=BG.getWinningTeam(); if (winningTeam.equals("UNC"))

System.out.println("yeaaaa!!!");

else

System.out.println("booo!!!!!");

}

// другие методы

}

class DukeFan implements Observer { // переменные, конструкторы

public void update(Observable o, Object Game) { BigGame BG=(BigGame)Game;

String winningTeam=BG.getWinningTeam(); if (winningTeam.equals("Duke"))

System.out.println("yeaaa!!!!");

else

{System.out.println("booo!!!");

}

}

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

Пример 6-13c. Добавление объектов выполнения Observer.

Observable onlookers=new Observable(); onlookers.addObserver(UNCFanInstance); on lookers.addObserver(DukeFanlnstance); on lookers.addObserver(Press);

on Iookers.addObserver(UnitedNations); // и т. д, и т. п.

Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com

Кроме метода addObserver, есть еще несколько других методов, помогающих управлять объектами. Они приведены в табл. 6-17.

 

Таблица 6-17. Методы класса Observable

Метод

Описание

void addObserver(Observer

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

o)

 

void

Удаляет наблюдателя.

deleteObserver(Observer o)

 

void notifyObservers(Object

Сообщает наблюдателям, что что-то случилось; чтобы узнать, что

arg)

именно, они могут исследовать arg.

int countObservers()

Возвращает число наблюдателей.

boolean hasChanged()

Возвращает true, если что-то изменилось; setChanged и clearChanged

 

должны использоваться, чтобы устанавливать и сбрасывать флажок.

void setChanged()

Заставляет hasChanged возвращать true.

void clearChanged()

Заставляет hasChanged возвращать false.

Математика и API

Мы рассмотрели базовые операторы в главе 2, "Основы программирования на Java", но рано или поздно вам понадобится выполнять более сложные операции. Класс Math пакета java.lang содержит 30 арифметических методов, например, методы нахождения максимума или минимума пары чисел или получения натурального логарифма. Он также содержит значения для чисел e и пи в виде статических переменных.

На рис. 6-12 показана Web-страница класса Math в интерактивной документации по Java. Вместо того чтобы пытаться описать методы более подробно, мы сосредоточимся на том, как использовать их на практике.

Рис. 6.12.

Пример 6-14. Использование класса Math. public class DoSomeMath {

// другие объявления

public void useMathMethods(int i1,int i2, double d, float f,long l) {

www.books-shop.com

int intAbsValue=Math.abs(i1); double doubAbsValue=Math.abs(d); float floatAbsValue=Math.abs(f); long longAbsValue=Math.abs(l);

//Они возвратят абсолютное значение.

//Метод abs !!!перегружен.

int minInt=Math.min(i1,i2); double maxDoub=Math.max(i1,d);

//Методы min и max перегружены для каждого числового типа.

//Во второй строке i1 приводится к типу double.

}

Как мы говорили выше, мы можем получать значения e и пи из класса Math. Классыупаковщики также содержат некоторые значения, представляющие для нас интерес, например статические переменные для максимального значения каждого примитивного типа и другие полезные величины. Все они описаны в табл. 6-18.

 

Таблица 6-18. Полезные статические переменные

Переменная

Значение

Классы, содержащие

 

 

данную переменную

E

Основание естественного логарифма.

Math

PI

Значение числа пи.

Math

MIN_VALUE

Минимальное значение для данного типа.

Integer, Float, Long, Double

MAX_VALUE

Максимальное значение для данного типа.

Integer, Float, Long, Double

NEGATIVE_INFINITY Представляет отрицательную бесконечность.

Float, Double

POSITIVE_INFINITY

Представляет положительную бесконечность.

Float, Double

NaN

"Не число"; может использоваться, чтобы

Float, Double

 

представить неназначенные значения.

 

Что дальше?

Мы только начали исследовать API. Теперь, когда вы узнали основы API, мы можем перейти к пакетам абстрактного набора инструментальных средств для работы с окнами. Мы опишем их в главе 7, "Пользовательский интерфейс", главе 8, "Еще об интерфейсе пользователя", и главе 9, "Графика и изображения". Вся часть книги о работе с сетями (часть IV, "Java и Сеть") посвящена пакетам java.io и java.net.

www.books-shop.com

Глава 7

Пользовательский интерфейс

Апплет пересчета денежных сумм Ввод с клавиатуры Поля редактирования текста Кнопки Переключатели Списки Выпадающие списки Полосы прокрутки Надписи

В этой главе мы приступаем к изучению особого компонента языка, называемого "Advanced Windowing Toolkit" ("Инструментарий для построения оконного интерфейса", AWT). Начнем мы с основных элементов экранного интерфейса пользователя (Graphical User Interface, GUI), определенных в пакете java.awt. Апплеты, которые мы напишем на протяжении этой главы, будут использовать следующие компоненты AWT:

ввод с клавиатуры,

поля для текстового ввода из одной или нескольких строк,

кнопки,

флажки,

списки,

всплывающие меню,

полосы прокрутки,

статичные текстовые надписи.

www.books-shop.com

Java позволяет использовать эти базовые элементы интерфейса пользователя с гораздо большим удобством и эффективностью, чем HTML. Одним из очень важных инструментов, доступных Java-программисту, является эмуляция ввода пользователя. Все перечисленные выше элементы позволяют отслеживать перемещение курсора мыши, что делает их более интерактивными. Например, программа может вывести какой-нибудь поясняющий или образцовый текст в поле редактирования в тот момент, когда пользователь проносит над ним курсор мыши. Следующая глава, "Еще об интерфейсе пользователя", развивающая материал данной главы, посвящена тому, как реализовать более сложные элементы интерфейса. Затем, когда мы перейдем к изучению взаимодействия с сетью (часть 4, "Java и Сеть"), вы уже будете уметь создавать эффективный и профессионально выглядящий интерфейс для своих программ и сможете приступить к созданию апплетов, реализующих связь с удаленными сетевыми серверами (в том числе и серверами протокола HTTP).

На протяжении этой главы мы создадим несколько версий одного и того же апплета, демонстрируя применение различных элементов экранного интерфейса. Апплет наш предназначен для пересчета денежных сумм из одной валюты в другую; его основная функция - принять от пользователя число (денежную сумму в некоей валюте), умножить его на определенный курс (коэффициент пересчета) и возвратить полученный результат.

СОВЕТ Фрагменты кода, приводимые в качестве примеров в этой главе, помещены на диск CDROM, прилагаемый к книге. Этим диском могут пользоваться те из читателей, кто работает с Windows 95/NT или Macintosh; пользователи UNIX должны обращаться к Web-странице Online Companion, на которой собраны сопроводительные материалы к этой книге (адрес http://www.vmedia.com/java.html).

Сравнение интерфейса пользователя Java и бланков на языке HTML

Если вам приходилось работать с бланками на языке HTML и составлять программы для работы на сервере, удовлетворяющие стандарту Common Gateway Interface (CGI), учтите, что возможности Java в этом отношении не идут ни в какое сравнение с возможностями HTML. Java обеспечивает более широкий набор инструментов и функций, а также обладает всеми преимуществами объектно-ориентированного подхода к дизайну интерфейса. Кроме того, уже написанные приложения, реализующие интерфейс CGI, могут использоваться совместно с Javaапплетами, включенными в HTML-страницу. Таким образом, вы можете перейти к разработке Java-апплетов вместо существующих HTML-бланков без необходимости существенно менять CGIпрограммы, обрабатывающие пользовательский ввод. Так, практический пример апплета, описанного в главе 17, использует ссылку на URL-адрес и метод POST протокола HTTP для посылки данных, введенных пользователем, специализированной CGI-программе на сервере.

Более того, теперь при необходимости обрабатывать данные из заполненных бланков вам даже не обязательно прибегать к CGI-программированию. Вы можете обрабатывать эти данные прямо в Java-апплете, работающем на компьютере пользователя. Тем самым можно заметно снизить нагрузку на Web-сервер - теперь ему не придется принимать данные и запускать CGIпрограммы каждый раз, когда пользователю потребуется поработать с бланком. Дополнительным преимуществом этого подхода является то, что Java-апплет может напрямую обращаться к любому Web-серверу. Характерный пример, в котором эта возможность может оказаться полезной, - интерфейс к базе данных, обычно реализуемый с помощью CGI: после того как пользователь заполнил бланк и отослал его, на Web-сервере запускается специальная CGIпрограмма, принимающая эти данные и отсылающая их на другой сервер, на котором и расположена база данных. Теперь Java-апплет может сразу обращаться к серверу базы данных, не загружая без нужды Web-сервер. Java позволяет напрямую обращаться к серверам баз данных с запросами, и уже существуют пакеты, предназначенные специально для этого.

Апплет пересчета денежных сумм

Представьте, что мы выполняем заказ туристического агентства, которое хочет, чтобы его клиенты через World Wide Web могли знакомиться с предлагаемыми маршрутами путешествий и ценами на билеты. Чтобы привлечь больше посетителей на свою страницу, агентство хочет предусмотреть удобную возможность пересчитывать денежные суммы из одной валюты в другую (например, для клиентов из других стран, которые хотят знать цены на услуги в знакомых им денежных единицах). Вы как администратор Web-сервера получаете задание разработать соответствующий механизм. Обдумав возможные варианты, вы приходите к выводу, что Javaапплет позволит сделать это гораздо удобнее и эффективнее, чем HTML-бланк в сочетании с CGIпрограммой. Процесс разработки такого апплета мы и рассмотрим в этой главе. По ходу дела вы познакомитесь с содержимым и возможностями классов AWT.

www.books-shop.com

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

Ввод с клавиатуры

В главе 5, "Апплет в работе", мы рассматривали концепцию событий и их обработки Javaпрограммой. Как вы помните, события одного типа, такие как проход курсора мыши над какой-то областью, могут относиться к некоторому объекту, в то время как другие осуществляют взаимодействие между объектами. Кроме того, события можно использовать для построения интерфейса пользователя, а именно - для перехвата воздействий пользователя на объекты интерфейса.

На рис. 7-1 показан простейший прототип апплета пересчета денежных сумм. В этой версии пользователь просто печатает число в текстовом поле ввода и нажимает Enter, чтобы увидеть результат пересчета. Для перехвата нажатия клавиши мы используем обработчик событий keyDown, в котором производится проверка на равенство нажатой клавиши значению "\n", что позволяет отфильтровать нажатие Enter и предусмотреть на эту клавишу особую реакцию. (Подробное описание классов TextField и TextArea вы найдете в следующем разделе.) Исходный текст этой версии нашего апплета приведен в примере 7-1.

Рис. 7.1.

Пример 7-1. Апплет пересчета денежных сумм, перехватывающий событие нажатия клавиши. import java.awt.*;

import java.applet.Applet;

public class currencyConverter1 extends java.applet.Applet { float conversion_ratio = 1.50f;

TextField field1 = new TextField(20); TextArea field2 = new TextArea(4,20);

//элементы экранного интерфейса для ввода/вывода

//(см. следующий раздел)

public void init() { field1.setEditable(true); field2.setEditable(false); field1.resize(field1.preferredSize()); field2.resize(field2.preferredSize()); add(field1);

add(field2);

show();

} // конец init public void convert() {

float currency1, currency2;

www.books-shop.com

String InputString = field1.getText(); field1.setText("");

currency1 = Float.valueOf(InputString).floatValue(); currency2 = conversion_ratio * currency1;

String OutputString =

"$" + InputString + " = " + "#" + Float.toString(currency2) + "\n"; field2.appendText(OutputString);

} // конец convert

public boolean keyDown(Event evt, int key)

//обработчик события нажатия клавиши

{char c=(char)key;

//преобразуем код клавиши к типу char для сравнения if (c == '\n')

//если нажата клавиша Enter, запускаем convert()

{ convert(); return true;

}

else { return false; }

}// конец KeyDown()

}// конец апплета currencyConverter1

Вэтом примере мы используем обработчик событий keyDown, перехватывающий событие нажатия клавиши. Ниже, в разделе "Флажки", мы также будем использовать нажатие клавиши Enter для запуска процедуры пересчета, но тогда мы будем пользоваться методом handleEvent. Этот метод представляет собой универсальный обработчик событий, с помощью которого можно перехватывать даже такие события, для которых в программе уже есть другие обработчики, и, таким образом, отбирать события, реакцию на которые вы хотите предусмотреть. (В примере, использующем флажки, вы увидите, как можно пользоваться этим обработчиком для перехвата нажатия клавиши Enter и щелчка мыши по флажку.) Таким образом, для перехвата событий существует несколько способов, и во многих случаях они вполне взаимозаменяемы как по своим функциям, так и по скорости работы. В тех апплетах, где вам будет нужно перехватывать много разных событий, наилучшим выбором будут универсальные обработчики событий, такие как handleEvent или action. Такие обработчики позволяют собрать весь код обработки событий в одном месте, что обычно выгодно с точки зрения удобочитаемости текста апплета и скорости его работы. Передача управления фрагменту, отвечающему за обработку конкретного события, чаще всего осуществляется оператором switch.

Кроме того, с помощью метода handleEvent можно обрабатывать целые последовательности событий, а также учитывать пространственные координаты событий в рамках апплета. Мы воспользуемся этим в примере, использующем флажки, в котором обработчик, перехватив событие, проверяет координаты курсора мыши, чтобы понять, где произошел щелчок - над флажком или где-то в другом месте. Множество других примеров обработки событий вы найдете как в главе 8, "Еще об интерфейсе пользователя", так и в других главах книги, особенно тех, в которых разрабатываются учебные апплеты.

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

Поле редактирования типа TextArea может использоваться в апплете как для вывода, так и для ввода и редактирования текста. Поля редактирования этого типа состоят из нескольких строк текста и имеют полосы прокрутки. Напротив, поля редактирования типа TextField состоят из одной строки и не имеют полос прокрутки. Как TextField, так и TextArea являются наследниками класса TextComponent и, за исключением упомянутых различий, во всем аналогичны друг другу. Поле типа TextField использовалось в приведенном выше примере апплета:

TextField field1 = new TextField(20); field1.setEditable(true);

В первой строке создается поле типа TextField шириной 20 символов. Во второй строке этому полю присваивается атрибут, разрешающий редактирование текста в нем. Если заменить во второй строке true на false, пользователь не сможет редактировать текст в поле.

Затем мы создаем поле типа TextArea шириной в 20 символов и высотой в 4 строки: TextArea field2 = new TextArea(4,20);

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

Вывод текста в поле редактирования из программы осуществляется одним из двух методов: field1.setText("");

www.books-shop.com

field2.appendText(OutputString);

Метод setText позволяет установить содержимое поля редактирования (в нашем случае пустая пара двойных кавычек позволяет очистить поле редактирования). Метод appendText позволяет приписать текстовую строку в конец текущего содержимого поля редактирования. Однако функция appendText() не начинает новую строку, если поле редактирования имеет в высоту несколько строк; чтобы перейти на новую строку, вы сами должны вставить в редактируемое значение символ новой строки.

Теперь нам следует позаботиться о размерах созданных полей редактирования. Дело в том, что, хотя каждое поле имеет свой изначальный, "естественный" размер, условия работы апплета могут привести к тому, что фактический размер будет другим. Чтобы явным образом приказать полю редактирования принять его натуральный размер, мы воспользуемся методом resize, а естественные размеры поля редактирования выясним с помощью метода preferredSize:

field1.resize(field1.preferredSize());

field2.resize(field2.preferredSize());

Теперь, когда объекты TextField и TextArea созданы и инициализированы, мы должны добавить их к интерфейсу нашего апплета. Для этого используется метод add. И наконец, чтобы вывести на экран все добавленные таким образом компоненты интерфейса, используется метод show. Вот что мы должны написать, чтобы увидеть созданные объекты field1 и field2:

add(field1);

add(field2);

show();

Существует много других методов, которые можно использовать для работы с полями редактирования. В табл. 7-1 перечислены методы, имеющиеся в обоих классах - как в TextField, так и в TextArea (все эти методы унаследованы из класса TextComponent).

 

Таблица 7-1. Методы класса TextComponent

Метод

Описание

getSelectedText()

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

getSelectionEnd()

Возвращает номер последнего выделенного символа.

getSelectionStart()

Возвращает номер первого выделенного символа.

getText()

Возвращает все содержимое поля.

isEditable()

Возвращает булевское значение, показывающее, разрешено ли

 

редактирование в поле.

paramString()

Возвращает значение типа String, содержащее параметры поля.

select(int, int)

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

 

начальным и конечным символами.

selectAll() Выделяет весь текст в поле.

setEditable(boolean) Запрещает или разрешает редактирование в поле в зависимости от передаваемого булевского значения.

setText(String) Выводит указанный текст в поле.

Класс TextField содержит меньше специфических методов, чем класс TextArea (так как некоторые из операций с многострочным полем редактирования не имеют смысла для поля из одной строки). Методы класса TextField перечислены в табл. 7-2.

 

Таблица 7-2. Методы класса TextField

Метод

Описание

echoCharlsSet()

Возвращает true, если данное поле имеет эхо-символ.

getColumns()

Возвращает ширину поля в символах.

getEchoChar()

Возвращает эхо-символ.

minimumSize(int)

Возвращает минимальный размер, который может иметь поле с

 

указанной шириной.

minimumSize()

Возвращает минимальный размер данного поля.

paramString()

Возвращает значение типа String, содержащее параметры поля.

preferredSize(int)

Возвращает естественный размер поля с указанной длиной.

www.books-shop.com

preferredSize() Возвращает естественный размер данного поля. setEchoCharacter(char) Устанавливает эхо-символ поля.

Класс TextArea имеет несколько разновидностей конструкторов. Один из них стоит в приведенном выше примере программы. В табл. 7-3 перечислены конструкторы класса TextArea, а в табл. 7-4 - методы этого класса.

 

Таблица 7-3. Конструкторы класса TextArea

Конструктор

Описание

TextArea()

Создает новый объект типа TextArea.

TextArea(int, int) Создает новый объект с указанным числом строк и символов в строке. TextArea(String) Создает новый объект, содержащий указанный текст.

TextArea(String, int, Создает новый объект с указанным числом строк и символов в строке,

int)

содержащий указанный текст.

 

 

Таблица 7-4. Методы класса TextArea

Метод

 

Описание

appendText(String)

 

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

getColumns()

 

Возвращает число символов в строке поля.

getRows()

 

Возвращает число строк в поле.

insertText(String, int)

Вставляет указанный текст после символа с указанным номером.

minimumSize(int, int)

Возвращает минимальный размер, который может иметь поле с

 

 

указанным количеством строк и символов в строке.

minimumSize()

 

Возвращает минимальный размер данного поля.

paramString()

 

Возвращает значение типа String, содержащее параметры поля.

preferredSize(int, int)

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

 

 

и символов в строке.

preferredSize()

 

Возвращает естественный размер данного поля.

replaceText(String, int, Заменяет текст, расположенный между символами с указанными int) номерами, на указанный текст.

Кнопки

Предыдущая версия апплета пересчета денежных сумм использовала для запуска пересчета нажатие клавиши Enter. Давайте теперь изменим апплет, добавив в него кнопку (button), с помощью которой пользователь сможет инициировать пересчет после ввода исходного значения. Вот как создается кнопка с надписью "Convert":

Button ConvertButton = new Button("Convert");

Именно так создается кнопка в примере 7-2 ниже. В этой версии мы не будем предусматривать перехват нажатия Enter, поскольку теперь вычисления запускаются только щелчком мыши по кнопке. Внешний вид этой версии апплета показан на рис. 7-2.

www.books-shop.com

Рис. 7.2.

Пример 7-2a. Апплет пересчета денежных сумм, содержащий кнопку. import java.awt.*;

import java.applet.Applet;

public class currencyConverter2 extends java.applet.Applet { float conversion_ratio = UKratio;

TextField field1 = new TextField(20); TextArea field2 = new TextArea(4,20); Button ConvertButton = new Button("Convert");

public void init() { field1.setEditable(true); field2.setEditable(false); field1.resize(field1.preferredSize()); field2.resize(field2.preferredSize()); add(field1);

add(field2);

add(ConvertButton);

show(); // вывод на экран созданных элементов } // конец метода init

Этот фрагмент кода обеспечивает создание кнопки с надписью "Convert", при нажатии которой введенное значение пересчитывается и выводится в соответствующее поле. Метод init используется для создания апплета. В поле field1 пользователь может вводить свое значение, а поле field2 предназначено для вывода и защищено от редактирования. Элементы экранного интерфейса добавляются в апплет с помощью метода add. Любой элемент для вывода на экран обязательно должен быть добавлен к некоторому контейнеру (в нашем случае контейнером по умолчанию является окно апплета). Метод resize приводит текстовые поля редактирования к заказанному для них размеру (в нашем случае 20 символов) с учетом ширины окна броузера.

Собственно пересчет осуществляется следующей функцией.

Пример 7-2b. Вычисления. public void convert() {

float currency1, currency2;

String InputString = field1.getText(); currency1 = Float.valueOf(InputString).floatValue(); currency2 = conversion_ratio * currency1; String OutputString = Float.toString(currency2); field2.setText(OutputString);

www.books-shop.com