Подробное руководство по программированию на Java

Базовые типы данных

Базовые типы данных

В языке Java определено восемь базовых типов данных. Для каждого базового типа данных отводится конкретный размер памяти. Этот размер, как мы говорили в предыдущем разделе, не зависит от платформы, на которой выполняется приложение Java:
Тип данных Размер занимаемой области памяти Значение по умолчанию
boolean 8 false
byte 8 0
char 16 'x0'
short 16 0
int 32 0
long 64 0
float 32 0.0F
double 64 0.0D
Фактически размеры памяти, отведенные для хранения переменной, могут отличаться от приведенных выше, например, для хранения переменной типа short может быть зарезервировано слово размером 32 бита. Однако язык Java сделан таким образом, что это никак не повлияет на мобильность приложения. Так как в языке Java нет указателей, вы не можете адресоваться к элементам массива чисел по относительному смещению этих элементов в оперативной памяти. Следовательно, точный размер элемента в данном случае не играет никакой роли.
Все базовые типы данных по умолчанию инициализируются, поэтому программисту не нужно об этом беспокоиться. Вы можете также инициализировать переменные базовых типов в программе или при их определении, как это показано ниже:
int nCounter = 0; int i; i = 8; Переменные типа boolean могут находиться только в двух состояниях - true и false, причем эти состояния никаким образом нельзя соотнести с целыми значениями. Вы не можете, как это было в языке С, выполнить преобразование типа boolean, например, к типу int - компилятор выдаст сообщение об ошибке.
Переменная типа byte занимает восемь бит памяти и про нее больше нечего сказать.
Что же касается типа char, то он используется для хранения символов в кодировке UNICODE. Эта кодировка позволяет хранить национальные наборы символов, что очень удобно для интернациональных приложений, предназначенных для работы в Internet.
Переменные типа byte, short, int и long являются знаковыми. В языке Java нет беззнаковых переменных, как это было в языке С.
Приложение Java может оперировать числами в формате с плавающей точкой, определенным в спецификации IEEE 754. Тип float позволяет хранить числа с одинарной точностью, а формат double - с двойной.
Переменные базовых типов могут передаваться функциям в качестве параметров только по значению, но не по ссылке. Поэтому следующий фрагмент кода работать не будет:
int x; void ChangeX(int x) { x = 5; } . . . x = 0; ChangeX(x); После вызова функции ChangeX содержимое переменной x останется равным нулю.
Проблему можно решить, если вместо базовых переменных использовать объекты встроенных классов, соответствующие базовым переменным. О встроенных классах вы узнаете из следующего раздела.

Библиотека классов java applet

Библиотека классов java.applet

Как нетрудно догадаться из названия, библиотека классов java.applet инкапсулирует поведение аплетов Java. Когда вы будете создавать свои аплеты, вам будет нужен класс Applet, расположенный в этой библиотеке классов. Дополнительно в библиотеке классов java.applet определены интерфейсы для подключения аплетов к содержащим их документам и классы для проигрывания звуковых фрагментов.

Библиотека классов java awt image

Библиотека классов java.awt.image

В среде любой операционной системы работа с графическими изображениями является достаточно сложной задачей. В операционной системе Windows для этого применяется графический интерфейс GDI. Если вы будете рисовать графические изображения в среде OS/2 или X-Windows, вам, очевидно, придется использовать другой программный интерфейс. Большую сложность также вызывает разбор заголовков графических файлов, так как они могут иметь различный формат и иногда содержат неправильную или противоречивую информацию.
Когда вы программируете на Java, рисование и обработка графических изображений выполняется намного проще, так как вам доступна специально предназначенная для этого библиотека классов java.awt.image. Помимо широкого разнообразия и удобства определенных в ней классов и методов, отметим способность этой библиотеки работать с графическими изображениями в формате GIF. Этот формат широко используется в Internet, так как он позволяет сжимать файлы графических изображений во много раз без потери качества за счет устранения избыточности.

Библиотека классов java awt peer

Библиотека классов java.awt.peer

Библиотека классов java.awt.peer служит для подключения компонент AWT (например, кнопок, списков, полей редактирования текстовой информации, переключателей и так далее) к реализациям, зависящим от платформы, в процессе создания этих компонент.

Библиотека классов java awt

Библиотека классов java.awt

Для создания пользовательского интерфейса аплеты Java могут и должны использовать библиотеку классов java.awt. AWT - это сокращение от Abstract Window Toolkit (инструментарий для работы с абстрактными окнами).
Классы, входящие в состав библиотеки java.awt, предоставляют возможность создания пользовательского интерфейса способом, не зависящим от платформы, на которой выполняется аплет Java. Вы можете создавать обычные окна и диалоговые панели, кнопки, переключатели, списки, меню, полосы просмотра, однострочные и многострочные поля для ввода текстовой информации.

Библиотека классов java io

Библиотека классов java.io

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

Библиотека классов java net

Библиотека классов java.net

Язык программирования Java разрабатывался в предположении, что им будут пользоваться для создания сетевых приложений. Поэтому было бы странно, если бы в составе среды разработки приложений Java не поставлялась библиотека классов для работы в сети. Библиотека классов java.net предназначена как раз для этого. Она содержит классы, с помощью которых можно работать с универсальными сетевыми адресами URL, передавать данные с использованием сокетов TCP и UDP, выполнять различные операции с адресами IP. Эта библиотека содержит также классы для выполнения преобразований двоичных данных в текстовый формат, что часто бывает необходимо.
В качестве примера приложения, составленного на языке программирования Java и ориентированного на работу в сети Internet, можно привести игру Java Color Lines (Рисунок 7).


Библиотека классов java util

Библиотека классов java.util

Библиотека классов java.util очень полезна при составлении приложений, потому что в ней имеются классы для создания таких структур, как динамические массивы, стеки и словари. Есть классы для работы с генератором псевдослучайных чисел, для разбора строк на составляющие элементы (токены), для работы с календарной датой и временем.

Библиотеки классов Java

Библиотеки классов Java

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

Браузеры

Браузеры

Для проверки работы аплетов вам следует установить браузер, способный работать с аплетами Java. Такая возможность есть во всех современных браузерах, поэтому вы можете выбрать любой из них. Лучше всего проверять работу создаваемых вами аплетов в различных браузерах. Это позволит вам обнаружить и решить проблемы несовместимости, прежде чем с ними столкнется пользователь.

Документация и литература

Документация и литература

На прилавках книжных магазинов вы можете найти несколько отечественных и переводных книг, посвященных программированию на языке Java. Большинство из них ориентировано на инструментарий JDK, созданный фирмой Sun, и содержат более или менее подробное описание классов Java.
Среди удачных назовем книгу Стефана Дэвиса с названием "Learn Java Now", которая может служить учебником по языку Java для тех, кто никогда не программировал на С и С++.
Среди переводных книг, которые можно встретить в продаже, отметим книгу Джона Родли "Создание JAVA-апплетов". Эта книга рассчитана на серьезных программистов, хорошо знающих язык программирования Java. Однако для тех, кто только начинает изучать язык Java, она может оказаться слишком сложной.
Другая книга, заслуживающая внимание, это книга Криса Джамса с названием "Java". После небольшого введения, рассчитанного на начинающих, в этой книге приводится описание более чем дюжины достаточно интересных аплетов с исходными текстами и комментариями.
Через сеть Internet вам доступны не только бесплатные средства разработки приложений и аплетов Java, но и грандиозные запасы документации и примеров программ.
В качестве отправной точки для поиска вы можете выбрать сервер разработчика этого языка - фирмы Sun Microsystems, расположенный по адресу http://www.sun.com. Помимо документации и примеров программ на Java, здесь вы найдете ссылки на другие ресурсы, посвященные этому языку программирования. Попробуйте также воспользоваться поисковыми серверами, такими как Yahoo! и Alta Vista, указав в качестве ключевого слово "Java".
Обращаем ваше внимание на cловарь Java-терминов, подготовленный Sun Microsystems специально для российских разработчиков приложений Java.
Вы также можете ознакомиться с примерами приложений Java, которые находятся на российском сервере Sun Microsystems.

Другие встроенные классы

Другие встроенные классы

Среди других встроенных классов отметим класс Math, предназначенный для выполнения математических операций, таких как вычисление синуса, косинуса и тангенса.
Предусмотрены также классы для выполнения запуска процессов и потоков, управления системой безопасности, а также для решения прочих системных задач.
Библиотека встроенных классов содержит очень важные классы для работы с исключениями. Эти классы нужны для обработки ошибочных ситуаций, которые могут возникнуть (и возникают!) при работе приложений или аплетов Java.

Инструментарий разработчика

Инструментарий разработчика

Первоначально средства разработки приложений и аплетов Java были созданы фирмой Sun Microsystems и до сих пор они пользуются популярностью. В сети Internet по адресу http://java.sun.com вы можете бесплатно получить набор Java Development Kit (JDK).

Инструментарий

Инструментарий


Интегрированные средства разработки

Интегрированные средства разработки

Для тех, кто привык пользоваться визуальными средствами разработки, доступны два других инструмента, созданных в Sun Microsystems. Это Java WorkShop 2.0 и Java Studio 1.0.
Интегрированная система разработки приложений Java WorkShop 2.0 содержит традиционные и визуальные средства программирования, отладчик, обширную справочную систему по классам и языку Java. С помощью Java WorkShop 2.0 вы можете создавать автономные приложения Java, аплеты, компоненты JavaBeans и собственные библиотеки классов.
На Рисунок 1 мы показали внешний вид главного окна приложения Java WorkShop 2.0.


Интерфейсы

Интерфейсы

Интерфейсы создаются при помощи ключевого слова interface таким же образом, что и классы. Однако в отличие от последних, интерфейсы являются аналогом абстрактных базовых классов без полей данных и предназначены только для определений набора методов для решения каких-либо задач, например, добавления компонент в контейнеры, организации списков, сортировки и так далее.
Вы можете создать свой класс на базе другого класса, указав при этом с помощью ключевого слова implements, что он реализует тот или иной интерфейс. При этом наряду с методами базового класса в созданном таким образом классе будут доступны методы, определенные в интерфейсе.

Класс String

Класс String

Класс String предназначен для работы с такими часто встречающимися объектами, как текстовые строки. Методы этого класса позволяют выполнять над строками практически все операции, которые вы делали раньше при помощи библиотечных функций C. Это преобразование строки в число и обратно с любым заданным основанием, определение длины строки, сравнение строк, извлечение подстроки и так далее.
Хотя в языке Java не допускается перезагрузка (переопределение) операторов, для объектов класса Stirng и объектов всех произошедших от него классов сделана встроенная перезагрузка операторов "+" и "+=". С помощью этих операторов можно выполнять слияние текстовых строк, например:
System.out.println("x = " + x + '\n'); Здесь в качестве параметра функции println передается текстовая строка, составленная из трех компонент: строки "x = ", числа x и символа перехода на следующую строку '\n'. Значение переменной x автоматически преобразуется в текстовую строку (что выполняется только для текстовых строк) и полученная таким образом текстовая строка сливается со строкой "x= ".

Классы Java

Классы Java


Массивы в Java

Массивы в Java

Для создания массива вы можете пользоваться квадратными скобками, расположив их справа от имени массива или от типа объектов, из которых составлен массив, например:
int nNumbers[]; int[] nAnotherNumbers; Допустимы оба варианта, поэтому вы можете выбрать тот, который вам больше нравится.
При определении массивов в языке Java нельзя указывать их размер. Приведенные выше две строки не вызывают резервирования памяти для массива. Здесь просто создаются ссылки на массивы, которые без инициализации использовать нельзя.
Для того чтобы заказать память для массива, вы должны создать соответствующие объекты с помощью ключевого слова new, например:
int[] nAnotherNumbers; nAnotherNumbers = new int[15]; Как выполнить инициализацию ячеек таблицы?
Такую инициализацию можно выполнить либо статически, либо динамически. В первом случае вы просто перечисляете значения в фигурных скобках, как это показано ниже:
int[] nColorRed = {255, 255, 100, 0, 10}; Динамическая инициализация выполняется с использованием индекса массива, например, в цикле:
int nInitialValue = 7; int[] nAnotherNumbers; nAnotherNumbers = new int[15]; for(int i = 0; i < 15; i++) { nAnotherNumbers[i] = nInitialValue; } Вы можете создавать массивы не только из переменных базовых типов, но и из произвольных объектов. Каждый элемент такого массива должен инициализироваться оператором new.
Массивы могут быть многомерными и, что интересно, несимметричными.
Ниже создается массив массивов. В нулевом и первом элементе создается массив из четырех чисел, а во втором - из восьми:
int[][] nDim = new int[5][10]; nDim[0] = new int [4]; nDim[1] = new int [4]; nDim[2] = new int [8]; Заметим, что во время выполнения приложения виртуальная машина Java проверяет выход за границы массива. Если приложение пытается выйти за границы массива, происходит исключение.
Массивы в языке Java являются объектами некоторого встроенного класса. Для этого класса существует возможность определить размер массива, обратившись к элементу данных класса с именем length, например:
int[] nAnotherNumbers; nAnotherNumbers = new int[15]; for(int i = 0; i < nAnotherNumbers.length; i++) { nAnotherNumbers[i] = nInitialValue; } Для определения размера массива вам не нужен такой оператор, как sizeof из языка программирования С, потому что существует другой способ определения этого размера.

Массивы

Массивы


Мобильность Java

Мобильность Java

В свое время вы слышали, что язык программирования С является мобильным. Это нужно понимать в том смысле, что имеется принципиальная возможность переноса программ C на различные платформы.
Однако следует отметить, что создание приложений, действительно работающих на разных платформах - непростая задача. К сожалению, дело не ограничивается необходимостью перекомпиляции исходного текста программы для работы в другой среде. Много проблем возникает с несовместимостью программных интерфейсов различных операционных систем и графических оболочек, реализующих пользовательский интерфейс.
Вспомните хотя бы проблемы, связанные с переносом 16-разрядных приложений Windows в 32-разрядную среду Windows 95 и Windows NT. Даже если вы тщательно следовали всем рекомендациям, разрабатывая приложения так, чтобы они могли работать в будущих версиях Windows, едва ли вам удастся просто перекомпилировать исходные тексты, не изменив в них ни строчки. Ситуация еще больше ухудшается, если вам нужно, например, перенести исходные тексты приложения Windows в среду операционной системы OS/2 или в оболочку X-Windows операционной системы UNIX. А ведь есть еще другие компьютеры и рабочие станции!
Как нетрудно заметить, даже если стандартизовать язык программирования для всех платформ, проблемы совместимости с программным интерфейсом операционной системы значительно усложняют перенос программ на различные платформы. И, конечно, вы не можете мечтать о том, чтобы загрузочный модуль одной и той же программы мог работать без изменений в среде различных операционных систем и на различных платформах. Если программа подготовлена для процессора Intel, она ни за что не согласится работать на процессоре Alpha или каком-либо другом.
В результате создавая приложение, способное работать на различных платформах, вы вынуждены фактически делать несколько различных приложений и сопровождать их по отдельности.
На Рисунок 5 мы показали, как приложение, изначально разработанное для Windows NT, переносится на платформу Apple Macintosh.



Мобильность

Мобильность


Наследование

Наследование

С помощью ключевого слова extends вы можете унаследовать один класс (дочерний) от другого (базового).
Множественное наследование не допускается. Таким образом, для каждого дочернего класса может быть только один базовый класс. При необходимости, однако, этот дочерний класс может реализовывать произвольное количество интерфейсов.
Для ссылки на методы базового класса вы должны использовать ключевое слово super.
При необходимости вы можете вызвать в первой исполняемой строке конструктора дочернего класса конструктор базового класса (опять же с помощью ключевого слова super).

Определение класса

Определение класса

Для создания классов вы можете использовать только ключевое слово class. Что же касается union, то это ключевое слово в Java не применяется.
В языке программирования С++ описание класса может быть отделено от его определения. Для Java это не так - описание класса недопустимо. Все методы должны быть определены внутри определения класса.
Недопустимо определение вложенных классов.
В Java также нет шаблонов. Вы можете создавать классы только на базе других классов.
Объект класса создается при помощи ключевого слова new, однако вы не можете удалить объект явным образом, так как ключевое слово delete языка программирования С++ в Java не используется.
При определении класса вы не можете указать деструктор. Функции удаления объектов Java из памяти выполняет система сборки мусора.
Внутри одного исходного файла вы можете определить только один общедоступный класс public.
Все классы в Java наследуются от класса Object, поэтому для любого объекта вы можете использовать методы этого класса.

Определение методов

Определение методов

Вы не можете определять методы вне тела класса, создавая таким образом глобальные функции. Нет также возможности определения вне класса глобальных данных. Тем не менее, внутри класса можно определять статические методы и поля (с помощью ключевого слова static), которые будут играть роль глобальных методов и данных.
Пользуясь ключевыми словами static и final, можно определять внутри классов глобальные константы.
Если в базовом классе метод определен с ключевым словом final, его нельзя переопределить в дочернем классе, созданном на базе данного метода.
Методы не могут быть определены как inline.
Методы Java могут создавать исключения, вызванные возникновением ошибок или других событий. Все исключения должны либо обрабатываться внутри метода, либо описываться в определении метода после ключевого слова throws.

Особенности реализации классов в Java

Особенности реализации классов в Java

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

Пакетные средства

Пакетные средства

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

Переопределение операторов

Переопределение операторов

В языке С++ вы могли переопределить операторы, такие как +, -, ++ и так далее. Язык Java не допускает переопределение, что сделано для упрощения программирования. Тем не менее, операторы "+" и "+=" перегружены по умолчанию для выполнения операции слияния текстовых строк класса String.

Подключаемые библиотеки классов

Подключаемые библиотеки классов

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

Подключение к Internet

Подключение к Internet

Заметим, что для запуска аплетов вам не нужно обязательно подключаться к Internet - вы можете встраивать аплеты в документы HTML, расположенные на локальном диске вашего компьютера и просматривать эти документы браузером просто как локальные файлы.
Автономные приложения Java работают под управлением специального интерпретатора (виртуальной машины Java), поэтому для их отладки вам также не потребуется сеть Internet.
Однако есть одно важное обстоятельство - аплеты, взаимодействующие с расширениями сервера Web, должны быть загружены именно с этого сервера. В противном случае их работа будет заблокирована по соображениям безопасности.
Если вы собираетесь проверять работу приложений и аплетов Java, взаимодействующих с сервером Web, вы можете воспользоваться собственным сервером в Internet или в корпоративной сети Intranet (если они у вас есть). Можно также установить сервер Web, входящий в комплект операционной системы Windows NT Workstation версии 4.0, или Personal Web Service для операционной системы Windows 95.

Реализация классов

Реализация классов


Главное окно приложения


Рисунок 1. Главное окно приложения .Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Среди основных возможностей Java WorkShop 2.0 назовем синтаксическое выделение в окне редактирования, возможность удаленной отладки приложений Java, быстродействующий компилятор, а также способность работать на различных платформах.

Главное окно приложения

Разработку элементов пользовательского интерфейса можно выполнять с помощью удобного средства визуального проектирования (Рисунок 2).


Java WorkShop 2 0 позволяет

Рисунок 2. Java WorkShop 2.0 позволяет разрабатывать пользовательский интерфес с помощью визуальных средств.Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Что же касается Java Studio 1.0, то эта система позволяет проектировать приложения вообще без программирования. Разработчик собирает приложения из готовых компонент, устанавливая между ними каналы передачи сообщений. Таким образом определяется логика работы приложения (Рисунок 3). Этот процесс чем-то напоминает сборку бытовой стереофонической системы из отдельных блоков, когда вы соединяете проводами входы и выходы усилителя, колонок, проигрывателя компакт-дисков и других устройств.

Java WorkShop 2 0 позволяет


Рисунок 2. Визуальные средства разработки

Рисунок 2. Визуальные средства разработки Java WorkShop 2.0

Рисунок 2. Визуальные средства разработки

Проектирование логики работы приложения

Рисунок 3. Проектирование логики работы приложения


Проектирование логики работы приложения



Проектирование логики

Рисунок 3. Проектирование логики работы приложения.Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
В наборе компонент JavaBeans, доступных в Java Studio, есть компоненты, предназначенные для работы с ресурсами Internet, базами данных и таблицами, формами и так далее.

Проектирование логики

Проектирование пользовательского интерфейса в Java Studio, также как и в Java WorkShop, выполняется визуально (Рисунок 4).


Визуальное проектирование

Рисунок 4. Визуальное проектирование пользовательского интерфейса.Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Подборку различных инструментальных средств, предназначенных для создания приложений Java, вы найдете по адресу http://www.sun.ru/download/download.html.

Визуальное проектирование


Рисунок 4. Визуальное проектирование пользовательского интерфейса


Визуальное проектирование



Перенос приложения с

Рисунок 5. Перенос приложения с платформы Windows NT на платформу Macintosh

Перенос приложения с
Вначале программист готовит исходные тексты приложения для платформы Windows NT и отлаживает их там. Для получения загрузочного модуля исходные тексты компилируются и редактируются. Полученный в результате загрузочный модуль может работать на процессоре фирмы Intel в среде операционной системы Windows NT.
Для того чтобы перенести приложение в среду операционной системы компьютера Macintosh, программист вносит необходимые изменения в исходные тексты приложения. Эти изменения необходимы из-за различий в программном интерфейсе операционной системы Windows NT и операционной системы, установленной в Macintosh. Далее эти исходные тексты транслируются и редактируются, в результате чего получается загрузочный модуль, способный работать в среде Macintosh, но не способный работать в среде Windows NT.
Программа на языке Java компилируется в двоичный модуль, состоящий из команд виртуального процессора Java. Такой модуль содержит байт-код, предназначенный для выполнения Java-интерпретатором. На настоящий момент уже созданы первые модели физического процессора, способного выполнять этот байт-код, однако интерпретаторы Java имеются на всех основных компьютерных платформах. Разумеется, на каждой платформе используется свой интерпретатор, или, точнее говоря, свой виртуальный процессор Java.
Если ваше приложение Java (или аплет) должно работать на нескольких платформах, нет необходимости компилировать его исходные тексты несколько раз. Вы можете откомпилировать и отладить приложение Java на одной, наиболее удобной для вас платформе. В результате вы получите байт-код, пригодный для любой платформы, где есть виртуальный процессор Java.
Сказанное иллюстрируется на Рисунок 6.



Подготовка приложения

Рисунок 6. Подготовка приложения Java для работы на разных платформах

Подготовка приложения
Таким образом, приложение Java компилируется и отлаживается только один раз, что уже значительно лучше. Остается, правда, вопрос - как быть с программным интерфейсом операционной системы, который отличается для разных платформ?
Здесь, на наш взгляд, разработчиками Java предлагается достаточно неплохое решение. Приложение Java не обращается напрямую к интерфейсу операционной системы. Вместо этого оно пользуется готовыми стандартными библиотеками классов, содержащими все необходимое для организации пользовательского интерфейса, обращения к файлам, для работы в сети и так далее.
Внутренняя реализация библиотек классов, разумеется, зависит от платформы. Однако все загрузочные модули, реализующие возможности этих библиотек, поставляются в готовом виде вместе с виртуальной машиной Java, поэтому программисту не нужно об этом заботиться. Для операционной системы Windows, например, поставляются библиотеки динамической загрузки DLL, внутри которых запрятана вся функциональность стандартных классов Java.
Абстрагируясь от аппаратуры на уровне библиотек классов, программисты могут больше не заботиться о различиях в реализации программного интерфейса конкретных операционных систем. Это позволяет создавать по-настоящему мобильные приложения, не требующие при переносе на различные платформы перетрансляции и изменения исходного текста.
Еще одна проблема, возникающая при переносе программ, составленных на языке программирования С, заключается в том, что размер области памяти, занимаемой переменными стандартных типов, различный на разных платформах. Например, в среде операционной системы Windows версии 3.1 переменная типа int в программе, составленной на С, занимает 16 бит. В среде Windows NT этот размер составляет 32 бита.
Очевидно, что трудно составлять программу, не зная точно, сколько имеется бит в слове или в байте. При переносе программ на платформы с иной разрядностью могут возникать ошибки, которые трудно обнаружить.
В языке Java все базовые типы данных имеют фиксированную разрядность, которая не зависит от платформы. Поэтому программисты всегда знают размеры переменных в своей программе.

Сетевая игра Java Color Lines

Рисунок 7. Сетевая игра Java Color Lines


Сетевая игра Java Color Lines



Сетевая игра Java Color

Рисунок 7. Сетевая игра Java Color Lines.Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Это сетевая версия известной игры Lines, которая выполнена в виде нескольких аплетов, взаимодействующих между собой и между сервером Web, на котором они расположены. Так как список имен игроков и достигнутых ими результатов хранится на сервере, вы можете поучаствовать в мировом турнире, сразившись с игроками из разных стран.

Сетевая игра Java Color

Сборка мусора


Сборка мусора

Одна из интереснейших особенностей языка программирования Java и среды выполнения приложений Java заключается в наличии специального процесса сборки мусора, предназначенного для удаления ненужных объектов из памяти. Эта система избавляет программиста от необходимости внимательно следить за использованием памяти, освобождая ненужные более области явным образом.
Создавая объекты в Java, вы можете руководствоваться принципом "создай и забудь", так как система сборки мусора позаботится об удалении ваших объектов. Объект будет удален из памяти, как только на него не останется ни одной ссылки из других объектов.
Приоритет процесса сборки мусора очень низкий, поэтому "уборка" среды выполнения приложений Java не отнимает ресурсы у самих приложений.

Ссылки на методы класса

Ссылки на методы класса

Так как в Java нет указателей, нет возможности ссылаться на методы с помощью оператора ->. Для ссылки на метод класса используется только оператор "точка".
Оператор "::" также не определен в Java. Если вам необходимо вызвать метод из базового класса, следует использовать ключевое слово super.

Типы данных

Типы данных


Указатели которых нет

Указатели, которых нет

Самая большая и шокирующая новость для тех, кто раньше программировал на С, а теперь занялся изучением Java, это то, что в языке Java нет указателей. Традиционно считалось, что работать с указателями трудно, а их использование приводит к появлению трудно обнаруживаемых ошибок. Поэтому разработчики Java решили отказаться от использования указателей совсем.
Спешим успокоить - вы сможете успешно составлять приложения Java и без указателей, несмотря на то что вам, возможно, придется немного изменить стиль программирования.
Вы можете спросить: как же передавать функциям ссылки на объекты, если нет указателей?
Если вам нужно передать ссылку на переменную базового типа, такого, например, как int или long, то ничего не получится - мы уже говорили, что переменные базовых типов передаются по значению, а не по ссылке. Поэтому нельзя напрямую создать на языке Java эквивалент следующей программы, составленной на языке С:
// Некоторая переменная int nSomeValue; // Функция, изменяющая значение переменной, // заданной своим адресом void StoreValue(int *pVar, int nNewValue) { pVar->nNewValue; } . . . StoreValue(&nSomeValue, 10); Выход, однако, есть.
Язык Java позволяет использовать вместо указателей ссылки на объекты. Пользуясь этими ссылками, вы можете адресовать объекты по их имени, вызывая методы и изменяя значения данных объектов.
Что же касается данных базовых типов, если вам нужно передавать на них ссылки, то следует заменить базовые типы на соответствующие замещающие классы. Например, вместо типа int используйте класс Integer, вместо типа long - класс Long и так далее.
Инициализация таких объектов должна выполняться с помощью конструктора, как это показано ниже:
Integer nSomeValue; nSomeValue = new Integer(10); Первая строка создает неинициализированную ссылку с именем nSomeValue и типом Integer. При попытке использования такой ссылки возникнет исключение.
Вторая строка создает объект класса Integer, вызывая конструктор. Этот конструктор определяет начальное значение. После выполнения оператора присваивания ссылка nSomeValue будет ссылаться на реальный объект класса Integer и ее можно будет использовать.
Имя объекта nSomeValue типа Integer вы можете передавать функциям в качестве параметра, причем это будет ссылкой на объект.
Составляя программы на языке С, вы часто использовали указатели для адресации элементов массивов, созданных статически или динамически в оперативной памяти. Зная начальный адрес такого массива и тип хранящихся в нем элементов, вы могли адресоваться к отдельным элементам массива.
В языке Java реализован механизм массивов, исключающих необходимость использования указателей.

Указатели

Указатели


Встроенные классы

Встроенные классы

В языке Java все классы происходят от класса Object, и, соответственно, наследуют методы этого класса. Некоторые библиотеки классов подключаются автоматически, и мы будем называть их встроенными. К таким относится, в частности, библиотека с названием java.lang. Другие библиотеки классов вы должны подключать в исходном тексте приложения Java явным образом с помощью оператора import.

Замещающие классы

Замещающие классы

Очень часто в наших приложениях вместо базовых типов переменных мы будем использовать объекты встроенных классов, которые называются замещающими классами (wrapper classes). Ниже мы перечислили названия этих классов и названия базовых типов данных, которые они замещают:
Базовый тип данных Замещающий класс
boolean Boolean
char Character
int Integer
long Long
float Float
double Double
Заметим, что для преобразования базовых типов данных в объекты замещающего класса и обратно вы не можете применять оператор присваивания. Вместо этого необходимо использовать соответствующие конструкторы и методы замещающих классов.

Подробное руководство по программированию на Java

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

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

Исходный текст нашего первого приложения состоит всего из нескольких строк:
public class HelloJava { public static void main(String args[]) { System.out.println("Hello, Java!"); } } По своей простоте он не уступает известной программе "Hello, world!", с которой обычно начинают изучение языка программирования C.
В нашем приложении определен один класс типа public с именем HelloJava. Заметим, что исходный файл приложения Java может содержать только один класс public, причем имя файла должно в точности совпадать с именем такого класса. В данном случае исходный файл называется HelloJava.java. Если бы вы назвали файл helloJava.java, компилятор выдал бы сообщение об ошибке.
В классе HelloJava мастером проектов автоматически создается один статический метод с именем main.
Если класс типа public с именем, совпадающем с именем файла, содержит определение метода main, то такой метод служит точкой входа автономного приложения Java. В этом он напоминает функцию main обычной программы, составленной на языке программирования C.
В качестве параметра методу main передается ссылка на массив строк класса String. Через эти строки вы можете передавать приложению Java параметры запуска.
Как наше приложение выводит текстовую строку на консоль?
В классе System определена переменная класса PrintStream с именем out. В классе PrintStream определен метод println, при помощи которого приложение HelloJava выводит сообщение "Hello, Java!" на консоль.
Но где же объект, для которого вызывается метод println? В классе System поле PrintStream определено как статическое, поэтому методы этого класса можно вызывать, не создавая объектов класса System.

Первое приложение Java

Первое приложение Java

Как мы уже говорили, приложение Java может выполняться под управлением специального интерпретатора, работающего в рамках отдельного процесса, либо под управлением браузера. В первом случае мы имеем дело с автономным приложением Java, в втором - с аплетом.
Изучение программирования на Java мы начнем с создания простейшего автономного приложения. В следующей статье мы расскажем о том, как сделать аплет и встроить его в документ HTML.
В качестве инструментального средства для разработки автономных приложений и аплетов Java мы будем использовать интегрированную систему разработки Java WorkShop. Она доступна для операционных систем Windows 95, Windows NT, Solaris (платформы SPARC и Intel).

Первое приложение

Первое приложение


Главное окно интегрированной

Рисунок 1. Главное окно интегрированной системы разработки Java WorkShopДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Главное окно интегрированной Рисунок 2. Окно Java WorkShop Startup

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Если раньше вы никогда не работали с Java WorkShop, окно Java WorkShop Startup поможет вам освоиться с основными процедурами. Нажав соответствующую кнопку, вы можете создать свой первый проект, открыть пример проекта, подготовленного для вас специалистами Sun Microsystems, ознакомиться с электронным руководством или справочной системой, а также открыть любой существующий проект.

Главное окно интегрированной

После приобретения небольшой практики можно включить переключатель Don't show me this window at startup, и окно Java WorkShop Startup перестанет появляться всякий раз, когда вы запускаете Java WorkShop.

Окно Java WorkShop Startup

Рисунок 2. Окно Java WorkShop Startup


Окно Java WorkShop Startup



Окно Java WorkShop Project Manager

Рисунок 3. Окно Java WorkShop Project Manager

Окно Java WorkShop Project Manager
Все проекты хранятся в портфелях (portfolios). В процессе установки автоматически создается ваш личный портфель personal, который находится в папке My Portfolios. В этом портфеле есть проекты Checkers, CardFile, JellyBeanExample и Performance Example. При создании нового проекта мы добавим его в портфель personal, хотя в дальнейшем вы сможете создавать новые портфели.
Прежде чем выполнять какие либо операции над портфелем или проектом, нужно сделать этот портфель или проект текущим. Чтобы выбрать текущий портфель или проект, следует сделать двойной щелчок левой клавишей мыши по соответствующему названию. Строка названия будет выделена синим цветом.
Для создания проекта HelloJava выберите из меню File окна Java WorkShop Project Manager строку New, а затем в меню второго уровня строку Project. В результате будет запущен мастер создания проектов, первая диалоговая панель которого показана на Рисунок 4.


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

Рисунок 4. Первая диалоговая панель мастера проектов


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



Первая диалоговая панель

Рисунок 4. Первая диалоговая панель мастера проектовДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
В поле Please, name this project введите название создаваемого проекта HelloJava, затем включите переключатели Standalone и No GUI. Первый из этих переключателей задает тип проекта (автономное приложение Java), второй указывает, что в проекте не используются средства автоматизированного проектирования пользовательского интерфейса.

Первая диалоговая панель

Далее нажмите кнопку Next. Вы окажитесь в диалоговой панели Create Project, показанной на Рисунок 5.


Диалоговая панель Create Project

Рисунок 5. Диалоговая панель Create Project


Диалоговая панель Create Project



Диалоговая панель Create

Рисунок 5. Диалоговая панель Create ProjectДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
В верхней части этой панели вы должны ввести путь к каталогу, в котором будут создаваться файлы проекта. Затем следует включить переключатель No, указывая тем самым, что каталог проектов пуст и в нем нужно создать новые файлы. Существует возможность создания проектов на базе уже имеющихся файлов, однако пока мы этого делать не будем.

Диалоговая панель Create

Теперь все готово к созданию проекта и вы можете нажать кнопку Finish. Мастер проектов создаст все необходимые файлы и сделает новый проект текущим. Основной файл проекта окажется загруженным в главное окно приложения Java WorkShop (Рисунок 6). Здесь вы можете его редактировать.


Основной файл созданного

Рисунок 6. Основной файл созданного проекта загружен в окно приложения Java WorkShopДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Если теперь вы раскроете окно Java WorkShop Project Manager, то увидите, что в портфеле personal появился новый проект HelloJava. Раскрыв его, можно увидеть включенные в него файлы (Рисунок 7).

Основной файл созданного

Файлы проекта HelloJava

Рисунок 7. Файлы проекта HelloJava.

Файлы проекта HelloJava
Наш проект содержит только один файл с именем HelloJava.java. Отредактируйте этот файл, добавив в него следующую строку:
System.out.println("Hello, Java!"); Новый вариант исходного текста показан на Рисунок 8.


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

Рисунок 8. Измененный исходный текст приложения HelloJava


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



Измененный исходный

Рисунок 8. Измененный исходный текст приложения HelloJavaДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Теперь выберите из меню Build главного окна Java WorkShop строку Build All. Через несколько мгновений исходные тексты приложения будут оттранслированы. Результат вы сможете увидеть нас странице Build блокнота, расположенного в нижней части окна Java WorkShop.

Измененный исходный

Чтобы запустить приложение, выберите из меню Project строку Run. На экране появится консоль приложения с сообщением "Hello, Java!" (Рисунок 9).

Работа приложения Hello Java!

Рисунок 9. Работа приложения Hello, Java!


Работа приложения Hello Java!


Создание нового проекта

Создание нового проекта

Как и многие другие интегрированные системы разработки программного обеспечения, система Java WorkShop использует концепцию проектов. Под проектом здесь понимается совокупность файлов и параметров, описанные в специальном файле проектов.
Всеми проектами в Java WorkShop управляет менеджер проектов. Чтобы открыть его окно, показанное на Рисунок 3, выберите строку Show Project Manager из меню Project главного окна Java WorkShop.

Текст HelloJava

Текст HelloJava


Установка Java WorkShop

Установка Java WorkShop

Для установки Java WorkShop вы должны вставить дистрибутивный диск в устройство чтения CD-ROM. Программа установки запустится автоматически. Если этого не произошло (например, потому что автоматический запуск заблокирован), следует запустить программу установки вручную.
Если вы работаете в среде Windows 95 или Windows NT, вам нужно запустить программу setup.exe из каталога Win32. На дистрибутивном диске Java WorkShop есть также установочные каталоги для других платформ.
Процедура установки очень проста. Достаточно следовать инструкциям, которые появляются на экране. Единственное, что необходимо выбрать - это путь к каталогу, в который будут скопированы файлы Java WorkShop. При этом следует учесть, что для установки Java WorkShop в среде Windows 95 или Windows NT требуется примерно 50 Мбайт дисковой памяти.

Установка WorkShop

Установка WorkShop


Запуск Java WorkShop

Запуск Java WorkShop


Подробное руководство по программированию на Java

Иерархия классов

Иерархия классов

Заглянем в документацию. Выберите из меню Help главного окна приложения Java WorkShop строку Java API Documentation. На экране появится окно браузера, встроенного в Java WorkShop. С помощью этого браузера вы сможете просматривать содержимое справочной системы.
В разделе Java API Packages выберите библиотеку классов java.applet, а затем в разделе Class Index - строку Applet. Вы увидите иерархию классов:
java.lang.Object | +---java.awt.Component | +---java.awt.Container | +---java.awt.Panel | +---java.applet.Applet Из этой иерархии видно, что класс java.applet.Applet произошел от класса java.awt.Panel. Этот класс, в свою очередь, определен в библиотеке классов java.awt и произошел от класса java.awt.Container.
Продолжим наши исследования. В классе java.awt.Container снова нет метода paint, но сам этот класс создан на базе класса java.awt.Component.
Но и здесь метода paint нет. Этот метод определен в классе java.awt.Component, который, в свою очередь, произошел от класса java.lang.Object и реализует интерфейс java.awt.image.ImageObserver.
Таким образом мы проследили иерархию классов от класса java.applet.Applet, на базе которого создан наш аплет, до класса java.lang.Object, который является базовым для всех классов в Java.
Метод paint определен в классе java.awt.Component, но так как этот класс является базовым для класса Applet и для нашего класса HelloApplet, мы можем переопределить метод paint.

Исходный текст аплета

Исходный текст аплета


Исходный текст документа HTML

Исходный текст документа HTML


Изменяем исходный текст аплета

Изменяем исходный текст аплета

Теперь давайте попробуем немного изменить исходный текст аплета, чтобы заставить его рисовать в своем окне текстовую строку "Hello, Java world".
Вначале измените исходный текст так, как это показано на Рисунок 6.


public class HelloApplet extends Applet

Листинг 1

. Файл HelloApplet.java import java.applet.Applet; public class HelloApplet extends Applet { /** * Initializes the applet. You never need to * call this directly; it is * called automatically by the system once the * applet is created. */ public void init() {} /** * Called to start the applet. You never need * to call this directly; it * is called when the applet's * document is visited. */ public void start() {} /** * Called to stop the applet. This is called * when the applet's document is * no longer on the screen. It is guaranteed * to be called before destroy() * is called. You never need to * call this method directly */ public void stop() {} /** * Cleans up whatever resources are being held. * If the applet is active * it is stopped. */ public void destroy() {} } Из-за обилия комментариев вы можете подумать, что исходный текст аплета, который ничего не делает, слишком сложный. Однако это вовсе не так. Вот что получится, если мы уберем все комментарии:
import java.applet.Applet; public class HelloApplet extends Applet { public void init() {} public void start() {} public void stop() {} public void destroy() {} } Исходный текст нашего аплета начинается со строки, подключающей оператором import библиотеку классов java.applet.Applet.
Оператор import должен располагаться в файле исходного текста перед другими операторами (за исключением операторов комментария). В качестве параметра оператору import передается имя подключаемого класса из библиотеки классов. Если же необходимо подключить все классы данной библиотеки, вместо имени класса указывается символ "*".
Напомним, что библиотека java.applet.Applet содержит классы, необходимые для создания аплетов, то есть разновидности приложений Java, встраиваемых в документы HTML и работающих под управлением браузера Internet.
Еще одна библиотека классов, которая нам скоро понадобится, это java.awt. С ее помощью аплет может выполнять в своем окне рисование различных изображений или текста. Преимущества данного метода перед использованием для рисования традиционного программного интерфейса операционной системы заключаются в том, что он работает на любой компьютерной платформе.
Далее в исходном тексте аплета определяется класс типа public с именем HelloApplet. Напомним, что это имя должно обязательно совпадать с именем файла, содержащего исходный текст этого класса.
public class HelloApplet extends Applet { . . . } Определенный нами класс HelloApplet с помощью ключевого слова extends наследуется от класса Applet. При этом методам класса HelloApplet становятся доступными все методы и данные класса, за исключением определенных как private. Класс Applet определен в библиотеке классов java.applet.Applet, которую мы подключили оператором import.

enabled browser, you would see

Листинг 2

. Файл HelloApplet.tmp.html

С помощью оператора
наш аплет встраивается в этот документ. Оператор
используется в паре с оператором

и имеет следующие параметры:
Параметр Описание
ALIGN Выравнивание окна аплета относительно окружающего его текста. Возможны следующие значения:LEFT - выравнивание влево относительно окружающего текста;
CENTER - центрирование;
RIGHT - выравнивание вправо относительно окружающего текста;
TOP - выравнивание по верхней границе;
MIDDLE - центрирование по вертикали;
BOTTOM - выравнивание по нижней границе
ALT С помощью этого параметра можно задать текст, который будет отображаться в окне аплета в том случае, если браузер не может работать с аплетами Java
CODE Имя двоичного файла, содержащего байт-код аплета. По умолчанию путь к этому файлу указывается относительно каталога с файлом HTML, в который встроен аплет. Такое поведение может быть изменено параметром CODEBASE
CODEBASE Базовый адрес URL аплета, то есть путь к каталогу, содержащему аплет
HEIGHT Ширина окна аплета в пикселах
WIDTH Высота окна аплета в пикселах
HSPACE Зазор слева и справа от окна аплета
VSPACE Зазор сверху и снизу от окна аплета
NAME Идентификатор аплета, который может быть использован другими аплетами, расположенными в одном и том же документе HTML, а также сценариями JavaScript
TITLE Строка заголовка
Дополнительно между операторами
и

вы можете задать параметры аплета. Для этого используется оператор
, который мы рассмотрим позже.
В нашем случае идентификатор NAME и имя двоичного файла заданы мастером проекта как "HelloApplet":
name="HelloApplet" code="HelloApplet" Параметр CODEBASE задает путь к каталогу локального диска:
codebase="file:/e:/sun/vol3/src/HelloApplet" Когда вы будете размещать документ HTML на сервере, параметр CODEBASE необходимо изменить или удалить, если этот документ и аплет располагаются в одном каталоге. В любом случае, если параметр CODEBASE задан, он должен указывать адрес URL каталога с аплетом.

public class HelloApplet extends Applet

Листинг 3

. Файл HelloApplet.java (новый вариант) import java.applet.Applet; import java.awt.*; public class HelloApplet extends Applet { public String getAppletInfo() { return "HelloJava Applet"; } public void paint(Graphics g) { g.drawString("Hello, Java world!", 20, 20);
} } Теперь исходный текст аплета транслируется без ошибок (Рисунок 7).


Метод destroy

Метод destroy

Перед удалением аплета из памяти вызывается метод destroy, который определен в базовом классе Applet как пустая заглушка. Мастер проектов добавляет в исходный текст класса переопределение метода destroy, которое вы можете при необходимости изменить.
Методу destroy обычно поручают все необходимые операции, которые следует выполнить перед удалением аплета. Например, если в методе init вы создавали какие-либо потоки, в методе destroy их нужно завершить.

Метод getAppletInfo

Метод getAppletInfo

Метод getAppletInfo

Базовый класс Applet содержит определение метода getAppletInfo, возвращающее значение null. В нашем классе HelloApplet, который является дочерним по отношению к классу Applet, мы переопределили метод getAppletInfo из базового класса следующим образом:
public String getAppletInfo() { return "HelloJava Applet"; } Теперь метод getAppletInfo возвращает текстовую информацию об аплете в виде объекта класса String.
Этой информацией могут воспользоваться другие аплеты или сценарии JavaScript, например, для определения возможности взаимодействия с аплетом.

Метод init

Метод init

Метод init определен в базовом классе Applet, от которого наследуются все аплеты. Определение его таково, что этот метод ровным счетом ничего не делает.
Когда вызывается метод init и зачем он нужен?
Метод init вызывается тогда, когда браузер загружает в свое окно документ HTML с оператором , ссылающимся на данный аплет. В этот момент аплет может выполнять инициализацию, или, например, создавать потоки, если он работает в многопоточном режиме.
Существует контрпара для метода init - метод destroy. О нем мы расскажем ниже.

Метод paint

Метод paint

Метод paint

Наиболее интересен для нас метод paint, который выполняет рисование в окне аплета. Вот его исходный текст:
public void paint(Graphics g) { g.drawString("Hello, Java world!", 20, 20); } Если посмотреть определение класса Applet, которое находится в файле JavaWorkshop20\JDK\src\java\applet\Applet.java, то в нем нет метода paint. В каком же классе определен этот метод?

Метод start

Метод start

Метод start вызывается после метода init в момент, когда пользователь начинает просматривать документ HTML с встроенным в него аплетом.
Вы можете модифицировать текст этого метода, если при каждом посещении пользователем страницы с аплетом необходимо выполнять какую-либо инициализацию.

Метод stop

Метод stop

Дополнением к методу start служит метод stop. Он получает управление, когда пользователь покидает страницу с аплетом и загружает в окно браузера другую страницу. Заметим, что метод stop вызывается перед методом destroy.

Методы в классе HelloApplet

Методы в классе HelloApplet

Методы в классе HelloApplet

Создавая файл HelloApplet.java, мастер проектов системы Java WorkShop определила в классе HelloApplet несколько методов, заменив таким образом некоторые методы базового класса Applet.

Новый текст

Новый текст


Первый аплет Java

Первый аплет Java

В предыдущем разделе мы создавали автономное приложение Java, работающее под управлением виртуальной машины Java. Теперь мы создадим приложение другого типа - аплет.
Аплет Java тоже выполняется под управлением виртуальной машины Java, но встроенной в браузер. Когда браузер загружает в свое окно документ HTML с аплетом, байт-код аплета начинает свою работу.
Внешне аплет выглядит как окно заданного размера. Он может рисовать внутри этого окна (и только в нем) произвольные изображения и текст.
Двоичный файл с интерпретируемым байт-кодом Java располагается на сервере Web. В документе HTML с помощью оператора организуется ссылка на этот двоичный файл.
Когда пользователь загружает в браузер документ HTML с аплетом, файл аплета переписывается с сервера Web на рабочую станцию пользователя. После этого браузер начинает его выполнение.
Возможно, вам не понравится такая идея, как запуск чужого аплета на своем компьютере - мало ли чего этот аплет может там сделать. Однако аплеты, в отличие от обычных приложений Java, сильно ограничены в своих правах. Например, они не могут читать локальные файлы и тем более в них писать. Есть также ограничения и на передачу данных через сеть: аплет может обмениваться данными только с тем сервером Web, с которого он был загружен.

Первый аплет

Первый аплет


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

Рисунок 1. Первая диалоговая панель мастера проектов


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



Первая диалоговая панель

Рисунок 1. Первая диалоговая панель мастера проектовДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Сделав это, нажмите кнопку Next. На экране появится вторая диалоговая панель мастера проектов. Здесь вы должны указать путь к каталогу, куда мастер проектов запишет файлы проекта, а также включить переключатель No (Рисунок 2).

Первая диалоговая панель


Вторая диалоговая панель мастера проектов

Рисунок 2. Вторая диалоговая панель мастера проектов


Вторая диалоговая панель мастера проектов



Вторая диалоговая панель

Рисунок 2. Вторая диалоговая панель мастера проектов Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
В результате мастер проектов создаст исходные тексты аплета, а также добавит новый проект в портфель personal (если этот портфель остался активным в последний раз, когда вы запускали Java WorkShop). Новый проект называется HelloApplet (Рисунок 3).

Вторая диалоговая панель

Новый проект появился в активном портфеле personal

Рисунок 3. Новый проект появился в активном портфеле personal

Новый проект появился в активном портфеле personal
Исходный текст аплета будет создан автоматически и загружен в окно редактирования системы Java WorkShop (Рисунок 4).


Исходный текст аплета

Рисунок 4. Исходный текст аплета загружен в окно редактирования Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Вы можете оттранслировать полученный исходный текст и запустить аплет на выполнение. Он будет работать под управлением программы просмотра аплетов appletviewer, которая входит в состав Java WorkShop.

Исходный текст аплета

Пока в окне нашего аплета ничего нет (Рисунок 5), однако скоро мы исправим это положение.

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


Исходный текст аплета



Окно аплета созданного

Рисунок 5. Окно аплета, созданного автоматически мастером проектов


Окно аплета созданного


Измененный исходный текст аплета HelloApplet

Рисунок 6. Измененный исходный текст аплета HelloApplet


Измененный исходный текст аплета HelloApplet



Измененный исходный

Рисунок 6. Измененный исходный текст аплета HelloAppletДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Здесь мы намеренно внесли в исходный текст ошибку, чтобы показать, как Java WorkShop отреагирует на нее. Как видно из рисунка, сообщение об ошибке отображается на странице блокнота с названием Build. Текст сообщения гласит, что компилятор не смог найти определение класса Graphics, на который есть ссылка в девятой строке.

Измененный исходный

Добавим строку импортирования класса java.awt.*, как это показано в листинге 3.

Измененный исходный текст успешно оттранслирован

Рисунок 7. Измененный исходный текст успешно оттранслирован


Измененный исходный текст успешно оттранслирован



Измененный исходный

Рисунок 7. Измененный исходный текст успешно оттранслированДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
Если запустить аплет на выполнение, в его окне будет нарисована строка "Hello, Java world" (Рисунок 8).

Измененный исходный

Теперь наш аплет "умеет"

Рисунок 8. Теперь наш аплет "умеет" рисовать в своем окне текстовые строки


Теперь наш аплет


Система координат используемая методом drawString

Рисунок 9. Система координат, используемая методом drawString

Система координат используемая методом drawString
На этом же рисунке показано, как метод drawString нарисует текстовую строку с координатами (xCoord, yCoord).

Создание проекта аплета

Создание проекта аплета

Создание проекта аплета

Проект аплета создается таким же способом, что и проект автономного приложения Java, однако мастеру проектов необходимо указать другие параметры.
В первой диалоговой панели мастера проектов следует включить переключатели Applet и No GUI (Рисунок 1).


Вызов метода paint

Вызов метода paint

Метод paint вызывается, когда необходимо перерисовать окно аплета. Если вы создавали приложения для операционной системы Windows, то наверняка знакомы с сообщением WM_PAINT, которое поступает в функцию окна приложения при необходимости его перерисовки.
Перерисовка окна приложения Windows и окна аплета обычно выполняется асинхронно по отношению к работе приложения или аплета. В любой момент времени аплет должен быть готов перерисовать содержимое своего окна.
Такая техника отличается о той, к которой вы, возможно, привыкли, создавая обычные программы для MS-DOS. Программы MS-DOS сами определяют, когда им нужно рисовать на экране, причем рисование может выполняться из разных мест программы. Аплеты, так же как и приложения Windows, выполняют рисование в своих окнах централизованно. Аплет делает это в методе paint, а приложение Windows - при обработке сообщения WM_PAINT.
Обратите внимание, что методу paint в качестве параметра передается ссылка на объект Graphics:
public void paint(Graphics g) { . . . } По своему смыслу этот объект напоминает контекст отображения, с которым хорошо знакомы создатели приложений Windows. Контекст отображения - это как бы холст, на котором аплет может рисовать изображение или писать текст. Многочисленные методы класса Graphics позволяют задавать различные параметры холста, такие, например, как цвет или шрифт.
Наше приложение вызывает метод drawString, который рисует текстовую строку в окне аплета:
g.drawString("Hello, Java world!", 20, 20); Вот прототип этого метода:
public abstract void drawString(String str, int x, int y); Через первый параметр методу drawString передается текстовая строка в виде объекта класса String. Второй и третий параметр определяют, соответственно, координаты точки, в которой начнется рисование строки.
В какой координатной системе?
Аплеты используют систему координат, которая соответствует режиму отображения MM_TEXT, знакомому тем, кто создавал приложения Windows. Начало этой системы координат расположено в левом верхнем углу окна аплета, ось X направлена слева направо, а ось Y - сверху вниз (Рисунок 9).

Подробное руководство по программированию на Java

Аплет Draw

Аплет Draw

Аплет Draw

В этом разделе мы приведем исходные тексты аплета Draw, в которых демонстрируется использование различных функций рисования.
На Рисунок 11 показано окно этого аплета.

Битовые маски стиля шрифта

Битовые маски стиля шрифта

  • BOLD
  • public final static int BOLD;
  • ITALIC
  • public final static int ITALIC;
  • PLAIN
  • public final static int PLAIN;



    Документ HTML для аплета Draw

    Документ HTML для аплета Draw

    Документ HTML для аплета Draw не имеет никаких особенностей. Он представлен в листинге 2.
    Листинг 2. Файл draw.tmp.html

    If your browser recognized the applet tag, you would see an applet here.


    Исходные тексты аплета Draw

    Исходные тексты аплета Draw

    Исходные тексты аплета Draw вы найдете в листинге 1.

    Исходные тексты

    Исходные тексты


    Извлечение списка шрифтов

    Извлечение списка шрифтов

    Процедура извлечения списка доступных шрифтов достаточно проста и выполняется следующим образом:
    Toolkit tk; String szFontList[]; . . . tk = Toolkit.getDefaultToolkit(); szFontList = tk.getFontList(); Аплет вызывает статический метод getDefaultToolkit из класса Toolkit и затем, пользуясь полученной ссылкой, извлекает список шрифтов, записывая его в массив szFontList.
    Для чего еще можно использовать класс Toolkit?
    Класс Toolkit является абстрактным суперклассом для всех реализаций AWT. Порожденные от него классы используются для привязки различных компонент конкретных реализаций.
    Создавая свои аплеты, вы будете редко прибегать к услугам этого класса. Однако в нем есть несколько полезных методов, прототипы которых мы перечислим ниже:
  • getDefaultToolkit

  • Получение ссылки на Toolkit
    public static Toolkit getDefaultToolkit();
  • getColorModel
  • Определение текущей цветовой модели, выбранной в контекст отображения
    public abstract ColorModel getColorModel();
  • getFontList
  • Получение списка шрифтов, доступных аплету
    public abstract String[] getFontList();
  • getFontMetrics
  • Получение метрик заданного шрифта
    public abstract FontMetrics getFontMetrics(Font font);
  • getImage
  • Получение растрового изображения по имени файла
    public abstract Image getImage(String filename);
  • getImage
  • Получение растрового изображения по адресу URL
    public abstract Image getImage(URL url);
  • getScreenResolution
  • Определение разрешения экрана в точках на дюйм
    public abstract int getScreenResolution();
  • getScreenSize
  • Размеры экрана в пикселах
    public abstract Dimension getScreenSize();
  • prepareImage
  • Подготовка растрового изображения для вывода
    public abstract boolean prepareImage( Image image, int width, int height, ImageObserver observer);
  • sync
  • Синхронизация состояния Toolkit
    public abstract void sync(); Наиболее интересны, с нашей точки зрения, методы getFontList, getScreenResolution и getScreenSize, с помощью которых аплет может, соответственно, получить список шрифтов, определить разрешение и размер экрана. Последние два параметра позволяют сформировать содержимое окна аплета оптимальным образом исходя из объема информации, который может в нем разместиться.

    Класс Font

    Класс Font

    Приведем краткое перечисление полей, конструкторов и методов этого класса.

    Конструктор

    Конструктор

  • Graphics
  • protected Graphics();



    Конструкторы


    Конструкторы

    public Polygon (); public Polygon(int xpoints[], int ypoints[], int npoints);



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


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

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

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

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

    Метод copyArea позволяет скопировать содержимое любой прямоугольной области окна аплета:
    public abstract void copyArea( int x, int y, int width, int height, int dx, int dy); Параметры x, y, width и height задают координаты копируемой прямоугольной области. Область копируется в другую прямоугольную область такого же размера, причем параметры dx и dy определяют координаты последней.

    Линии

    Линии

    Для того чтобы нарисовать прямую тонкую сплошную линию, вы можете воспользоваться методом drawLine, прототип которого приведен ниже:
    public abstract void drawLine(int x1, int y1,int x2, int y2); Концы линии имеют координаты (x1, y1) и (x2, y2), как это показано наРисунок 1.

    public class draw extends Applet

    Листинг 1

    . Файл draw.java import java.applet.*; import java.awt.*; public class draw extends Applet { Toolkit tk; String szFontList[]; FontMetrics fm; int yStart = 20; int yStep; String parm_TestString; public void init() { tk = Toolkit.getDefaultToolkit();
    szFontList = tk.getFontList();
    parm_TestString = getParameter("TestString");
    } public String getAppletInfo() { return "Name: draw"; } public void paint(Graphics g) { int yDraw; Dimension dimAppWndDimension = getSize();
    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);
    fm = g.getFontMetrics();
    yStep = fm.getHeight();
    for(int i = 0; i < szFontList.length; i++) { g.setFont(new Font("Helvetica", Font.PLAIN, 12));
    g.drawString(szFontList[i], 10, yStart + yStep * i);
    fm = g.getFontMetrics();
    yStep = fm.getHeight();
    g.setFont(new Font(szFontList[i], Font.PLAIN, 12));
    g.drawString(parm_TestString, 100, yStart + yStep * i);
    } yDraw = yStart + yStep * szFontList.length + yStep; Polygon p = new Polygon();
    p.addPoint(70, yDraw);
    p.addPoint(150, yDraw + 30);
    p.addPoint(160, yDraw + 80);
    p.addPoint(190, yDraw + 60);
    p.addPoint(140, yDraw + 30);
    p.addPoint(70, yDraw + 39);
    g.drawPolygon(p);
    g.setColor(Color.red);
    g.drawRect(10, yDraw + 85, 200, 100);
    g.setColor(Color.black);
    g.drawArc(10, yDraw + 85, 200, 100, -50, 320);
    } public String[][] getParameterInfo() { String[][] info = { { "TestString", "String", "Test string" } }; return info; } }

    Метод init

    Метод init

    При инициализации аплета метод init извлекает список доступных шрифтов и принимает значение параметра TestString, передаваемое аплету в документе HTML.

    Метод paint

    Метод paint

    Первым делом метод paint определяет размеры окна аплета, вызывая для этого метод getSize:
    Dimension dimAppWndDimension = getSize(); Метод getSize возвращает ссылку на объект класса Dimension, хранящий высоту и ширину объекта:
  • height

  • Высота
    public int height;
  • width
  • Ширина
    public int width; В классе Dimension предусмотрено три конструктора и один метод:
    public Dimension(); public Dimension(Dimension d); public Dimension(int width, int height);
  • toString
  • Получение строки, представляющей класс
    public String toString(); После определения размеров окна аплета метод paint стирает содержимое всего окна:
    g.clearRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); Далее в контексте отображения устанавливается желтый цвет:
    g.setColor(Color.yellow); Этим цветом заполняется внутренняя область окна аплета, для чего применяется метод fillRect:
    g.fillRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); Затем метод paint устанавливает в контексте отображения черный цвет и рисует тонкую черную рамку вокруг окна аплета:
    g.setColor(Color.black); g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); На следующем этапе мы получаем метрики текущего шрифта, выбранного в контекст отображения:
    fm = g.getFontMetrics(); Пользуясь этими метриками, мы определяем высоту символов текущего шрифта и записываем ее в поле yStep:
    yStep = fm.getHeight(); После этого метод paint запускает цикл по всем шрифтам, установленным в системе:
    for(int i = 0; i < szFontList.length; i++) { . . . } Количество доступных шрифтов равно размеру массива szFontList, которое вычисляется как szFontList.length.
    Метод paint выписывает в окне аплета название каждого шрифта, устанавливая для этого шрифт Helvetica размером 12 пикселов:
    g.setFont(new Font("Helvetica", Font.PLAIN, 12)); g.drawString(szFontList[i], 10, yStart + yStep * i); Смещение каждой новой строки с названием шрифта вычисляется исходя из высоты символов установленного шрифта:
    fm = g.getFontMetrics(); yStep = fm.getHeight(); После названия шрифта метод paint рисует в окне аплета текстовую строку parm_TestString, полученную через параметр с именем "TestString":
    g.setFont(new Font(szFontList[i], Font.PLAIN, 12)); g.drawString(parm_TestString, 100, yStart + yStep * i); Перед тем как перейти к рисованию геометрических фигур, метод paint запоминает в поле yDraw координату последней строки названия шрифта, сделав отступ высотой yStep :
    int yDraw; yDraw = yStart + yStep * szFontList.length + yStep; Первая фигура, которую рисует наш аплет, это многоугольник.
    Мы создаем многоугольник как объект класса Polygon:
    Polygon p = new Polygon(); В этот объект при помощи метода addPoint добавляется несколько точек:
    p.addPoint(70, yDraw); p.addPoint(150, yDraw + 30); p.addPoint(160, yDraw + 80); p.addPoint(190, yDraw + 60); p.addPoint(140, yDraw + 30); p.addPoint(70, yDraw + 39); После добавления всех точек метод paint рисует многоугольник, вызывая для этого метод drawPolygon:
    g.drawPolygon(p); Затем мы устанавливаем в контексте отображения красный цвет и рисуем прямоугольник:
    g.setColor(Color.red); g.drawRect(10, yDraw + 85, 200, 100); Затем метод paint вписывает в этот прямоугольник сегмент окружности:
    g.setColor(Color.black); g.drawArc(10, yDraw + 85, 200, 100, -50, 320);

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

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

    В качестве базового для класса Graphics (полное название класса java.awt.Graphics) выступает класс java.lang.Object.
    Прежде всего мы приведем прототипы конструктора этого класса и его методов с краткими комментариями. Полное описание вы сможете найти в электронной документации, которая входит в комплект Java WorkShop.
    Далее мы рассмотрим назначение основных методов, сгруппировав их по выполняемым функциям.

    Методы

    Методы

  • clearRect
  • Стирание содержимого прямоугольной области
    public abstract void clearRect(int x, int y, int width, int height);
  • clipRect
  • Задание области ограничения вывода
    public abstract void clipRect(int x, int y, int width, int height);
  • copyArea
  • Копирование содержимого прямоугольной области
    public abstract void copyArea(int x, int y, int width, int height, int dx, int dy);
  • create
  • Создание контекста отображения
    public abstract Graphics create(); public Graphics create(int x, int y, int width, int height);
  • dispose
  • Удаление контекста отображения
    public abstract void dispose();
  • draw3DRect
  • Рисование прямоугольной области с трехмерным выделением
    public void draw3DRect(int x, int y, int width, int height, boolean raised);
  • drawArc
  • Рисование сегмента
    public abstract void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle); Рисование сегмента
  • drawBytes

  • Рисование текста из массива байт
    public void drawBytes(byte data[], int offset, int length, int x, int y);
  • drawChars
  • Рисование текста из массива символов
    public void drawChars(char data[], int offset, int length, int x, int y);
  • drawImage
  • Рисование растрового изображения
    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);
  • drawLine
  • Рисование линии
    public abstract void drawLine(int x1, int y1, int x2, int y2);
  • drawOval
  • Рисование овала
    public abstract void drawOval(int x, int y, int width, int height);
  • drawPolygon
  • Рисование многоугольника
    public abstract void drawPolygon( int xPoints[], int yPoints[], int nPoints); public void drawPolygon(Polygon p);
  • drawRect
  • Рисование прямоугольника
    public void drawRect(int x, int y, int width, int height);
  • drawRoundRect
  • Рисование прямоугольника с круглыми углами
    public abstract void drawRoundRect( int x, int y, int width, int height, int arcWidth, int arcHeight);
  • drawString
  • Рисование текстовой строки
    public abstract void drawString(String str, int x, int y);
  • fill3DRect
  • Рисование заполненного прямоугольника с трехмерным выделением
    public void fill3DRect(int x, int y, int width, int height, boolean raised);
  • fillArc
  • Рисование заполненного сегмента круга
    public abstract void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle);
  • fillOval
  • Рисование заполненного овала
    public abstract void fillOval(int x, int y, int width, int height);
  • fillPolygon
  • Рисование заполненного многоугольника
    public abstract void fillPolygon( int xPoints[], int yPoints[], int nPoints);
  • fillPolygon
  • Рисование заполненного многоугольника
    public void fillPolygon(Polygon p); public abstract void fillRect(int x, int y, int width, int height);
  • fillRoundRect
  • Рисование заполненного прямоугольника с круглыми углами
    public abstract void fillRoundRect( int x, int y, int width, int height, int arcWidth, int arcHeight);
  • finalize
  • Прослеживание вызова метода dispose
    public void finalize();
  • getClipRect
  • Определение границ области ограничения вывода
    public abstract Rectangle getClipRect();
  • getColor
  • Определение цвета, выбранного в контекст отображения
    public abstract Color getColor();
  • getFont
  • Определение шрифта, выбранного в контекст отображения
    public abstract Font getFont();
  • getFontMetrics
  • Определение метрик текущего шрифта
    public FontMetrics getFontMetrics();
  • getFontMetrics
  • Определение метрик заданного шрифта
    public abstract FontMetrics getFontMetrics(Font f);
  • setColor
  • Установка цвета для рисования в контексте отображения
    public abstract void setColor(Color c);
  • setFont
  • Установка текущего шрифта в контексте отображения
    public abstract void setFont(Font font);
  • setPaintMode
  • Установка режима рисования
    Метод setPaintMode устанавливает в контексте отображения режим рисования, при котором выполняется замещение изображения текущим цветом, установленном в контексте отображения.
    public abstract void setPaintMode();
  • setXORMode
  • Установка маски для рисования
    Задавая маску для рисования при помощи метода setXORMode, вы можете выполнить при рисовании замещение текущего цвета на цвет, указанный в параметре метода, и наоборот, цвета, указанного в параметре метода, на текущий.
    Все остальные цвета изменяются непредсказуемым образом, однако эта операция обратима, если вы нарисуете ту же самую фигуру два раза на одном и том же месте.
    public abstract void setXORMode(Color c1);
  • translate
  • Сдвиг начала системы координат
    Метод translate сдвигает начало системы координат в контексте отображения таким образом, что оно перемещается в точку с координатами (x, y), заданными через параметры метода:
    public abstract void translate(int x, int y);
  • toString
  • Получение текстовой строки, представляющей данный контекст отображения
    public String toString();

    Методы

    Методы

  • equals
  • Сравнение шрифтов
    public boolean equals(Object obj);
  • getFamily
  • Определение названия семейства шрифтов
    public String getFamily();
  • getFont
  • Получение шрифта по его характеристикам
    public static Font getFont(String nm); public static Font getFont(String nm, Font font);
  • getName
  • Определение названия шрифта
    public String getName();
  • getSize
  • Определение размера шрифта
    public int getSize();
  • getStyle
  • Определение стиля шрифта
    public int getStyle();
  • hashCode
  • Получение хэш-кода шрифта
    public int hashCode();
  • isBold
  • Определение жирности шрифта
    public boolean isBold();
  • isItalic
  • Проверка, является ли шрифт наклонным
    public boolean isItalic();
  • isPlain
  • Проверка, есть ли шрифтовое выделение
    public boolean isPlain();
  • toString
  • Получение текстовой строки для объекта
    public String toString(); Создавая шрифт конструктором Font, вы должны указать имя, стиль и размер шрифта.
    В качестве имени можно указать, например, такие строки как Helvetica или Courier. Учтите, что в системе удаленного пользователя, загрузившего ваш аплет, может не найтись шрифта с указанным вами именем. В этом случае браузер заменит его на наиболее подходящий (с его точки зрения).
    Стиль шрифта задается масками BOLD, ITALIC и PLAIN, которые можно комбинировать при помощи логической операции "ИЛИ":
    Маска Описание
    BOLD Утолщенный шрифт
    ITALIC Наклонный шрифт
    PLAIN Шрифтовое выделение не используется
    Что же касается размера шрифта, то он указывается в пикселах.

    Методы

    Методы

  • addPoint
  • Добавление вершины
    public void addPoint(int x, int y);
  • getBoundingBox
  • Получение координат охватывающего прямоугольника
    public Rectangle getBoundingBox();
  • inside
  • Проверка, находится ли точка внутри многоугольника
    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); Если вам нужно нарисовать заполненный многоугольник (Рисунок 7), то для этого вы можете воспользоваться методами, приведенными ниже:
    public abstract void fillPolygon( int xPoints[], int yPoints[], int nPoints); public void fillPolygon(Polygon p); Первый из этих методов рисует многоугольник, координаты вершин которого заданы в массивах, второй - получая объект класса Polygon в качестве параметра.

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

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

    Для рисования многоугольников в классе Graphics предусмотрено четыре метода, два из которых рисуют незаполненные многоугольники, а два - заполненные.
    Первый метод рисует незаполненный многоугольник, заданный массивами координат по осям X и Y:
    public abstract void drawPolygon( int xPoints[], int yPoints[], int nPoints); Через параметры xPoints и yPoints передаются, соответственно, ссылки на массивы координат по оис X и Y. Параметр nPoints задает количество точек в массивах.
    На Рисунок 6 показан многоугольник, нарисованный методом drawPolygon.

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

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

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

    Определение атрибутов

    Определение атрибутов


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

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

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

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

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

    С помощью метода clipRect, о котором мы расскажем чуть позже, вы можете определить в окне аплета область ограничения вывода прямоугольной формы. Вне этой области рисование графических изображений и текста не выполняется.
    Метод getClipRect позволяет вам определить координаты текущей области ограничения, заданной в контексте отображения:
    public abstract Rectangle getClipRect(); Метод возвращает ссылку на объект класса Rectangle, который, в частности, имеет поля класса с именами x, y, height и width. В этих полях находится, соответственно, координаты верхнего левого угла, высота и ширина прямоугольной области.

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

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

    Несмотря на то что вы можете заказать шрифт с заданным именем и размером, не следует надеяться, что навигатор выделит вам именно такой шрифт, какой вы попросите. Для правильного размещения текста и других изображений в окне аплета вам необходимо знать метрики реального шрифта, выбранного навигатором в контекст отображения.
    Метрики текущего шрифта в контексте отображения вы можете узнать при помощи метода 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 без параметров возвращает метрики текущего шрифта, выбранного в контекст отображения.

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

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

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

    Овалы и круги

    Овалы и круги

    Для рисования окружностей и овалов вы можете воспользоваться методом drawOval:
    public abstract void drawOval( int x, int y, int width, int height); Параметры этого методы задают координаты и размеры прямоугольника, в который вписывается рисуемый овал (Рисунок 8).

    Поля класса

    Поля класса

  • name
  • protected String name;
  • size
  • protected int size;
  • style
  • protected int style;

    Поля класса

  • npoints
  • Количество вершин
    public int npoints;
  • xpoints
  • Массив координат по оси X
    public int xpoints[];
  • ypoints
  • Массив координат по оси Y
    public int ypoints[]

    Получение значения параметров

    Получение значения параметров

    До сих пор наши аплеты не получали параметров из документов HTML, в которые мы их встраивали.
    Конечно, все константы, текстовые строки, адреса URL и другую информацию можно закодировать непосредственно в исходном тексте аплета, однако, очевидно, это очень неудобно.
    Пользуясь операторами , расположенными в документе HTML сразу после оператора , можно передать аплету произвольное количество параметров, например, в виде текстовых строк:
    . . . Здесь через параметр NAME оператора передается имя параметра аплета, а через параметр VALUE - значение соответствующего параметра.
    Как параметр может получить значение параметров?
    Для получения значения любого параметра аплет должен использовать метод getParameter. В качестве единственного параметра этому методу передается имя параметра аплета в виде строки типа String, например:
    parm_TestString = getParameter("TestString"); Обычно в аплете также определяется метод getParameterInfo, возвращающий информацию о параметрах. Вот исходный текст этого метода для нашего аплета Draw:
    public String[][] getParameterInfo() { String[][] info = { { "TestString", "String", "Test string" } }; return info; } Метод getParameterInfo возвращает массив массивов текстовых строк. Первая строка указывает имя параметра, вторая - тип передаваемых через него данных, а третья - значение параметра по умолчанию.

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

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

    Среди методов класса Graphics есть несколько, предназначенных для рисования прямоугольников. Первый из них, с именем drawRect, позволяет нарисовать прямоугольник, заданный координатами своего левого верхнего угла, шириной и высотой:
    public void drawRect(int x, int y, int width, int height); Параметры x и y задают, соответственно, координаты верхнего левого угла, а параметры width и height - высоту и ширину прямоугольника (Рисунок 2).

    Проект аплета

    Проект аплета


    Проект для аплета Draw

    Проект для аплета Draw

    Подготовьте файлы проекта аплета Draw, скопировав их из предыдущего раздела в какой-нибудь каталог. Затем запустите мастер проектов и в соответствующей диалоговой панели укажите путь к этому каталогу (Рисунок 12).


    Рисование фигур

    Рисование фигур


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

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

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

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


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

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

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

    Рисунок 1. Рисование прямой линии

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

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

    Рисунок 10. Рисование незаполненного сегмента

    Рисование незаполненного сегмента
    Параметры x, y, width и height задают координаты прямоугольника, в который вписан сегмент.
    Параметры startAngle и arcAngle задаются в градусах. Они определяют, соответственно, начальный угол и угол разворота сегмента.
    Для того чтобы нарисовать заполненный сегмент, вы можете воспользоваться методом fillArc:
    public abstract void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle);

    Окно аплета Draw

    Рисунок 11. Окно аплета Draw

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

    Указание пути к каталогу с исходными файлами

    Рисунок 12. Указание пути к каталогу с исходными файлами


    Указание пути к каталогу с исходными файлами



    Указание пути к каталогу

    Рисунок 12. Указание пути к каталогу с исходными файламиДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
    Так как в каталоге уже есть файлы, вы должны включить переключатель Yes и затем нажать кнопку Next.

    Указание пути к каталогу

    После этого вы увидите на экране диалоговую панель, показанную на Рисунок 13.


    Добавление к проекту существующих файлов

    Рисунок 13. Добавление к проекту существующих файлов


    Добавление к проекту существующих файлов



    Добавление к проекту

    Рисунок 13. Добавление к проекту существующих файловДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
    Здесь вам нужно нажать кнопку Add All in Directory. Как только вы это сделаете, в списке файлов Project Files появится имя файла draw.java, подготовленного вами заранее.

    Добавление к проекту

    На следующем шаге вам опять нужно нажать кнопку Next и проследить, чтобы имя главного класса аплета, отображаемое в диалоговой панели, показанной на Рисунок 14, было draw.


    Задание имени главного класса

    Рисунок 14. Задание имени главного класса


    Задание имени главного класса



    Задание имени главного

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

    Задание имени главного

    Hаш аплет принимает из документа HTML один параметр с именем TestString. Для добавления параметров вам нужно открыть окно менеджера проектов, выбрав из меню Project строку Show Project Manager. В этом окне проект draw должен быть текущим.
    Выделите его курсором мыши в окне Java WorkShop Project Manager и из меню Project этого окна выберите строку Edit. Вы увидите блокнот Project Edit, с помощью которого можно изменять различные параметры проекта. Откройте в этом блокноте страницу Run (Рисунок 15).


    Добавление параметра TestString

    Рисунок 15. Добавление параметра TestString


    Добавление параметра TestString



    Добавление параметра

    Рисунок 15. Добавление параметра TestStringДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
    В полях Name и Value введите, соответственно, имя параметра и значение параметра по умолчанию, а затем нажмите кнопку Add. Добавленный вами параметр появится в списке Parameters. Теперь вам осталось только нажать кнопку OK.

    Добавление параметра


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

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

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

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

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

    Рисование заполненного прямоугольника
    Прототип метода fillRect приведен ниже:
    public abstract void fillRect(int x, int y, int width, int height); Метод drawRoundRect позволяет нарисовать прямоугольник с закругленными углами:
    public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); Параметры x и y определяют координаты верхнего левого угла прямоугольника, параметры width и height задают, соответственно его ширину и высоту.
    Размеры эллипса, образующего закругления по углам, вы можете задать с помощью параметров arcWidth и arcHeight. Первый из них задает ширину эллипса, а второй - высоту (Рисунок 4).

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

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

    Рисование прямоугольника с закругленными углами
    Метод fillRoundRect позволяет нарисовать заполненный прямоугольник с закругленными углами (Рисунок 5).

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

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

    Рисование заполненного
    Назначение параметров этого метода аналогично назначению параметров только что рассмотренного метода drawRoundRect:
    public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); Метод fill3Drect предназначен для рисования выступающего или западающего прямоугольника:
    public void fill3DRect(int x, int y, int width, int height, boolean raised); Если значение параметра raised равно true, рисуется выступающий прямоугольник, если false - западающий. Назначение остальных параметров аналогично назначению параметров метода drawRect.

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

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

    Многоугольник нарисованный методом drawPolygon
    В этом многоугольнике шесть вершин с координатами от (x0,y0) до (x5, y5), причем для того чтобы он стал замкнутым, координаты первой и последней вершины совпадают.
    Второй метод также рисует незаполненный многоугольник, однако в качестве параметра методу передается ссылка на объект Polygon:
    public void drawPolygon(Polygon p); Класс Polygon достаточно прост. Приведем описание его полей, конструкторов и методов:

    Многоугольник нарисованный методом fillPolygon

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


    Многоугольник нарисованный методом fillPolygon



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

    Рисунок 8. Рисование овала

    Рисование овала
    Метод fillOval предназначен для рисования заполненного овала (Рисунок 9). Назначение его параметров аналогично назначению параметров метода drawOval:
    public abstract void fillOval( int x, int y, int width, int height);

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

    Рисунок 9. Рисование заполненного овала


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



    Сегменты

    Сегменты

    Метод drawArc предназначен для рисования незаполненного сегмента (Рисунок 10). Прототип этого метода приведен ниже:
    public abstract void drawArc( int x, int y, int width, int height, int startAngle, int arcAngle);

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

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

    Изменяя атрибуты контекста отображения, приложение 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("Hello, Java world!", 10, 20); . . . } Здесь мы привели фрагмент исходного текста метода paint, в котором в контексте отображения устанавливается желтый цвет. После этого метод drawString выведет текстовую строку " Hello, Java world!" желтым цветом.
    Если необходима более точная установка цвета, вы можете воспользоваться одним из трех конструкторов объекта 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.

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

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

    Если для окна аплета задать область ограничения, то рисование будет возможно только в пределах этой области. Область ограничения задается методом clipRect, прототип которого мы привели ниже:
    public abstract void clipRect( int x, int y, int width, int height); Параметры x, y, width и height задают координаты прямоугольной области ограничения.

    Подробное руководство по программированию на Java

    Аплет LineDraw


    Аплет LineDraw

    В аплете LineDraw мы показали основные приемы обработки событий, вызываемых мышью. Вы можете рисовать в окне аплета прямые линии, причем возле концов линий отображаются их координаты (Рисунок 1).

    Исходный текст аплета LineDraw

    Исходный текст аплета LineDraw

    Исходный текст аплета LieDrnaw вы найдете в листинге 1.

    Исходный текст

    Исходный текст


    Как обрабатываются события

    Как обрабатываются события

    Когда возникает событие, управление получает метод handleEvent из класса Component. Класс Applet является дочерним по отношению к классу Component.
    Прототип метода handleEvent мы привели ниже:
    public boolean handleEvent(Event evt); В качестве параметра методу handleEvent передается объект класса Event, который содержит всю информацию о событии. По содержимому полей класса Event вы можете определить координаты курсора мыши в момент, когда пользователь нажал клавишу, отличить одинарный щелчок от двойного и так далее.
    Ниже мы привели список полей класса Event, которые вы можете проанализировать:
    Поле Описание
    public Object argarg; Произвольный аргумент события, значение которого зависит от типа события
    public int clickCountclickCount; Это поле имеет значение только для события с типом MOUSE_DOWNMOUSE_DOWN и содержит количество нажатий на клавишу мыши. Если пользователь сделал двойной щелчок мышью, в это поле будет записано значение 2
    public Event evtevt; Следующее событие в связанном списке
    public int idid; Тип события. Ниже мы перечислим возможные значения для этого поля
    public int keykey; Код нажатой клавиши (только для события, созданного при выполнении пользователем операции с клавиатурой)
    public int modifiersmodifiers; Состояние клавиш модификации , ,
    public Object targettarget; Компонент, в котором произошло событие
    public long whenwhen; Время, когда произошло событие
    public int xx; Координата по оси X
    public int yy; Координата по оси Y
    Поле id (тип события) может содержать следующие значения:
    Значение Тип события
    ACTION_EVENTACTION_EVENT Пользователь хочет, чтобы произошло некоторое событие
    GOT_FOCUSGOT_FOCUS Компонент (в нашем случае окно аплета) получил фокус ввода. О фокусе ввода вы узнаете из раздела, посвященного работе с клавиатурой
    KEY_ACTIONKEY_ACTION Пользователь нажал клавишу типа "Action"
    KEY_ACTION_RELEASEKEY_ACTION_RELEASE Пользователь отпустил клавишу типа "Action"
    KEY_PRESSKEY_PRESS Пользователь нажал обычную клавишу
    KEY_RELEASEKEY_RELEASE Пользователь отпустил обычную клавишу
    LIST_DESELECTLIST_DESELECT Отмена выделения элемента в списке
    LIST_SELECTLIST_SELECT Выделение элемента в списке
    LOAD_FILELOAD_FILE Загрузка файла
    LOST_FOCUSLOST_FOCUS Компонент потерял фокус ввода
    MOUSE_DOWNMOUSE_DOWN Пользователь нажал клавишу мыши
    MOUSE_DRAGMOUSE_DRAG Пользователь нажал клавишу мыши и начал выполнять перемещение курсора мыши
    MOUSE_ENTERMOUSE_ENTER Курсор мыши вошел в область окна аплета
    MOUSE_EXITMOUSE_EXIT Курсор мыши покинул область окна аплета
    MOUSE_MOVEMOUSE_MOVE Пользователь начал выполнять перемещение курсора мыши, не нажимая клавишу мыши
    MOUSE_UPMOUSE_UP Пользователь отпустил клавишу мыши
    SAVE_FILESAVE_FILE Сохранение файла
    SCROLL_ABSOLUTESCROLL_ABSOLUTE Пользователь переместил движок полосы просмотра в новую позицию
    SCROLL_LINE_DOWNSCROLL_LINE_DOWN Пользователь выполнил над полосой просмотра операцию сдвига на одну строку вниз
    SCROLL_LINE_UPSCROLL_LINE_UP Пользователь выполнил над полосой просмотра операцию сдвига на одну строку вверх
    SCROLL_PAGE_DOWNSCROLL_PAGE_DOWN Пользователь выполнил над полосой просмотра операцию сдвига на одну страницу вниз
    SCROLL_PAGE_UPSCROLL_PAGE_UP Пользователь выполнил над полосой просмотра операцию сдвига на одну страницувверх
    WINDOW_DEICONIFYWINDOW_DEICONIFY Пользователь запросил операцию восстановления нормального размера окна после его минимизации
    WINDOW_DESTROYWINDOW_DESTROY Пользователь собирается удалить окно
    WINDOW_EXPOSEWINDOW_EXPOSE Окно будет отображено
    WINDOW_ICONIFYWINDOW_ICONIFY Окно будет минимизировано
    WINDOW_MOVEDWINDOW_MOVED Окно будет перемещено
    Если событие связано с клавиатурой (тип события KEY_ACTION или KEY_ACTION_RELEASE), в поле key может находиться одно из следующих значений:
    Значение Клавиша
    DOWNDOWN Клавиша перемещения курсора вниз
    ENDEND
    F1F1-F12
    F2
    F3
    F4
    F5
    F6
    F7
    F8
    F9
    F10
    F11
    F12
    HOMEHOME
    LEFTLEFT Клавиша перемещения курсора влево
    PGDNPGDN
    PGUPPGUP
    RIGHTRIGHT Клавиша перемещения курсора вправо
    UPUP Клавиша перемещения курсора вниз
    Могут быть указаны следующие маски для поля модификаторов modifiers:
    Значение маски Описание
    ALT_MASKALT_MASK Была нажата клавиша
    META_MASKMETA_MASK Была нажата мета-клавиша (клавиша для ввода диактрических символов)
    CTRL_MASKCTRL_MASK Была нажата клавиша
    SHIFT_MASKSHIFT_MASK Была нажата клавиша
    Ваше приложение может переопределить метод handleEvent и обрабатывать события самостоятельно, однако есть более простой путь. Обработчик этого метода, который используется по умолчанию, вызывает несколько методов, которые более удобны в использовании, в частности, при обработке событий от мыши или клавиатуры.

    public class LineDraw extends Applet

    Листинг 1

    . Файл LieDrnaw.java import java.applet.*; import java.awt.*; import java.util.*; public class LineDraw extends Applet { Dimension dmDown; Dimension dmUp; Dimension dmPrev; boolean bDrawing; Vector lines; public String getAppletInfo() { return "Name: LineDraw"; } public void init() { bDrawing = false; lines = new Vector();
    } public void paint(Graphics g) { Dimension dimAppWndDimension = getSize();
    setBackground(Color.yellow);
    g.setColor(Color.black);
    g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1);
    for (int i=0; i < lines.size();
    i++) { Rectangle p = (Rectangle)lines.elementAt(i);
    g.drawLine(p.width, p.height, p.x, p.y);
    g.drawString("<" + p.width + "," + p.height + ">
    ", p.width, p.height);
    g.drawString("<" + p.x + "," + p.y+ ">
    ", p.x, p.y);
    } bDrawing = false; } public boolean mouseDown(Event evt, int x, int y) { if(evt.clickCount >
    1) { lines.removeAllElements();
    repaint();
    return true; } dmDown = new Dimension(x, y);
    dmPrev = new Dimension(x, y);
    bDrawing = false; return true; } public boolean mouseUp(Event evt, int x, int y) { if(bDrawing) { dmUp = new Dimension(x, y);
    lines.addElement( new Rectangle(dmDown.width, dmDown.height, x, y));
    repaint();
    bDrawing = false; } return true; } public boolean mouseDrag(Event evt, int x, int y) { Graphics g = getGraphics();
    bDrawing = true; g.setColor(Color.yellow);
    g.drawLine(dmDown.width, dmDown.height, dmPrev.width, dmPrev.height);
    g.setColor(Color.black);
    g.drawLine(dmDown.width, dmDown.height, x, y);
    dmPrev = new Dimension(x, y);
    return true; } public boolean mouseMove(Event evt, int x, int y) { bDrawing = false; return true; } } Исходный текст документа HTML, подготовленного системой JavaWorkshop, представлен в листинге 2.

    enabled browser, you would see

    Листинг 2

    . Файл LineDraw.tmp.html


    Метод getAppletInfo

    Метод getAppletInfo

    Метод getAppletInfo возвращает название аплета и не имеет никаких особенностей.

    Метод init

    Метод init

    Метод init сбрасывает признак рисования, записывая в поле bDrawing значение false, а также создает новый динамический массив в виде объекта класса Vector:
    public void init() { bDrawing = false; lines = new Vector(); }

    Метод mouseDown

    Метод mouseDown

    В начале своей работы метод mouseDown определяет, был ли сделан одинарный щелчок клавишей мыши, или двойной. Если был сделан двойной щелчок мышью, метод удаляет все элементы из массива list, а затем перерисовывает окно аплета, вызывая метод repaint:
    lines.removeAllElements(); repaint(); После перерисовки окно аплета очищается от линий.
    Если же был сделан одинарный щелчок клавишей мыши, метод mouseDown сохраняет текущие координаты курсора в переменных dmDown и dmPrev, а затем сбрасывает признак рисования:
    dmDown = new Dimension(x, y); dmPrev = new Dimension(x, y); bDrawing = false;

    Метод mouseDrag

    Метод mouseDrag

    До сих пор наши аплеты выполняли рисование только в методе paint, и так поступают большинство аплетов. Однако наш аплет должен рисовать линии во время перемещения курсора мыши, так как в противном случае пользователю не будет видно, как пройдет рисуемая линия.
    Для того чтобы нарисовать что-либо в окне аплета, наобходимо получить контекст отображения. Методу paint этот контекст передается через парметр как объект класса Graphics. Если же вы собираетесь рисовать в другом методе, отличном от paint, необходимо получить контекст отображения, например, так:
    Graphics g = getGraphics(); После получения контекста отображения и включения режима рисования (записью в переменную bDrawing значения true) метод mouseDrag стирает линию, которая была нарисована ранее, в процессе предыдущего вызова этого же метода:
    g.setColor(Color.yellow); g.drawLine(dmDown.width, dmDown.height, dmPrev.width, dmPrev.height); Для стирания линии мы рисуем ее на том же месте с использованием цвета, совпадающего с цветом фона.
    Далее метод mouseDrag рисует новую линию черного цвета, соединяя точку, в которой была нажата клавиша мыши, с точкой текущего расположения курсора мыши:
    g.setColor(Color.black); g.drawLine(dmDown.width, dmDown.height, x, y); После рисования линии координаты ее конца сохраняются в поле dmPrev для стирания этой линии при следующем вызове метода mouseDrag:
    dmPrev = new Dimension(x, y); return true;

    Метод mouseMove

    Метод mouseMove

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

    Метод mouseUp

    Метод mouseUp

    Когда пользователь отпускает клавишу мыши, вызывается метод mouseUp. В его задачу входит сохранение текущих координат курсора мыши в поле dmUp, а также добавление нового элемента в массив lines:
    dmUp = new Dimension(x, y); lines.addElement( new Rectangle(dmDown.width, dmDown.height, x, y)); repaint(); После добавления элемента в массив метод mouseUp инициирует перерисовку окна аплета, вызывая для этого метод repaint.
    Заметим, что в качестве координат начала линии мы записываем в элемент массива координаты точки, где в последний раз пользователь нажимал курсор мыши. В качестве координат конца линии используются текущие координаты курсора на момент отпускания клавиши мыши.

    Метод paint

    Метод paint

    После изменения цвета фона и рисования рамки метод 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); g.drawString("<" + p.width + "," + p.height + ">", p.width, p.height); g.drawString("<" + p.x + "," + p.y+ ">", p.x, p.y); } Для объектов класса Vector метод size возвращает количество элементов в массиве, чем мы воспользовались для проверки условия выхода из цикла.
    Чтобы извлечь элемент массива по его номеру, мы применили метод elementAt, передав ему через единственный параметр номер извлекаемого элемента.
    Так как в массиве хранятся объекты класса Rectangle, перед инициализацией ссылки p мы выполняем явное преобразование типов.
    Координаты концов линий рисуются с помощью уже знакомого вам метода drawString.
    Перед завершением работы метод paint сбрасывает признак рисования, записывая в поле bDrawing значение false:
    bDrawing = false;

    Нажатие клавиши мыши

    Нажатие клавиши мыши

    Переопределив метод mouseDown, вы сможете отслеживать нажатия клавиши мыши. Прототип этого метода приведен ниже:
    public boolean mouseDown(Event evt, int x, int y); Через параметр evt методу передается ссылка на объект Event, с помощью которой метод может получить полную информацию о событии.
    Анализируя содержимое параметров x и y, приложение может определить координаты курсора на момент возникновения события.
    Заметим, что для отслеживания двойного щелчка мыши не предусмотрено никакого отдельного метода. Однако анализируя содержимое поля clickCount переменной evt, вы можете определить кратность щелчка мыши:
    if(evt.clickCount > 1) // Двойной щелчок showStatus("Mouse Double Click"); else // Одинарный щелчок showStatus("Mouse Down");

    Обработка событий

    Обработка событий


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

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

    В нашем аплете мы будем создавать объект класса Vector, который является массивом с динамически изменяемым размером. Здесь мы будем хранить координаты нарисованных линий.
    Класс Vector имеет полное имя java.util.Vector, поэтому мы подключаем соответствующую библиотеку классов:
    import java.util.*;

    Описание текста

    Описание текста


    Отпускание клавиши мыши

    Отпускание клавиши мыши

    При отпускании клавиши мыши управление получает метод mouseUp:
    public boolean mouseUp(Event evt, int x, int y); Анализируя параметры x и y, вы можете определить координаты точки, в которой пользователь отпустил клавишу мыши.

    Перемещение курсора мыши

    Перемещение курсора мыши

    Когда пользователь перемещает курсор мыши над окном аплета, в процессе перемещения происходит вызов метода mouseMove:
    public boolean mouseMove(Event evt, int x, int y); Через переменные x и y передаются текущие координаты курсора мыши.

    Поля класса LineDraw

    Поля класса LineDraw

    В нашем классе мы определили несколько полей, предназначенных для хранения текущих координат рисуемых линий:
    Dimension dmDown; Dimension dmUp; Dimension dmPrev; boolean bDrawing; Vector lines; В переменную dmDown класса Dimension записываются координаты курсора на момент нажатия клавиши мыши. Если пользователь нажал клавишу мыши для того чтобы приступить к рисованию линии, это будет координатами начала линии.
    Когда пользователь отпускает клавишу мыши, координаты записываются в переменную dmUp.
    В процессе рисования линии метод mouseDrag стирает ранее нарисованную линию и рисует новую. Координаты конца старой линии хранятся в переменной dmPrev.
    Переменная bDrawing типа boolean хранит текущее состояние аплета. Когда аплет находится в состоянии рисования линии, в эту переменную записывается значение true, а когда нет - значение false.
    И, наконец, переменная lines типа Vector является динамическим массивом, в котором хранятся координаты нарисованных линий.

    Окно аплета LineDraw с нарисованными в нем линиями

    Рисунок 1. Окно аплета LineDraw с нарисованными в нем линиями

    Окно аплета LineDraw с нарисованными в нем линиями
    Для того чтобы нарисовать линию в окне аплета LineDraw, вы должны установить курсор в начальную точку, нажать клавишу мыши и затем, не отпуская ее, переместить курсор в конечную точку. После отпускания клавиши мыши координаты линии будут сохранены аплетом в массиве, после чего произойдет перерисовка окна аплета.
    По мере того как вы будете рисовать линии, аплет будет заполнять массив с координатами линий. Каждый раз, когда окно аплета будет перерисовываться, метод paint перерисует все линии заново, пользуясь координатами, сохраненными в массиве.
    Для того чтобы стереть содержимое окна аплета, вам достаточно сделать двойной щелчок в его окне. При этом из массива координать линий будут удалены все элементы.

    События от мыши


    События от мыши

    В этом разделе мы рассмотрим события, которые возникают в результате того, что пользователь выполняет в окне аплета операции с мышью. Это такие операции, как нажатие и отпускание клавиши мыши, перемещение курсора мыши в окне аплета с нажатой или отпущенной клавишей, перемещение курсора мыши в окно аплета и удаление этого курсора из окна аплета.
    Все перечисленные ниже методы должны вернуть значение true, если обработка события выполнена успешно и дальнейшая обработка не требуется. Если же методы вернут значение false, событие будет обработано методом из базового класса, то есть для него будет выполнена обработка, принятая по умолчанию.
    Программисты, создававшие приложения для операционной системы Microsoft Windows, могут найти здесь аналогию с вызовом функции DefWindowProc, которая выполняет обработку сообщений, принятую по умолчанию.

    События


    События

    От аплетов Java было бы немного толку, если бы они не умели обрабатывать информацию, поступающую от мыши и клавиатуры. К счастью, такая обработка предусмотрена и она выполняется достаточно просто.
    Когда пользователь выполняет операции с мышью или клавиатурой в окне аплета, возникают события, которые передаются соответствующим методам класса Applet. Переопределяя эти методы, вы можете организовать обработку событий, возникающих от мыши или клавиатуры.
    Если вы создавали приложения для операционной системы Microsoft Windows, здесь для вас нет ничего нового - вспомните, как вы обрабатывали сообщение WM_LBUTTONDOWN или WM_CHAR. Когда пользователь выполнял действие с мышью или клавиатурой в окне приложения, функция этого окна получала соответствующее сообщение. Методы класса Applet, обрабатывающие события от мыши и клавиатуры, являются аналогами обработчиков указанных сообщений.
    Заметим, что аплеты имеют дело только с левой клавишей мыши. В текущей версии Java вы не можете никаким образом задействовать в аплете правую или среднюю клавишу мыши.

    Вход курсора мыши в область окна аплета

    Вход курсора мыши в область окна аплета

    Метод mouseEnter получает управление, когда курсор мыши в процессе перемещения по экрану попадает в область окна аплета:
    public boolean mouseEnter(Event evt, int x, int y); Вы можете использовать этот метод для активизации аплета, на который указывает курсор мыши.

    Выход курсора мыши из области окна аплета

    Выход курсора мыши из области окна аплета

    Метод mouseExit вызывается при покидании куросром окна аплета:
    public boolean mouseExit(Event evt, int x, int y); Если пользователь убрал курсор из окна аплета, активизированного методом mouseEnter, то метод mouseExit может переключить аплет в пассивное состояние.

    Выполнение операции Drag and Drop

    Выполнение операции Drag and Drop

    Операция Drag and Drop выполняется следующим образом: пользователь нажимает клавишу мыши и, не отпуская ее, начинает перемещать курсор мыши. При этом происходит вызов метода mouseDrag:
    public boolean mouseDrag(Event evt, int x, int y); Через переменные x и y передаются текущие координаты курсора мыши. Метод mouseDrag вызывается даже в том случае, если в процессе перемещения курсор вышел за пределы окна аплета.

    Подробное руководство по программированию на Java

    Аплет FormDemo


    Аплет FormDemo

    В аплете FormDemo мы покажем приемы работы с компонентами, такими как переключатели, кнопки, текстовые поля и списки.
    Мы разместили несколько таких компонент в окне этого аплета (Рисунок 7) таким образом, что они образуют собой форму. В этой форме вы можете ввести имя и фамилию, выбрать один из трех режимов работы, а также цвет.


    Класс Button

    Класс Button


    Класс Checkbox

    Класс Checkbox

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

    Класс Choice

    Класс Choice

    Приведем описание прототипов конструктора и методов класса Choice:

    Класс Label

    Класс Label

    Ниже мы привели краткое описание класса Label:

    Класс TextArea

    Класс TextArea

    Краткое описание класса TextArea мы привели ниже:

    Класс TextComponent

    Класс TextComponent


    Класс TextField

    Класс TextField

    Приведем краткое описание класса TextField:

    Кнопки


    Кнопки

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

    Компоненты в окне аплета

    Компоненты в окне аплета

    Практически каждое приложение Windows, за исключением самых простейших, имеет такие органы управления, как меню, кнопки, поля редактирования текстовой информации, переключатели с независимой и зависимой фиксацией и списки. Кроме того, приложение Windows может создавать диалоговые панели, содержащие перечисленные выше и другие органы управления.
    В окне аплета вы также можете разместить некоторые из перечисленных выше органов управления, а именно:
  • кнопки;
  • переключатели с независимой фиксацией;
  • переключатели с зависимой фиксацией;
  • статические текстовые поля;
  • однострочные и многострочные поля редактирования текста;
  • списки;
  • полосы просмотра

  • Самый большой и едва ли приятный сюрприз для вас это то, что при размещении перечисленных органов управления в окне аплета вы не можете задать для них точные координаты и размеры. Размещением занимается система управления внешним видом Layout Manager, которая располагает органы управления по-своему. Вы, однако, можете задавать несколько режимов размещения (последовательное, в ячейках таблицы и так далее), но не координаты или размеры. Это сделано для обеспечения независимости приложений Java от платформ, на которых они выполняются.
    Органы управления создаются как объекты классов, порожденных от класса Component (Рисунок 1). Поэтому в дальнейшем мы будем называть органы управления компонентами.

    Компоненты

    Компоненты


    public class FormDemo extends Applet

    Листинг 1

    . Файл FormDemo.java import java.applet.Applet; import java.awt.*; import java.util.*; public class FormDemo extends Applet { Button btReady; Checkbox chbox1; Checkbox chbox2; CheckboxGroup grRadio; Checkbox rd1; Checkbox rd2; Checkbox rd3; Choice ch1; Label lbFirstName; Label lbSecondName; TextField txtFirstName; TextField txtSecondName; TextArea txta; public void init() { chbox1 = new Checkbox("First");
    add(chbox1);
    lbFirstName = new Label("Enter your first name:");
    add(lbFirstName);
    txtFirstName = new TextField(" ", 30);
    add(txtFirstName);
    chbox2 = new Checkbox("Second");
    add(chbox2);
    lbSecondName = new Label("Enter your second name:");
    add(lbSecondName);
    txtSecondName = new TextField(" ", 30);
    add(txtSecondName);
    grRadio = new CheckboxGroup();
    rd1 = new Checkbox("Mode 1", grRadio, true);
    rd2 = new Checkbox("Mode 2", grRadio, false);
    rd3 = new Checkbox("Mode 3", grRadio, false);
    add(rd1);
    add(rd2);
    add(rd3);
    ch1 = new Choice();
    ch1.addItem("White");
    ch1.addItem("Green");
    ch1.addItem("Yellow");
    add(ch1);
    setBackground(Color.yellow);
    lbFirstName.setBackground(Color.yellow);
    lbSecondName.setBackground(Color.yellow);
    rd1.setBackground(Color.yellow);
    rd2.setBackground(Color.yellow);
    rd3.setBackground(Color.yellow);
    chbox1.setBackground(Color.yellow);
    chbox2.setBackground(Color.yellow);
    txta = new TextArea("", 6, 45);
    add(txta);
    txta.setBackground(Color.white);
    btReady = new Button("Ready");
    add(btReady);
    } public String getAppletInfo() { return "Name: FormDemo"; } public void paint(Graphics g) { Dimension dimAppWndDimension = getSize();
    g.setColor(Color.black);
    g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1);
    } public boolean action(Event evt, Object obj) { Button btn; String str1, str2; if(evt.target instanceof Button) { if(evt.target.equals(btReady)) { btn = (Button)evt.target; str1 = txtFirstName.getText();
    str2 = txtSecondName.getText();
    if(chbox1.getState()) txta.append(str1);
    if(chbox2.getState()) txta.append(str2);
    if(rd1.getState()) txta.append("\nMode 1\n");
    if(rd2.getState()) txta.append("\nMode 2\n");
    if(rd3.getState()) txta.append("\nMode 3\n");
    } else { return false; } return true; } else if(evt.target instanceof Choice) { if(evt.target.equals(ch1)) { if(ch1.getSelectedIndex() == 0) txta.setBackground(Color.white);
    if(ch1.getSelectedIndex() == 1) txta.setBackground(Color.green);
    if(ch1.getSelectedIndex() == 2) txta.setBackground(Color.yellow);
    } } return false; } } В листинге 2 мы привели исходный текст документа HTML, созданный для нашего аплета системой Java WorkShop.

    enabled browser, you would see

    Листинг 2

    . Файл FormDemo.tmp.html


    If your browser recognized the applet tag, you would see an applet here.


    Описание исходного текста Приведем краткое описание полей и методов, определенных в аплете FormDemo.

    Поля главного класса В главном классе нашего аплета мы определили несколько полей.
    Поле btReady хранит ссылку на кнопку с надписью Ready:
    Button btReady; В полях chbox1 и chbox2 записаны ссылки на переключатели с независимой фиксацией, которые используются для активизации однострочных текстовых полей:
    Checkbox chbox1; Checkbox chbox2; Поле grRadio хранит ссылку на группу переключателей с зависимой фиксацией, определяющих режимы работы Mode 1, Mode 2 и Mode 3:
    CheckboxGroup grRadio; Ссылки на эти переключатели находятся в следующих трех полях:
    Checkbox rd1; Checkbox rd2; Checkbox rd3; В поле ch1 хранится ссылка на список, предназначенный для выбора цвета:
    Choice ch1; Слева от однострочных полей редактирования в нашем окне имеются подписи, реализованные как объекты класса Label. Ссылки на эти объекты находятся в полях lbFirstName и lbSecondName:
    Label lbFirstName; Label lbSecondName; Ссылки на однострочные поля редактирования записаны в поля с именами txtFirstName и txtSecondName:
    TextField txtFirstName; TextField txtSecondName; И, наконец, ссылка на многострочное текстовое поле хранится в поле с именем txta:
    TextArea txta;

    Метод init Метод init занимается созданием компонент и добавлением их в окно алпета. Кроме того, этот метод изменяет цвет фона окна аплета и окон добавляемых компонент.
    Прежде всего метод init создает два переключателя с независимой фиксацией, два объекта класса Label и два однострочных поля редактирования текста:
    chbox1 = new Checkbox("First");
    add(chbox1);
    lbFirstName = new Label("Enter your first name:");
    add(lbFirstName);
    txtFirstName = new TextField(" ", 30);
    add(txtFirstName);
    chbox2 = new Checkbox("Second");
    add(chbox2);
    lbSecondName = new Label("Enter your second name:");
    add(lbSecondName);
    txtSecondName = new TextField(" ", 30);
    add(txtSecondName);
    Поля создаются при помощи конструкторов, а добавляются в окно аплета методом add. Согласно схемы расположения компонент, установленой по умолчанию, добавляемые компоненты размещаются сверху вниз и слева направо.
    Для группы переключателей с зависимой фиксацией мы создаем объект класса CheckboxGroup:
    grRadio = new CheckboxGroup();
    Ссылка на этот объект затем передается в качестве второго параметра конструкторам, создающим переключатели:
    rd1 = new Checkbox("Mode 1", grRadio, true);
    rd2 = new Checkbox("Mode 2", grRadio, false);
    rd3 = new Checkbox("Mode 3", grRadio, false);
    Переключатели добавляются в окно аплета при помощи метода add:
    add(rd1);
    add(rd2);
    add(rd3);
    Список цветов создается как объект класса Choice:
    ch1 = new Choice();
    После создания списка мы добавляем в него три элемента, вызывая для этого метод addItem:
    ch1.addItem("White");
    ch1.addItem("Green");
    ch1.addItem("Yellow");
    Вслед за этим мы добавляем сформированный список в окно аплета:
    add(ch1);
    Для установки цвета фона мы вызываем метод setBackground без указания объекта:
    setBackground(Color.yellow);
    В этом случае метод вызывается для текущего объекта, то есть для нашего аплета. Чтобы установить цвет фона в окнах компонент, мы вызываем метод setBackground для соответствующих объектов, как это показано ниже:
    lbFirstName.setBackground(Color.yellow);
    lbSecondName.setBackground(Color.yellow);
    rd1.setBackground(Color.yellow);
    rd2.setBackground(Color.yellow);
    rd3.setBackground(Color.yellow);
    chbox1.setBackground(Color.yellow);
    chbox2.setBackground(Color.yellow);
    Многострочное текстовое поле создается как объект класса TextArea. В нем 6 строк и 45 столбцов:
    txta = new TextArea("", 6, 45);
    add(txta);
    Первоначальный цвет фона многострочного текстового поля устанавливается тем же способом, чтомы использовали для других компонент:
    txta.setBackground(Color.white);
    Этот цвет в дальнейшем будет изменяться обработчиком событий, создаваемых списком цветов.
    И, наконец, последнее что делает метод init перед тем как вернуть управление, - создает кнопку с надписью Ready и добавляет ее в окно аплета:
    btReady = new Button("Ready");
    add(btReady);

    Метод action В методе action мы определили рабочие поля btn, str1 и str2:
    Button btn; String str1, str2; В начале своей работы метод action определяет, какой компонент вызвал событие. Для этого анализируется поле evt.target:
    if(evt.target instanceof Button) { . . . return true; } else if(evt.target instanceof Choice) { . . . return true; } return false; Наш метод action обрабатывает события, вызываемые объектами классов Button и Choice. Если событие вызвано компонентом, относящимся к какому-либо другому классу, метод возвращает значение false. Этим он сигнализирует, что обработка события не выполнялась.
    В случае успешной обработки события метод action возвращает значение true.
    Если событие вызвано кнопкой, наш метод action проверяет, какой именно. Обработка выполняется только в том случае, если через поле evt.target передается ссылка на кнопку btReady:
    if(evt.target.equals(btReady)) { . . . } else { return false; } return true; В противном случае метод action возвращает значение false, отказываясь от обработки события.
    Что делает обработчик события, создаваемого кнопкой?
    Прежде всего, он сохраняет ссылку на кнопку в рабочей переменной (просто для того чтобы показать, как это делается):
    btn = (Button)evt.target; Далее наш обработчик события извлекает текстовые строки из однострочных текстовых полей, вызывая для этого метод getText. Эти строки записываются в рабочие переменные str1 и str2:
    str1 = txtFirstName.getText();
    str2 = txtSecondName.getText();
    Затемметод action проверяет состояние переключателей с независимой фиксацией chbox1 и chbox2. Если они включены, содержимое соответствующих временных переменных добавляется в многострочное текстовое поле txta:
    if(chbox1.getState()) txta.append(str1);
    if(chbox2.getState()) txta.append(str2);
    Для добавления мы вызываем метод append.
    Аналогичным образом преверяется состояние переключателей с зависимой фиксацией:
    if(rd1.getState()) txta.append("\nMode 1\n");
    if(rd2.getState()) txta.append("\nMode 2\n");
    if(rd3.getState()) txta.append("\nMode 3\n");
    Если событие вызвано списокм цветов ch1, то метод action определяет, какая строка списка стала выделенной и устанавливает в многострочном поле редактирования соответствующий цвет фона. Для определения выделенной строки применяется метод getSelectedIndex:
    if(evt.target.equals(ch1)) { if(ch1.getSelectedIndex() == 0) txta.setBackground(Color.white);
    if(ch1.getSelectedIndex() == 1) txta.setBackground(Color.green);
    if(ch1.getSelectedIndex() == 2) txta.setBackground(Color.yellow);
    } Работу остальных методов приложения FormDemo вы сможете разобрать самостоятельно.



    Методы

    Методы

  • addNotify
  • Вызов метода createTextField
    public void addNotify();
  • echoCharIsSet
  • Проверка, установлен ли для поля эхо-символ
    public boolean echoCharIsSet();
  • getColumns
  • Определение размера поля
    public int getColumns();
  • getEchoChar
  • Получение текущего эхо-символа
    public char getEchoChar();
  • minimumSize
  • Определение минимальных размеров области для отображения поля
    public Dimension minimumSize(); Определение минимальных размеров области для отображения поля заданной ширины
    public Dimension minimumSize(int cols);
  • paramString
  • Получение строки параметров
    protected String paramString();
  • preferredSize
  • Определение оптимальных размеров области для отображения поля
    public Dimension preferredSize(); Определение оптимальных размеров области для отображения поля заданной ширины
    public Dimension preferredSize(int cols);
  • setEchoCharacter
  • Установка эхо-символа для отображения в поле
    public void setEchoCharacter(char c);

    Методы

    Методы

  • getSelectedText
  • Получение текста, выделенного пользователем в окне поля
    public String getSelectedText();
  • getSelectionEnd
  • Получение позиции конца выделенной области
    public int getSelectionEnd();
  • getSelectionStart
  • Получение позиции начала выделенной области
    public int getSelectionStart();
  • getText
  • Получение полного текста из поля
    public String getText();
  • isEditable
  • Проверка, возможно ли редактирование текста в поле
    public boolean isEditable();
  • paramString
  • Получение строки параметров
    protected String paramString();
  • removeNotify
  • Удаление извещения
    public void removeNotify();
  • select
  • Выделение заданной области текста
    public void select(int selStart, int selEnd);
  • selectAll
  • Выделение всего текста
    public void selectAll();
  • setEditable
  • Включение или выключение возможности редактирования текста
    public void setEditable(boolean t);
  • setText
  • Установка текста в поле
    public void setText(String t); С помощью метода getText вы можете получить весь текст, который имеется в поле. Метод getSelectedText позволяет получить только ту часть текста, которая предварительно была выделена пользователем.
    Приложение может выделить любой фрагмент текста или весь текст при помощи методов select и selectAll, соответственно.
    Для записи текста в поле приложение может воспользоваться методом setText.
    Возможно, для вас будет интересен метод setEditable, позволяющий переключать текстовое поля из режима, при котором редактирование заблокировано, в режим с разрешенным редактированием и обратно.

    Методы

    Методы

  • addNotify
  • Вызов метода createTextArea
    public void addNotify();
  • append
  • Добавление текста в поле редактирования
    public void append(String str);
  • appendText
  • Добавление текста в поле редактирования. Этот метод устарел. Вы должны использовать вместо него метод append, описанный выше.
    public void appendText(String str);
  • getColumns
  • Определение количества столбцов поля
    public int getColumns();
  • getRows
  • Определение количества строк поля
    public int getRows();
  • insertText
  • Добавление текста в поле редактирования начиная с заданной позиции
    public void insertText(String str, int pos);
  • minimumSize
  • Определение минимальных размеров области для размещения многострочного текстового поля
    public Dimension minimumSize(); Определение минимальных размеров области для размещения многострочного текстового поля с заданным количеством строк и столбцов
    public Dimension minimumSize(int rows, int cols);
  • paramString
  • Получение строки параметров
    protected String paramString();
  • preferredSize
  • Определение предпочтительных размеров области для размещения многострочного текстового поля
    public Dimension preferredSize(); Определение предпочтительных размеров области для размещения многострочного текстового поля с заданным количеством строк и столбцов
    public Dimension preferredSize(int rows, int cols);
  • replaceText
  • Замещение блока текста, начиная с первой позиции и до второй позиции
    public void replaceText(String str, int start, int end);

    Методы

    Методы

  • addNotify
  • Вызов метода createButton
    public void addNotify(); Получение надписи на кнопке
  • getLabel
  • public String getLabel();
    Получение строки параметров, отражающей состояние кнопки
  • paramString
  • protected String paramString();
    Установка надписи на кнопке
  • setLabel
  • public void setLabel(String label);
    Из методов класса Button вы будете использовать чаще всего два - getLabel и setLabel. Первый из них позволяет получить строку надписи на кнопке, а второй - установить новую надпись.
    Обычно аплет создает в своем окне кнопки в процессе своей инициализации при обработке метода init, например:
    Button btn1; . . . public void init() { btn1 = new Button("Button 1"); add(btn1); } Здесь мы создали кнопку с надписью Button 1. Затем мы добавили эту кнопку в контейнер, которым является окно аплета, с помощью метода add.

    Методы

    Методы

  • addNotify
  • Вызов метода createCheckbox
    public void addNotify();
  • getCheckboxGroup
  • Получение группы, к которой относится данный переключатель с зависимой фиксацией
    public CheckboxGroup getCheckboxGroup();
  • getLabel
  • Получение названия переключателя
    public String getLabel();
  • getState
  • Определение текущего состояния переключателя
    public boolean getState();
  • paramString
  • Получение строки параметров
    protected String paramString();
  • setCheckboxGroup
  • Установка группы, к которой относится данный переключатель с зависимой фиксацией
    public void setCheckboxGroup(CheckboxGroup g);
  • setLabel
  • Установка названия переключателя
    public void setLabel(String label);
  • setState
  • Установка нового состояния переключателя
    public void setState(boolean state);

    Методы

    Методы

    Получение ссылки на переключатель, который находится во включенном состоянии
    public Checkbox getCurrent(); Установка указанного переключателя в группе во включенное состояние
    public void setCurrent(Checkbox box); Получение строки, которая представляет группу
    public String toString(); Ссылка на этот объект указывается при создании отдельных переключателей с зависимой фиксацией, входящих в группу:
    CheckboxGroup grModeGroup; Checkbox rdbox1; Checkbox rdbox2; Checkbox rdbox3; Checkbox rdbox4; . . . public void init() { grModeGroup = new CheckboxGroup(); rdbox1 = new Checkbox("Mode 1", grModeGroup, true); rdbox2 = new Checkbox("Mode 2", grModeGroup, false); rdbox3 = new Checkbox("Mode 3", grModeGroup, false); rdbox4 = new Checkbox("Mode 4", grModeGroup, false); add(rdbox1); add(rdbox2); add(rdbox3); add(rdbox4); } Через первый параметр конструктору Checkbox в этом примере передается название переключателя, через второй - ссылка на группу, а через третий - состояние, в которое должен быть установлен переключатель. Из всех переключателей группы только один может находиться во включенном состоянии.

    Методы

    Методы

  • addItem
  • Добавление элемента в список
    public void addItem(String item);
  • addNotify
  • Вызов метода createChoice
    public void addNotify();
  • countItems
  • Определение количества элементов в списке
    public int countItems();
  • getItem
  • Получение строки списка по номеру соответствующего ему элемента списка
    public String getItem(int index);
  • getSelectedIndex
  • Получение номера текущего выбранного элемента
    public int getSelectedIndex();
  • getSelectedItem
  • Получение строки, соответствующей текущему выбранному элементу списка
    public String getSelectedItem();
  • paramString
  • Получение строки параметров
    protected String paramString();
  • select
  • Выбор в списке элемента по заданному номеру
    public void select(int pos);
  • select
  • Выбор в списке элемента по заданной строке
    public void select(String str);

    Методы

    Методы

  • addItem
  • Добавление элемента в список
    public void addItem(String item); Добавление элемента в список с указанием номера позиции
    public void addItem(String item, int index);
  • addNotify
  • Вызов метода createList
    public void addNotify();
  • allowsMultipleSelections
  • Переключение списка в режим, при котором возможно выбирать одновременно несколько элементов
    public boolean allowsMultipleSelections();
  • clear
  • Удаление из списка всех элементов
    public void clear();
  • countItems
  • Определение количества элементов в списке
    public int countItems();
  • delItem
  • Удаление элемента из заданной позиции
    public void delItem(int position);
  • delItems
  • Удаление нескольких элементов
    public void delItems(int start, int end);
  • deselect
  • Отмена выделения элемента с заданной позицией
    public void deselect(int index);
  • getItem
  • Получение строки, связанной с элементом, по позиции этого элемента
    public String getItem(int index);
  • getRows
  • Определение количества элементов, которые видны в окне списка
    public int getRows();
  • getSelectedIndex
  • Определение номера выделенного элемента
    public int getSelectedIndex();
  • getSelectedIndexes
  • Определение номеров выделенных элементов
    public int[] getSelectedIndexes();
  • getSelectedItem
  • Получение текстовой строки, связанной с выделенным элементом
    public String getSelectedItem();
  • getSelectedItems
  • Получение ссылки на массив строк, связанных с выделенными элементами
    public String[] getSelectedItems();
  • getVisibleIndex
  • Определение номера элемента массива, который был сделан в последний раз выделенным с помощью метода makeVisible
    public int getVisibleIndex();
  • isSelected
  • Проверка, является ли выделенной строка с заданным номером
    public boolean isSelected(int index);
  • makeVisible
  • Выполняется свертка элементов списка таким образом, чтобы элемент с заданным номером стал видимым
    public void makeVisible(int index);
  • minimumSize

  • Минимальные размеры области, необходимые для отображения списка
    public Dimension minimumSize(); Минимальные размеры области, необходимые для отображения списка с заданным количеством строк
    public Dimension minimumSize(int rows);
  • paramString
  • Получение строки параметров
    protected String paramString();
  • preferredSize
  • Предпочтительные размеры области, необходимые для отображения списка
    public Dimension preferredSize(); Предпочтительные размеры области, необходимые для отображения списка с заданным количеством строк
    public Dimension preferredSize(int rows);
  • removeNotify

  • Извещение об уничтожении узла
    public void removeNotify();
  • replaceItem
  • Замещение элемента списка с заданным номером
    public void replaceItem(String newValue, int index);
  • select
  • Выделение элемента с заданным номером
    public void select(int index);
  • setMultipleSelections
  • Установка или сброс режима одновременного выделения нескольких строк
    public void setMultipleSelections(boolean v);

    Методы

    Методы

  • addNotify
  • Вызов метода createLabel
    public void addNotify();
  • getAlignment
  • Определение текущего выравнивания текстового поля
    public int getAlignment();
  • getText
  • Получение текста из поля
    public String getText();
  • paramString
  • Получение строки параметров
    protected String paramString();
  • setAlignment
  • Установка выравнивания текстового поля
    public void setAlignment(int alignment);
  • setText
  • Запись текста в поле
    public void setText(String label);

    Многострочное текстовое поле класса TextArea

    Многострочное текстовое поле класса TextArea

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

    Обработка событий от кнопки

    Обработка событий от кнопки

    Для обработки событий, создаваемых кнопками и другими компонентами, вы можете переопределить метод handleEvent. Однако существует и более простой способ.
    Этот способ основан на переопределении метода action, который получает управление, когда пользователь совершает какое-либо действие с компонентом. Под действием подразумевается нажатие на кнопку, завершение ввода текстовой строки, выбор элемента из списка, изменение состояния переключателя и так далее.
    Прототип метода action представлен ниже:
    public boolean action(Event evt, Object obj) { . . . } В качестве первого параметра методу передается ссылка на объект класса Event, содержащий всю информацию о событии. Второй параметр представляет собой ссылку на объект, вызвавший появление события.
    Как обрабатывать событие в методе action?
    Прежде всего необходимо проверить, объект какого типа создал событие. Это можно сделать, например, следующим образом:
    if(evt.target instanceof Button) { . . . return true; } return false; Здесь мы с помощью оператора instanceof проверяем, является ли объект, вызвавший появление события, объектом класса Button.
    Далее, если в окне аплета имеется несколько кнопок, необходимо выполнить ветвление по ссылкам на объекты кнопок, как это показано ниже:
    if(evt.target.equals(btn1)) { . . . } else if(evt.target.equals(btn2)) { . . . } . . . else { return false; } return true; Тем из вас, кто создавал приложения Windows на языке программирования С, этот фрагмент кода может напомнить длинный переключатель switch обработки сообщений Windows.

    Обработка событий от списка класса List

    Обработка событий от списка класса List

    В отличие от списка класса Choice, для выбора строки (или нескольких строк) из списка класса List, пользователь должен сделать двойной щелчок левой клавишей мыши по выделенному элементу (или элементам, если выделено несколько элементов). При этом событие можно обработать переопределенным методом action, как мы это делали для списка класса Choice.
    Однако список класса List создает события не только при двойном щелчке, но и при выделении или отмены выделения элементов, сделанном пользователем одинарным щелчком клавиши мыши. Аплет может перехватывать и обрабатывать такие события, переопределив метод handleEvent.

    Описание класса List

    Описание класса List

    В классе List определено два конструктора и довольно много различных методов. Ниже мы привели краткое описание класса List:

    Переключатели


    Переключатели

    Аплеты Java могут создавать в своем окне переключатели двух типов: с независимой фиксацией и с зависимой фиксацией.
    Переключатели с независимой фиксацией имеют прямоугольную форму и, исходя из названия, работают независимо друг от друга. Если такой переключатель находится во включенном состоянии, внутри изображения маленького квадрата появляется галочка, если в выключенном - галочка исчезает.
    Обычно переключатели с независимой фиксацией используются для управления независящими друг от друга режимами или параметрами.
    Переключатели с зависимой фиксацией имеют круглую форму. В каждый момент времени может быть включен только один такой переключатель из группы переключателей с фиксацией. Аплет может создавать несколько групп переключателей с зависимой фиксацией.
    Переключатели с зависимой фиксацией используются для выбора из нескольких взаимоисключающих возможностей, например, для установки одного из нескольких режимов.

    Поле Label

    Поле Label


    Поле TextArea

    Поле TextArea


    Поле TextField

    Поле TextField


    Поля

    Поля

    Поля класса Label задают способ выравнивания текстового поля
  • CENTER

  • Центрирование
    public final static int CENTER;
  • LEFT
  • Выравнивание по левой границе
    public final static int LEFT;
  • RIGHT
  • Выравнивание по правой границе
    public final static int RIGHT;

    Взаимосвязь классов

    Рисунок 1. Взаимосвязь классов органов управления в приложениях Java

    Взаимосвязь классов
    Класс Button позволяет создавать стандартные кнопки. Если вам нужна нестандартная кнопка (например, графическая кнопка), вы можете создать ее на базе класса Canvas.
    Для создания переключателей с независимой или зависимой фиксацией предназначен класс CheckBox.
    С помощью класса Label вы можете создавать в окне аплета текстовые строки, например, надписи для других компонент. Эти строки не редактируются пользователем.
    Класс List, как нетрудно догадаться из названия, предназначен для создания списков.
    С помощью класса Scrollbar вы можете создавать полосы просмотра, которые используются, в частности, могострочными полями редактирования текста.
    Класс TextComponent служит базовым для двух других классов - TextField и TextArea. Первый из них предназначен для создания однострочных редакторов текста, второй - для создания многострочных редкаторов текста.
    Для того чтобы понять, как компоненты размещаются на поверхности окна аплета системой Layout Manager, рассмотрим другую взаимосвязь классов Java, показанную на Рисунок 2.

    Компоненты и контейнеры

    Рисунок 2. Компоненты и контейнеры

    Компоненты и контейнеры
    Класс Component служит в качестве базового класса для класса Container. Объекты этого класса, которые мы будем называть контейнерами, могут содержать объекты классов Component и Container. Таким образом, внутри контейнеров могут находиться компоненты и другие контейнеры.
    Класс Applet, так же как и другие классы, произведенные от класса Container, является контейнером. Это означает, что аплет может содержать в себе компоненты (такие как органы управления) и контейнеры.
    Заметим, что класс Applet наследуется от класса Container через класс Panel, в котором определены методы системы Layout Manager. Настраивая соответствующим образом Layout Manager, мы можем менять стратегию размещения компонент внутри окна аплета.
    В окне аплета вы можете создать несколько объектов класса Panel (панелей), разделяющих окно на части. Для каждой такой панели можно установить свою стратегию размещения компонент и контейнеров, что позволяет выполнять достаточно сложную компоновку в окне аплета.
    Теперь после такого краткого введения в контейнеры и компоненты мы перейдем к описанию методов создания отдельных компонент.

    Список типа Drop Down

    Рисунок 3. Список типа Drop Down, созданный на базе класса Choice

    Список типа Drop Down
    Если нажать на эту кнопку, список раскроется и вы сможете сделать выбор из его элементов (Рисунок 4).

    Раскрытый список созданный на базе класса Choice

    Рисунок 4. Раскрытый список, созданный на базе класса Choice

    Раскрытый список созданный на базе класса Choice
    В списке класса Choice одновременно можно выбрать только один элемент.

    Список класса List все

    Рисунок 5. Список класса List, все элементы которого помещаются в окне списка

    Список класса List все
    Если размеры окна списка класса List недостаточны для того чтобы вместить в себя все элементы, в правой части окна списка автоматически создается полоса просмотра, с помощью которой можно пролистать весь список (Рисунок 6).

    Список класса List с полосой просмотра

    Рисунок 6. Список класса List с полосой просмотра


    Список класса List с полосой просмотра



    Окно аплета FormDemo

    Рисунок 7. Окно аплета FormDemo


    Окно аплета FormDemo



    Окно аплета FormDemoДля

    Рисунок 7. Окно аплета FormDemoДля того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению
    Переключатели First и Second активизируют однострочные текстовые поля редактирования Enter your first name и Enter your second name. После того как пользователь нажмет кнопку Ready, содержимое активных полей, а также состояние переключателей Mode 1, Mode 2 и Mode 3 будет отображено в многострочном поле редактирования. Это поле находится в нижней части окна аплета.

    Окно аплета FormDemoДля

    С помощью списка, расположенного справа от переключателя Mode 3, можно задавать цвет фона многострочного поля. Цвет устанавливается сразу после выбора новой строки из этого списка.
    К сожалению, при изменении размеров окна аплета находящиеся в нем компоненты изменяют свое расположение. Этот недостаток мы устраним после того, как расскажем вам о системе Layout Manager, с помощью которой вы можете управлять размещением компонент в окне аплета.

    Исходный текст аплета FormDemo Исходный текст аплета FormDemo вы найдете в листинге 1.



    Создание переключателей с независимой фиксацией

    Создание переключателей с независимой фиксацией

    Создать переключатель с независимой фиксацией не сложнее, чем создать кнопку:
    Checkbox rdbox1; . . . public void init() { chbox1 = new Checkbox("Switch 1"); add(chbox1); } В этом фрагменте кода мы создаем переключатель chbox1 с названием Switch 1, а затем с помощью метода add добавляем его в контейнер, которым является окно аплета.
    Для определения текущего состояния переключателя вы можете использовать метод getState. Если переключатель включен, этот метод возвращает значение true, а если выключен - значение false.

    Создание переключателей с зависимой фиксацией

    Создание переключателей с зависимой фиксацией

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

    Создание поля класса Label

    Создание поля класса Label

    Текстовое поле класса Label создается вызовом соответствующего конструктора. Например, ниже мы создали текстовое поле, указав строку, которую надо в него записать:
    Label lbTextLabel; lbTextLabel = new Label("Выберите выравнивание"); С помощью метода add вы можете добавить текстовое поле в окно аплета:
    add(lbTextLabel); Метод setAlignment позволяет при необходимости изменить выравнивание текста. Способ выравнивания необходимо указать через единственный параметр метода:
    lbTextLabel.setAlignment(Label.LEFT); При помощи метода setText вы сможете динамически изменять текст, расположенный в поле класса Label.

    Создание поля TextArea

    Создание поля TextArea

    Когда вы создаете многострочное текстовое поле редактирования, то можете использовать конструктор, допускающий указание размеров поля в строках и столбцах:
    TextArea txt; txt = new TextArea("Введите строку текста", 5, 35); Созданное поле добавляется в окно аплета методом add.
    Отметим, что в классе TextArea есть методы для работы с блоками текста (вставка и замена), а также методы, с помощью которых можно определить количество строк и столбцов в поле редактирования.

    Создание списка класса List

    Создание списка класса List

    Процесс создания списка класса List несложен:
    List chBackgroundColor; chBackgroundColor = new List(6, false); При создании списка вы передаете конструктору количество одновременно отображаемых строк и флаг разрешения одновременного выбора нескольких строк. Если значение этого флага равно true, пользователь сможет выбирать из списка одновременно несколько строк, а если false - только одну строку.
    Для наполнения списка вы можете использовать уже знакомый вам метод addItem:
    chBackgroundColor.addItem("Yellow"); chBackgroundColor.addItem("Green"); chBackgroundColor.addItem("White"); Список класса List добавляется к окну аплета методом add:
    add(chBackgroundColor); Кратко остановимся на нескольких методах класса List.
    Если вы разрешили пользователю выбирать из списка одновременно несколько элементов, то для получения ссылки на массив выбранных элементов вам пригодятся методы getSelectedItems и getSelectedIndexes:
    public String[] getSelectedItems(); public int[] getSelectedIndexes(); С помощью метода setMultipleSelections вы можете динамически включать или выключать режим одновременного выбора нескольких элементов.
    В некоторых случаях вам может пригодиться метод clear, удаляющий все элементы из списка:
    public void clear(); Методика использования других методов очевидна из краткого описания класса List, приведенного в нашей статье.

    Создание списков

    Создание списков

    Конструктор класса Choice не имеет параметров. Создание списка с его помощью не вызовет у вас никаких затруднений:
    Choice chBackgroundColor; chBackgroundColor = new Choice(); Для наполнения списка используйте метод addItem. В качестве параметра ему необходимо передать текстовую строку, которая будет связана с добавляемым элементом списка:
    chBackgroundColor.addItem("Yellow"); Далее список можно добавить в окно аплета как компонент с помощью метода add:
    add(chBackgroundColor); Заметим, что список можно заполнять до или после добавления в окно аплета.
    После наполнения списка по умолчанию выделяется элемент, который был добавлен в список первым. При помощи метода select вы можете выделить любой элемент списка по его номеру или строке, связанной с элементом.
    Когд пользователь выбирает новую строку в списке, возникает событие. Обработчик этого события, реализованный, например, переопределением метода action, может получить номер выбранной строки при помощи метода getSelectedIndex. Пример обработки такого события вы найдете в разделе "Приложение ChoiceList".
    Если вас интересует не номер выбранного элемента, а строка, связанная с выбранным элементом, воспользуйтесь методом getSelectedItem.
    И, наконец, с помощью метода getItem вы можете получить текст строки, связанной с элементом, по номеру элемента.

    Создание текстового поля класса TextField

    Создание текстового поля класса TextField

    При создании текстового поля вы можете выбрать один из четырех конструкторов, соответственно, для создания поля без текста и без указания размера, без текста заданного размера, для создания поля с текстом и для создания поля с текстом указанного размера.
    Вот фрагмент кода, в котором создается поле с текстом, имеющее ширину, достаточную для размещения 35 символов:
    TextField txt; txt = new TextField( "Введите строку текста", 35); Созданное поле добавляется в окно аплета методом add.
    Большинство самых полезнных методов, необходимых для работы с полем класса TextField, определено в классе TextComponent, краткое описание которого мы привели ниже.

    Списки Choice

    Списки Choice


    Списки класса Choice

    Списки класса Choice

    На базе класса Choice вы можете создать списки типа Drop Down или, как их еще называют, "выпадающие" списки. Такой список выглядит как текстовое поле высотой в одну строку, справа от которого располагается кнопка (Рисунок 3).

    Списки класса List

    Списки класса List

    На базе класса List вы можете сделать список другого типа, который допускает выбор не только одного, но и нескольких элементов. В отличие от списка, созданного на базе класса Choice, список класса List может занимать прямоугольную область, в которой помещаются сразу несколько элементов. Этот список всегда находится в раскрытом состоянии (Рисунок 5).

    Списки List

    Списки List


    Текстовое поле класса Label

    Текстовое поле класса Label

    На базе класса Label вы можете создать в окне аплета однострочное текстовое поле, которое не поддается редактированию. Основное назначение таких полей - подпись других компонент, таких, например, как группы переключателей или списки.

    Текстовое поле класса TextField

    Текстовое поле класса TextField

    Для редактирования одной строки текста вы можете создать текстовое поле на базе класса TextField, которое несложно в использовании. Класс TextField создан на базе другого класса с именем TextComponent, поэтому при работе с текстовым полем класса TextField вы можете использовать и методы класса TextComponent.

    Подробное руководство по программированию на Java

    Аплет FormLayout


    Аплет FormLayout

    В окне аплета FormLayout (Рисунок 2) мы расположили те же самые органы управления, которые были использованы в предыдущем аплете FormDemo. Однако для указания способа размещения компонент мы выполнили настройку системы Layout Manager, выбрав режим GridLayout.


    Исходный текст аплета FormLayout

    Исходный текст аплета FormLayout

    Исходный текст аплета FormLayout практически повторяет исходный текст аплета FormDemo, рассмотренный в нашей предыдущей статье. Единственное отличие заключается в том, что в методе init мы выполнили настройку системы Layout Manager, установив режим GridLayout:
    public void init() { setLayout(new GridLayout(4, 3)); . . . } Здесь для размещения компонент в окне аплета создается таблица из четырех строк и трех столбцов.
    Полный исходный текст аплета FormLayout вы найдете в листинге 1.

    Использование режима размещения CardLayout

    Использование режима размещения CardLayout

    Как пользоваться режимом размещения CardLayout?
    Обычно в окне аплета создается две панели, одна из которых предназначена для показа страниц блокнота в режиме размещения CardLayout, а вторая содержит органы управления перелистыванием страниц, например, кнопки.
    Такие методы, как first, last, next и previous позволяют отображать, соответственно, первую, последнюю, следующую и предыдущую страницу блокнота. Если вызвать метод next при отображении последней страницы, в окне появится первая страница. Аналогично, при вызове метода previous для первой страницы блокнота вы увидите последнюю страницу.
    А как отобразить произвольную страницу, не перебирая их по одной методами next и previous?
    Для этого существует метод show. Учтите, что этот метод позволяет отображать только такие страницы, при добавлении которых методом add было указано имя, например:
    pCardPanel.add("BackgroundColor", pBackgroundColor); pCardPanel.add("ForegroundColor", pForegroundColor); pCardPanel.add("Font", pFont); Здесь в панель pCardPanel добавляются панели pBackgroundColor, pForegroundColor и pFont, имеющие имена, соответственно, "BackgroundColor", "ForegroundColor" и "Font".

    Класс FlowLayout

    Класс FlowLayout

    Ниже мы привели краткое описание класса FlowLayout:

    Конструкторы класса BorderLayout

    Конструкторы класса BorderLayout

    Ниже приведено краткое описание конструкторов класса BorderLayout.
    public BorderLayout(); public BorderLayout(int hgap, int vgap); Эти конструкторы предназначены для создания схемы размещения, без зазора между компонентами и с зазором заданной величины,соответственно.

    Конструкторы класса CardLayout

    Конструкторы класса CardLayout

    Режим без зазоров
    public CardLayout(); Режим с зазорами по вертикали и горизонтали между компонентами и окном контейнера
    public CardLayout(int hgap, int vgap);

    Конструкторы

    Конструкторы

    Создание таблицы с заданным количеством строк и столбцов
    public GridLayout( int rows, int cols); Создание таблицы с заданным количеством строк и столбцов и с заданным зазором между компонентами
    public GridLayout(int rows, int cols, int hgap, int vgap);

    Конструкторы

    Конструкторы

    Без указания выравнивания и зазора между компонентами
    public FlowLayout();
    С указанием выравнивания
    public FlowLayout(int align); С указанием выравнивания и зазора между компонентами по вертикали и горизонтали
    public FlowLayout(int align, int hgap, int vgap); Обычно приложения не вызывают методы класса FlowLayout, устанавливая варианты компоновки при помощи конструкторов.
    Первый конструктор класса FlowLayout не имеет параметров. Он устанавливает по умолчанию режим центрирования компонент и зазор между компонентами по вертикали и горизонтали, равный 5 пикселам. Именно этот режим и использовался раньше во всех наших аплетах, так как именно он применяется по умолчанию объектами класса Panel, от которого наследуется класс Applet.
    С помощью второго конструктора вы можете выбрать режим размещения с заданным выравниванием компонент в окне контейнера по горизонтали. В качестве параметров этому конструктору необходимо передавать значения FlowLayout.LEFT, FlowLayout.RIGHT, или FlowLayout.CENTER. Зазор между компонентами будет при этом равен по умолчанию 5 пикселам.
    И, наконец, третий конструктор допускает раздельное указание режима выравнивания, а также зазоров между компонентами по вертикали и горизонтали в пикселах.

    public class FormLayout extends Applet

    Листинг 1

    . Файл FormLayout.java import java.applet.Applet; import java.awt.*; import java.util.*; public class FormLayout extends Applet { Button btReady; Checkbox chbox1; Checkbox chbox2; CheckboxGroup grRadio; Checkbox rd1; Checkbox rd2; Checkbox rd3; Choice ch1; Label lbFirstName; Label lbSecondName; TextField txtFirstName; TextField txtSecondName; TextArea txta; public void init() { setLayout(new GridLayout(4, 3));
    chbox1 = new Checkbox("First");
    add(chbox1);
    lbFirstName = new Label( "Enter your first name:");
    add(lbFirstName);
    txtFirstName = new TextField(" ", 30);
    add(txtFirstName);
    chbox2 = new Checkbox("Second");
    add(chbox2);
    lbSecondName = new Label( "Enter your second name:");
    add(lbSecondName);
    txtSecondName = new TextField(" ", 30);
    add(txtSecondName);
    grRadio = new CheckboxGroup();
    rd1 = new Checkbox("Mode 1", grRadio, true);
    rd2 = new Checkbox("Mode 2", grRadio, false);
    rd3 = new Checkbox("Mode 3", grRadio, false);
    add(rd1);
    add(rd2);
    add(rd3);
    ch1 = new Choice();
    ch1.addItem("White");
    ch1.addItem("Green");
    ch1.addItem("Yellow");
    add(ch1);
    setBackground(Color.yellow);
    lbFirstName.setBackground( Color.yellow);
    lbSecondName.setBackground( Color.yellow);
    rd1.setBackground(Color.yellow);
    rd2.setBackground(Color.yellow);
    rd3.setBackground(Color.yellow);
    chbox1.setBackground(Color.yellow);
    chbox2.setBackground(Color.yellow);
    txta = new TextArea("", 6, 45);
    add(txta);
    txta.setBackground(Color.white);
    btReady = new Button("Ready");
    add(btReady);
    } public String getAppletInfo() { return "Name: FormDemo"; } public void paint(Graphics g) { Dimension dimAppWndDimension = getSize();
    g.setColor(Color.black);
    g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1);
    } public boolean action(Event evt, Object obj) { Button btn; String str1, str2; if(evt.target instanceof Button) { if(evt.target.equals(btReady)) { btn = (Button)evt.target; str1 = txtFirstName.getText();
    str2 = txtSecondName.getText();
    if(chbox1.getState()) txta.append(str1);
    if(chbox2.getState()) txta.append(str2);
    if(rd1.getState()) txta.append("\nMode 1\n");
    if(rd2.getState()) txta.append("\nMode 2\n");
    if(rd3.getState()) txta.append("\nMode 3\n");
    } else { return false; } return true; } else if(evt.target instanceof Choice) { if(evt.target.equals(ch1)) { if(ch1.getSelectedIndex() == 0) txta.setBackground(Color.white);
    if(ch1.getSelectedIndex() == 1) txta.setBackground(Color.green);
    if(ch1.getSelectedIndex() == 2) txta.setBackground(Color.yellow);
    } } return false; } } Исходный текст документа HTML, созданный для нашего аплета системой Java WorkShop, представлен в листинге 2.

    enabled browser, you would see

    Листинг 2

    . Файл FormLayout.tmp.html


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

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

    Перечислим также методы класса BorderLayout:
    public void addLayoutComponent( String name, Component comp); public void layoutContainer( Container target); public Dimension minimumLayoutSize( Container target); public Dimension preferredLayoutSize( Container target); public void removeLayoutComponent( Component comp); public String toString();

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

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

  • addLayoutComponent
  • Добавление компоненты с указанием имени
    public void addLayoutComponent( String name, Component comp);
  • first
  • Отображение первой страницы блокнота
    public void first(Container target);
  • last
  • Отображение последней страницы блокнота
    public void last(Container target);
  • next
  • Отображение следующей страницы блокнота
    public void next(Container target);
  • previous
  • Отображение предыдущей страницы блокнота
    public void previous(Container target);
  • layoutContainer
  • Выполнение размещения компонент
    public void layoutContainer( Container target);
  • minimumLayoutSize
  • Определение минимальных размеров окна, необходимых для размещения компонент
    public Dimension minimumLayoutSize( Container target);
  • preferredLayoutSize
  • Определение предпочтительных размеров окна, необходимых для размещения компонент
    public Dimension preferredLayoutSize( Container target);
  • removeLayoutComponent
  • Удаление заданной компоненты
    public void removeLayoutComponent( Component comp);
  • show
  • Отображение произвольной страницы блокнота по ее имени
    public void show( Container target, String name);
  • toString
  • Получение текстовой строки названия режима размещения
    public String toString();

    Методы

    Методы

  • addLayoutComponent
  • Не используется
    public void addLayoutComponent( String name, Component comp);
  • layoutContainer
  • Предназначен для того чтобы компоненты могли установить для себя предпочтительный размер
    public void layoutContainer( Container target);
  • minimumLayoutSize
  • Определение минимального размера окна контейнера, необходимого для размещения всех компонент
    public Dimension minimumLayoutSize( Container target);
  • preferredLayoutSize
  • Определение предпочтительного размера окна контейнера, необходимого для размещения всех компонент
    public Dimension preferredLayoutSize( Container target);
  • removeLayoutComponent
  • Удаление компоненты из контейнера
    public void removeLayoutComponent( Component comp);
  • toString
  • Получение строки названия метода компоновки
    public String toString();

    Методы

    Методы

    Методы класса GridLayout используются редко, поэтому мы их только перечислим.
    public void addLayoutComponent( String name,Component comp); public void layoutContainer( Container target); public Dimension minimumLayoutSize( Container target); public Dimension preferredLayoutSize( Container target); public void removeLayoutComponent( Component comp); public String toString();

    Поля

    Поля

    Следующие три поля задают способы выравнивания:
  • CENTER

  • Центрирование
    public final static int CENTER;
  • LEFT
  • По левой границе
    public final static int LEFT;
  • RIGHT
  • По правой границе
    public final static int RIGHT;

    Применение класса BorderLayout

    Применение класса BorderLayout

    Добавляя компоненты к контейнеру, вы должны использовать метод add с двумя параметрами, первый из которых указывает направление размещения, а второй - ссылку на добавляемый объект:
    add("North", btn1); add("East", btn2); add("West", btn3); add("South", btn4); add("Center", btn5);

    Работа с системой Layout Manager


    Работа с системой Layout Manager

    В предыдущей статье мы рассказали вам о том, как создавать компоненты и размещать их в контейнере. Однако предложенный способ размещения компонент в окне контейнера едва ли можно назвать удобным, так как заранее трудно предугадать, на каком месте окажется тот или иной орган управления.
    К счастью, имеются способы, позволяющие контролировать размещение отдельных компонент в окне контейнера. И хотя эти способы не позволяют задавать конкретные координаты и размеры органов управления, использовнные схемы размещения компонент будут правильно работать на любой аппаратной платформе (не забывайте, что Java создавалась как средство разработки приложений, способных выполняться на любой платформе).
    В чем трудность создания пользовательского интерфейса для мультиплатформных систем?
    В том, что разработчик приложения никогда не знает характеристики устройства отображения, установленные у пользователя. Он, в частности, не может заранее знать разрешение монитора, размер системного шрифта и другие характеристики, необходимые для компоновки диалоговых панелей в терминах абсолютных координат.
    Средства пользовательского интерфейса AWT способны динамически измнять размеры компонент, подгоняя их "по месту" в системе пользователя. В результате значительно повышается вероятность того что внешний вид диалоговой панели, в каком она предстанет перед пользователем, будет похож на то, что ожидал разработчик.

    Режим BorderLayout

    Режим BorderLayout

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

    Режим CardLayout

    Режим CardLayout

    Режим CardLayout предназначен для создания набора диалоговых панелей, которые можно показывать по очереди в одном окне прямоугольной формы. Обычно для управления процессом перебора диалоговых панелей в режиме CardLayout используются отдельные органы управления, расположенные в другой панели или даже в другом аплете на той же самой странице сервера Web.
    Класс CardLayout содержит два конструктора и несколько методов.

    Режим FlowLayout

    Режим FlowLayout

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

    Режим GridBagLayout

    Режим GridBagLayout

    Режим GridBagLayout намного сложнее только что описанного режима GridLayout. Он позволяет размещать компоненты разного размера в таблице, задавая при этом для отдельных компонент размеры отступов и количество занимаемых ячеек.
    Сейчас мы не будем рассматривать этот режим, так как сходные результаты могут быть достигнуты другими, менее сложными способами. Например, вы можете создать в контейнере несколько панелей, использовав внутри каждой свой метод размещения компонент.
    Если вы создаете аплеты для размещения в документах HTML, никто не заставляет вас ограничиваться только одним аплетом для одного документа HTML - вы можете разместить там произвольное количество аплетов, организовав взаимодействие с одной стороны, между отдельными аплетами, а с другой - между аплетами и расширениями сервера Web.
    В интегрированной системе разработки приложений Java WorkShop версии 2.0 имеется встроенная система визуального проектирования пользовательского интерфейса, в результате работы которой создаются исходные тексты классов. Размещение органов управления при этом выполняется интерактивными средствами.

    Режим GridLayout

    Режим GridLayout

    В режиме GridLayout компоненты размещаются в ячейках таблицы, параметры которой можно задать с помощью конструкторов класса GridLayout.
    При размещении компонент внутри ячеек таблицы все они получают одинаковые размеры. Если один из параметров, задающих размерность таблицы, равен нулю, это означает, что соответствующий столбец или строка может содержать любое количество элементов.
    Заметим, что оба параметра rows и cols не могут быть равны нулю одновременно.
    Приведем описание конструкторов класса GridLayout.

    Режимы BorderLayout

    Режимы BorderLayout


    Режимы CardLayout

    Режимы CardLayout


    Режимы FlowLayout

    Режимы FlowLayout


    Режимы GridBagLayout

    Режимы GridBagLayout


    Режимы GridLayout

    Режимы GridLayout


    Окно аплета FormLayout

    Рисунок 2. Окно аплета FormLayout


    Окно аплета FormLayout



    Окно аплета FormLayoutДля

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

    Окно аплета FormLayoutДля

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

    Подробное руководство по программированию на Java

    Аплет Options


    Аплет Options

    Аплет Options демонстрирует методики работы с панелями, а также с различными режимами системы Layout Manager.
    В окне аплета Options мы создали три панели (Рисунок 2).

    Добавление компонент в панели

    Добавление компонент в панели

    Для добавления компонент в панель вы должны указать, для какой панели вызывается метод add, например:
    Botton btn1; Botton btn2; btn1 = new Button(); btn2 = new Button(); pBottomPanel.add(btn1); pBottomPanel.add(btn2);

    Добавление компонент

    Добавление компонент


    Добавление панелей


    Добавление панелей

    Создав панели, вы можете добавить их в окно аплета, вызвав метод add, как это показано ниже:
    add(pTopPanel); add(pBottomPanel); Заметим, что вы можете добавлять панели в панели, указывая, для какой панели нужно вызывать метод add:
    Panel pLeft; Panel pRight; pLeft = new Panel(); pRight = new Panel(); pTopPanel.setLayout(new GridLayout(1, 2)); pTopPanel.add(pLeft); pTopPanel.add(pRight); Здесь мы создали две панели pLeft и pRight, которые по нашему замыслу должны разделить пространство панели pTopPanel на две части по вертикали. Для обеспечения вертикального размещения панелей pLeft и pRight в панели pTopPanel мы вызвали для панели pTopPanel метод setLayout. При этом мы указали, что компоненты, добавляемые в эту панель, должны размещаться в таблице, состоящей из односй строки и двух столбцов.
    Затем панели pLeft и pRight были добавлены в панель pTopPanel методом add.

    Главный класс аплета Options

    Главный класс аплета Options

    В главном классе аплета Options мы определили три поля с именами pPanel1, pCard и pControl:
    FirstPanel pPanel1; CardPanel pCard; ControlPanel pControl; В них хранятся ссылки на три класса, созданных нами для трех панелей.

    Исходный текст аплета Options

    Исходный текст аплета Options

    Исходный текст аплета Options представлен в листинге 1.

    Исходный текст

    Исходный текст


    Класс CardPanel

    Класс CardPanel

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

    Класс ControlPanel

    Класс ControlPanel

    Класс ControlPanel создан для нижней панели с управляющими кнопками.

    Класс FirstPanel

    Класс FirstPanel

    Мы создали класс FirstPanel на базе класса Panel, определив в нем одно поле типа String и переопределив метод paint:
    class FirstPanel extends Panel { . . . } Текстовое поле szFontName хранит название шрифта, с использованием которого в окне верхней панели отображается текстовая строка:
    String szFontName = "TimesRoman"; Метод paint определяет текущие размеры панели и рисует вокруг нее прямоугольную рамку:
    Dimension dimAppWndDimension = getSize(); g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); Далее метод paint выбирает в контекст отображения, связанный с панелью, шрифт с названием szFontName и рисует текстовую строку:
    g.setFont(new Font(szFontName, Font.PLAIN, 24)); g.drawString("First panel", 10, 50); Заметим, что сразу после запуска аплета рамка и строка будут нарисованы с использованием черного цвета, выбранного в контекст отображения панели по умолчанию. В дальнейшем вы можете изменить этот цвет при помощи соответствующей страницы блокнота, реализованного во второй панели.
    Последнее действие, которое выполняет метод paint первой панели - вызов метода paint из родительского класса:
    super.paint(g); Это приводит к перерисовке окна аплета.

    Класс на базе Panel

    Класс на базе Panel


    Конструктор класса CardPanel

    Конструктор класса CardPanel

    При создании объекта класса CardPanel мы передаем конструктору ссылку на верхнюю панель, параметрами которой нужно управлять. Конструктор записывает эту ссылку в поле pControlled:
    public CardPanel(Panel pControlledPanel) { pControlled = pControlledPanel; . . . } Затем конструктор устанавливает режим размещения CardLayout, оставляя зазор по вертикали и горизонтали, равный пяти пикселам:
    setLayout(new CardLayout(5, 5)); На следующем этапе мы создаем три панели для страниц блокнота и добавляем их в панель CardPanel, задавая имена:
    pBgColor = new Panel(); pFgColor = new Panel(); pFont = new Panel(); add("BgColor", pBgColor); add("FgColor", pFgColor); add("Font", pFont); Теперь нам нужно создать и заполнить три списка, предназначенный для выбора цвета и шрифта. Эти списки создаются как объекты класса Choice:
    chBgColor = new Choice(); chFgColor = new Choice(); chFont = new Choice(); После создания списки наполняются текстовыми строками. В каждый список мы добавляем по три строки:
    chBgColor.add("Yellow"); chBgColor.add("Green"); chBgColor.add("White"); chFgColor.add("Black"); chFgColor.add("Red"); chFgColor.add("Green"); chFont.add("TimesRoman"); chFont.add("Helvetica"); chFont.add("Courier"); Для того чтобы снабдить списки подписями, мы создаем три объекта класса Label:
    lbBgColor = new Label("Background color"); lbFgColor = new Label("Foreground color"); lbFont = new Label("Font"); Эти объекты, а также списки добавляются на свои страницы блокнота (то есть в свои панели):
    pBgColor.add(lbBgColor); pBgColor.add(chBgColor); pFgColor.add(lbFgColor); pFgColor.add(chFgColor); pFont.add(lbFont); pFont.add(chFont); На этом работа метода init заканчивается.

    Конструктор класса ControlPanel

    Конструктор класса ControlPanel

    В задачу конструктора класса ControlPanel входит запоминание ссылки на панель блокнота, установка режима размещения компонент GridLayout, а также создание и добавление в нижнюю панель управляющих кнопок:
    public ControlPanel(Panel pCardPanel) { pCard = pCardPanel; setLayout(new GridLayout(2,3)); btBgColor = new Button("Background Color"); btFgColor = new Button("Foreground Color"); btFont = new Button("Set Font"); btNext = new Button("Next"); btPrev = new Button("Prev"); add(btBgColor); add(btFgColor); add(btFont); add(btNext); add(btPrev); } Кнопки располагаются в ячейках таблицы, содержащей две строки и три столбца. В целом конструктор класса ControlPanel не имеет никаких интересных особенностей.

    public class Options extends Applet

    Листинг 1

    . Файл Options.java import java.applet.*; import java.awt.*; public class Options extends Applet { FirstPanel pPanel1; CardPanel pCard; ControlPanel pControl; public String getAppletInfo() { return "Name: Options"; } public void init() { setLayout(new GridLayout(3, 1));
    pPanel1 = new FirstPanel();
    add(pPanel1);
    pCard = new CardPanel(pPanel1);
    add(pCard);
    pControl = new ControlPanel(pCard);
    add(pControl);
    pPanel1.setBackground(Color.yellow);
    pPanel1.setForeground(Color.black);
    repaint();
    } } class FirstPanel extends Panel { String szFontName = "TimesRoman"; public void paint(Graphics g) { Dimension dimAppWndDimension = getSize();
    g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1);
    g.setFont(new Font(szFontName, Font.PLAIN, 24));
    g.drawString("First panel", 10, 50);
    super.paint(g);
    } } class CardPanel extends Panel { Panel pBgColor; Panel pFgColor; Panel pFont; Panel pControlled; Choice chBgColor; Choice chFgColor; Choice chFont; Label lbBgColor; Label lbFgColor; Label lbFont; public CardPanel(Panel pControlledPanel) { pControlled = pControlledPanel; setLayout(new CardLayout(5, 5));
    pBgColor = new Panel();
    pFgColor = new Panel();
    pFont = new Panel();
    add("BgColor", pBgColor);
    add("FgColor", pFgColor);
    add("Font", pFont);
    chBgColor = new Choice();
    chFgColor = new Choice();
    chFont = new Choice();
    chBgColor.add("Yellow");
    chBgColor.add("Green");
    chBgColor.add("White");
    chFgColor.add("Black");
    chFgColor.add("Red");
    chFgColor.add("Green");
    chFont.add("TimesRoman");
    chFont.add("Helvetica");
    chFont.add("Courier");
    lbBgColor = new Label("Background color");
    lbFgColor = new Label("Foreground color");
    lbFont = new Label("Font");
    pBgColor.add(lbBgColor);
    pBgColor.add(chBgColor);
    pFgColor.add(lbFgColor);
    pFgColor.add(chFgColor);
    pFont.add(lbFont);
    pFont.add(chFont);
    } public void paint(Graphics g) { Dimension dimAppWndDimension = getSize();
    g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1);
    super.paint(g);
    } public boolean action(Event evt, Object obj) { Choice ch; if(evt.target instanceof Choice) { ch = (Choice)evt.target; if(evt.target.equals(chBgColor)) { if(ch.getSelectedIndex() == 0) pControlled.setBackground( Color.yellow);
    else if(ch.getSelectedIndex() == 1) pControlled.setBackground( Color.green);
    else if(ch.getSelectedIndex() == 2) pControlled.setBackground( Color.white);
    } else if(evt.target.equals(chFgColor)) { if(ch.getSelectedIndex() == 0) pControlled.setForeground( Color.black);
    else if(ch.getSelectedIndex() == 1) pControlled.setForeground( Color.red);
    else if(ch.getSelectedIndex() == 2) pControlled.setForeground( Color.green);
    } else if(evt.target.equals(chFont)) { if(ch.getSelectedIndex() == 0) ((FirstPanel)pControlled).szFontName = "TimesRoman"; else if(ch.getSelectedIndex() == 1) ((FirstPanel)pControlled).szFontName = "Helvetica"; else if(ch.getSelectedIndex() == 2) ((FirstPanel)pControlled).szFontName = "Courier"; } else { return false; } pControlled.repaint();
    return true; } return false; } } class ControlPanel extends Panel { Button btNext; Button btPrev; Button btBgColor; Button btFgColor; Button btFont; Panel pCard; public ControlPanel(Panel pCardPanel) { pCard = pCardPanel; setLayout(new GridLayout(2,3));
    btBgColor = new Button("Background Color");
    btFgColor = new Button("Foreground Color");
    btFont = new Button("Set Font");
    btNext = new Button("Next");
    btPrev = new Button("Prev");
    add(btBgColor);
    add(btFgColor);
    add(btFont);
    add(btNext);
    add(btPrev);
    } public boolean action(Event evt, Object obj) { if(evt.target instanceof Button) { if(evt.target.equals(btBgColor)) { ((CardLayout)pCard.getLayout()).show( pCard, "BgColor");
    } else if(evt.target.equals(btFgColor)) { ((CardLayout)pCard.getLayout()).show( pCard, "FgColor");
    } else if(evt.target.equals(btFont)) { ((CardLayout)pCard.getLayout()).show( pCard, "Font");
    } else if(evt.target.equals(btNext)) { ((CardLayout)pCard.getLayout()).next( pCard);
    } else if(evt.target.equals(btPrev)) { ((CardLayout)pCard.getLayout()). previous(pCard);
    } else { return false; } return true; } return false; } } Исходный текст документа HTML, созданный для аплета Options системой Java WorkShop, представлен в листинге 2.
    Листинг 2. Файл Options.tmp.html



    If your browser recognized the applet tag, you would see an applet here.



    Метод action

    Метод action

    Метод action обрабатывает события, возникающие в результате выбора новых значений из списков, расположенных на страницах блокнота. Схема обработки событий не имеет никаких особенностей.
    Вначале метод action проверяет, что событие вызвано списком класса Choice:
    if(evt.target instanceof Choice) { . . . return true; } return false; } События, связанные с изменением цвета фона, обрабатываются следующим образом:
    ch = (Choice)evt.target; if(evt.target.equals(chBgColor)) { if(ch.getSelectedIndex() == 0) pControlled.setBackground( Color.yellow); else if(ch.getSelectedIndex() == 1) pControlled.setBackground( Color.green); else if(ch.getSelectedIndex() == 2) pControlled.setBackground( Color.white); } Здесь метод setBackground вызывается для объекта, ссылка на который передана конструктору класса и записана в поле pControlled. Это ссылка на панель, размещенную в верхней части окна нашего аплета.
    Аналогичным образом изменяется цвет текста и рамки для верхней панели:
    else if(evt.target.equals(chFgColor)) { if(ch.getSelectedIndex() == 0) pControlled.setForeground( Color.black); else if(ch.getSelectedIndex() == 1) pControlled.setForeground( Color.red); else if(ch.getSelectedIndex() == 2) pControlled.setForeground( Color.green); } Для изменения шрифта мы устанавливаем новое значение переменной поля szFontName, определенной в классе FirstPanel:
    else if(evt.target.equals(chFont)) { if(ch.getSelectedIndex() == 0) ((FirstPanel)pControlled).szFontName = "TimesRoman"; else if(ch.getSelectedIndex() == 1) ((FirstPanel)pControlled).szFontName = "Helvetica"; else if(ch.getSelectedIndex() == 2) ((FirstPanel)pControlled).szFontName = "Courier"; } Для того чтобы адресоваться к полю szFontName, нам пришлось выполнить явное преобразование типа ссылки pControlled.
    Последнее действие, которое совершает метод action - это перерисовка окна верхней панели, которая выполняется с помощью метода repaint:
    pControlled.repaint();

    Метод action

    Метод action управляет работой блокнота, отображая его страницы.
    Когда пользователь нажимает на кнопки, выбирающие страницы блокнота, метод action выдвигает нужную страницу на передний план с помощью метода show:
    if(evt.target.equals(btBgColor)) { ((CardLayout)pCard.getLayout()).show( pCard, "BgColor"); } else if(evt.target.equals(btFgColor)) { ((CardLayout)pCard.getLayout()).show( pCard, "FgColor"); } else if(evt.target.equals(btFont)) { ((CardLayout)pCard.getLayout()).show( pCard, "Font"); } В качестве первого параметра этому методу передается идентификатор панели блокнота, а в качестве второго - имя страницы, которую необходимо отобразить.
    Циклический перебор страниц блокнота выполняется с помощью методов next и previous, соответственно:
    else if(evt.target.equals(btNext)) { ((CardLayout)pCard.getLayout()).next( pCard); } else if(evt.target.equals(btPrev)) { ((CardLayout)pCard.getLayout()). previous(pCard); }

    Метод init

    Метод init

    Прежде всего метод init устанавливает для окна аплета режим размещения GridLayout:
    setLayout(new GridLayout(3, 1)); Окно аплета делится на три горизнтальные области, в которых мы будем размещать панели.
    Панели создаются с помощью оператора new как объекты соответствующих классов, определенных в нашем приложении:
    pPanel1 = new FirstPanel(); add(pPanel1); pCard = new CardPanel(pPanel1); add(pCard); pControl = new ControlPanel(pCard); add(pControl); Для добавления панелей в окно аплета мы использовали метод add.
    Далее метод init устанавливает начальные значения для цвета фона и текста верхней панели:
    pPanel1.setBackground(Color.yellow); pPanel1.setForeground(Color.black); Обратите внимание, что мы вызываем методы setBackground и setForeground для объекта pPanel1.
    После выполнения всех этих действий метод init перерисовывает окно аплета, вызывая метод repaint:
    repaint();

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

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

    Помимо основного класса Options в нашем аплете создается еще три класса для панелей с именами FirstPanel, CardPanel и ControlPanel.
    Класс FirstPanel соответствует самой верхней панели, в которой отображается строка текста First panel. Классы CardPanel и ControlPanel испльзуются для создания панелей со списками и управляющими кнопками, соответственно. Мы будем рассматривать эти классы по отдельности.

    Описание текста

    Описание текста


    Поля класса CardPanel

    Поля класса CardPanel

    В полях pBgColor, pFgColor и pFont хранятся ссылки на панели страниц блокнота, которые мы разместим внутри панели класса CardPanel:
    Panel pBgColor; Panel pFgColor; Panel pFont; Кроме того, в поле pControlled хранится ссылка на верхнюю панель с текстовой строкой First Panel.
    Panel pControlled; Это поле будет проинициализировано конструктором класса CardPanel.
    В следующих трех полях мы храним ссылки на списки класса Choice, предназначенные, соответственно, для выбора цвета текста, цвета фона и шрифта:
    Choice chBgColor; Choice chFgColor; Choice chFont; Три поля класса Label содержат ссылки на подписи к указанным выше спискам:
    Label lbBgColor; Label lbFgColor; Label lbFont;

    Поля класса ControlPanel

    Поля класса ControlPanel

    Следующие пять полей хранят ссылки на кнопки, управляющие страницами блокнота:
    Button btNext; Button btPrev; Button btBgColor; Button btFgColor; Button btFont; Поле pCard хранит ссылку на панель блокнота:
    Panel pCard; Эта ссылка инициализируется конструктором класса.

    Работа с панелями


    Работа с панелями

    Панели, создаваемые на базе класса Panel, являются мощным средством организации диалогового интерфейса. Так как класс Panel произошел от класса Container, панель может содержать компоненты и другие панели. Для каждой панели можно определить режим размещения компонент, что позволяет создавать достаточно сложный пользовательский интерфейс.
    В окне аплета вы можете создать несколько панелей, разделяющих его на части. В свою очередь, пространство, занимаемое панелями, также может быть разделено с использованием одного из описанных выше режимов размещения (Рисунок 1).

    Рисование в окне панели

    Рисование в окне панели

    Как вы знаете, для того чтобы что-нибудь нарисовать, необходимо вначале получить контекст отображения. Методу paint передается контекст отображения, связанный с окном аплета. Если в окне имеются панели, то для рисования внутри них необходимо получить контекст отображения окон панелей.
    Проще всего это сделать с помощью метода getGraphics, вызвав его для объекта класса Panel:
    Graphics gpDraw; gpDraw = pDraw.getGraphics(); Здесь в переменную gpDraw мы записали ссылку на контекст отображения для панели pDraw.
    Получив контекст отображения, можно приступить к рисованию. Вот, например, как можно нарисовать вокруг панели тонкую рамку:
    Dimension dimAppWndDimension = pDraw.size(); gpDraw.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); В этом фрагменте кода мы вначале определили размеры панели, вызвав для нее метод size, а затем при помощи метода drawRect, вызванного для контекста отображения gpDraw, нарисовали рамку.
    Для установки шрифта и рисования текста в окне панели вы также должны указывать ссылку на контекст отображения вашей панели:
    gpDraw.setFont(new Font("Courier", Font.PLAIN, 12)); gpDraw.drawString( "Текст внутри окна панели", 10, 50); Другой способ основан на создании собственного класса на базе класса Panel и переопределения в этом классе метода paint.

    Рисование в панели

    Рисование в панели


    Размещение нескольких панелей в окне аплета

    Рисунок 1. Размещение нескольких панелей в окне аплета

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

    Окно аплета Options

    Рисунок 2. Окно аплета Options

    Окно аплета Options
    В верхней панели отображается текстовая строка First panel. Цвет и шрифт этой строки, а также цвет фона можно задавать при помощи второй панели, расположенной в центре окна нашего аплета.
    Вторая панель представляет собой блокнот, на страницах которого находятся списки цвета фона, текста и шрифтов. С помощью кнопок нижней панели вы можете перелистывать страницы этого блокнота. На Рисунок 3 и 4 мы показали страницы, предназначенные для выбора цвета фона и цвета текста, соответственно.

    Выбор цвета фона

    Рисунок 3. Выбор цвета фона


    Выбор цвета фона



    Выбор цвета текста

    Рисунок 4. Выбор цвета текста

    Выбор цвета текста
    Нажимая кнопки Background Color, Foreground Color и Set Font, вы можете отображать нужные вам страницы блокнота. С помощью кнопок Next и Prev можно перебирать страницы блокнота в прямом или обратном направлении, соответственно.

    Создание нового класса на базе класса Panel

    Создание нового класса на базе класса Panel

    Если ваш аплет создает много панелей, техника рисования в окнах этих панелей, описанная выше, может привести к усложнению исходного текста приложения. Так как рисование в окнах панелей выполняется в методе paint класса аплета, вам придется получать контекст отображения для каждой панели.
    Намного проще создать несколько дочерних классов от класса Panel, переопределив в каждом из них метод paint. В этом случае для каждой панели вы можете создать свой метода paint, которому будет автоматически передаваться контекст отображения, связанный с окном соответствующей панели.
    В аплете Options, который мы рассмотрим ниже, использована именно такая методика работы с панелями.

    Создание панелей


    Создание панелей

    Панель создается очень просто. Прежде всего необходимо выбрать для окна аплета схему размещения компонент, соответствующую требуему расположению панелей. Например, для создания в окне аплета двух панелей, разделяющих его по горизонтали, следует выбрать режим GridLayout:
    setLayout(new GridLayout(2, 1)); Панели будут размещаться в ячейках таблицы, состоящей из одного столбца и двух строк.
    Далее нужно создать объекты класса Panel:
    Panel pTopPanel; pTopPanel = new Panel(); Panel pBottomPanel; pBottomPanel = new Panel(); Ссылка на панель, которая будет располагаться сверху, записывается в переменную pTopPanel, а на ту, что будет располагаться снизу - в переменную pBottomPanel.

    Подробное руководство по программированию на Java

    Диалоговые панели

    Диалоговые панели


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

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

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

    Использование класса Dialog

    Использование класса Dialog

    Для того чтобы создать свою диалоговую панель, вы должны определить новый класс, унаследовав его от класса Dialog, как это показано ниже:
    class MessageBox extends Dialog { . . . public MessageBox(String sMsg, Frame parent, String sTitle, boolean modal) { super(parent, sTitle, modal); . . . resize(200, 100); . . . } } В этом классе нужно определить конструктор, который вызывает конструктор базового метода класса Dialog и определяет размеры окна диалоговой панели. Кроме того, в конструкторе вы должны создать все необходимые компоненты для размещения внутри диалоговой панели (кнопки, списки, текстовые поля, переключатели и так далее), а также выполнить размещение этих компонент, установив нужный режим размещения.
    Для окон класса Dialog устанавливается режим размещения BorderLayout. Если нужен другой режим размещения, необходимо установить его явным образом методом setLayout.
    Для отображения окна диалоговой панели необходимо вызвать метод show. Чтобы спрятать диалоговой окно, применяйте метод hide. Метод dispose удаляет окно диалоговой панели окончательно и освобождает все связанные с ним ресурсы.
    Когда пользователь пытается уничтожить окно диалоговой панели при помощи органов управления, расположенных в заголовке такого окна, возникает событие Event.WINDOW_DESTROY. Вы должны обработать его, обеспечив удаление окна диалоговой панели вызовом метода dispose, если, конечно, это соответствует логике работы вашей панели.

    Класс MainFrameWnd

    Класс MainFrameWnd

    Класс MainFrameWnd создан на базе класса Frame:
    class MainFrameWnd extends Frame { . . . } В нем мы определили три поля, конструктор, методы paint, handleEvent и action.

    Класс Menu


    Класс Menu

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

    Класс MenuApp

    Класс MenuApp

    В главном классе приложения MenuApp мы определили только один метод main. Этот метод получает управление при запуске приложения.
    Первым делом метод main создает объект класса MainFrameWnd, определенного в нашем приложении:
    MainFrameWnd frame = new MainFrameWnd("MenuApp"); Этот класс, созданный на базе класса Frame, определяет поведение главного окна нашего приложения.
    На втором шаге метод init настраивает размеры главного окна с учетом размеров внешней рамки и заголовка окна:
    frame.setSize(frame.getInsets().left + frame.getInsets().right + 320, frame.getInsets().top + frame.getInsets().bottom + 240); Поля left и right объекта класса Insets, ссылку на который возвращает метод getInsets, содержат ширину левой и правой части рамки окна, соответственно. Поле top содержит высоту верхней части рамки окна с учетом заголовка, а поле bottom - высоту нижней части рамки окна.
    Для отображения окна фрейма мы вызываем метод show, как это показано ниже:
    frame.show();

    Класс MenuItem


    Класс MenuItem

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

    Класс MessageBox

    Класс MessageBox

    Для отображения названий выбранных строк меню мы создаем диалоговую панель, определив свой класс MessageBox на базе класса Dialog, как это показано ниже:
    class MessageBox extends Dialog { . . . } В классе MessageBox есть два поля, конструктор, методы handleEvent и action.

    Конструктор класса MainFrameWnd

    Конструктор класса MainFrameWnd

    В качестве единственного параметра конструктору класса MainFrameWnd передается заголовок создаваемого окна. В первой исполняемой строке наш конструктор вызывает конструктор из базового класса, передавая ему строку заголовка через параметр:
    public MainFrameWnd(String sTitle) { super(sTitle); . . . } Далее конструктор определяет размеры окна, вызывая для него метод setSize:
    setSize(400, 200); Затем мы устанавливаем для нашего окна желтый цвет фона и черный цвет изображения:
    setBackground(Color.yellow); setForeground(Color.black); По умолчанию для окон класса Frame устанавливается режим добавления компонент BorderLayout. Мы изменяем этот режим на FlowLayout, вызывая метод setLayout:
    setLayout(new FlowLayout()); Далее конструктор приступает к формированию главного меню окна. Это меню создается как объект класса MenuBar:
    mbMainMenuBar = new MenuBar(); Затем мы создаем и наполняем меню "File":
    mnFile = new Menu("File"); mnFile.add("New"); mnFile.add("-"); mnFile.add("Exit"); Это меню создается на базе класса Menu. Обратите внимание, что между строками New и File расположен разделитель.
    Аналогичным образом мы добавляем в главное меню другое меню - "Help":
    mnHelp = new Menu("Help"); mnHelp.add("Content"); mnHelp.add("-"); mnHelp.add("About"); После своего окончательного формирования меню "File" и "Help" добавляются в главное меню окна mbMainMenuBar:
    mbMainMenuBar.add(mnFile); mbMainMenuBar.add(mnHelp); И, наконец, когда главное меню будет сформировано, оно подключается к окну вызовом метода setMenuBar, как это показано ниже:
    setMenuBar(mbMainMenuBar);

    Конструктор класса MessageBox

    Конструктор класса MessageBox

    Наш конструктор создает диалоговую панель с заданным сообщением внутри нее. Ссылка на строку сообщения передается конструктору через первый параметр. Остальные параметры используются конструктором базового класса Dialog для создания диалоговой панели:
    super(parent, sTitle, modal); После вызова конструктора из базового класса наш конструктор устанавливает размеры окна созданной диалоговой панели, вызывая метод resize:
    resize(200, 100); Отменяя установленный по умолчанию режим размещения компонент BorderLayout, конструктор устанавливает режим GridLayout:
    setLayout(new GridLayout(2, 1)); Окно диалоговой панели при этом разделяется на две части по горизонтали. В верхнюю часть добавляется текстовое поле для отображения сообщения, в нижнюю - кнопка OK:
    lbMsg = new Label(sMsg, Label.CENTER); add(lbMsg); btnOK = new Button("OK"); add(btnOK);

    Конструкторы

    Конструкторы

    Для класса Frame определено два конструктора:
    Создание окна без заголовка
    public Frame(); Создание окна с заголовоком
    public Frame(String title);

    Конструкторы

    Конструкторы

    Создание меню с заданным названием public Menu(String label); Создание меню с заданным названием,которое может оставаться на экране после того как пользователь отпустил клавишу мыши
    public Menu(String label, boolean tearOff);

    Конструкторы

    Конструкторы

    Создание диалоговой панели без заголовка
    public Dialog(Frame parent, boolean modal); Создание диалоговой панели с заголовком
    public Dialog(Frame parent, String title, boolean modal);

    MenuBar mbMainMenuBar; Menu mnFile; Menu

    Листинг 1

    . Файл MenuApp.java import java.awt.*; public class MenuApp { public static void main(String args[]) { MainFrameWnd frame = new MainFrameWnd("MenuApp");
    frame.setSize( frame.getInsets().left + frame.getInsets().right + 320, frame.getInsets().top + frame.getInsets().bottom + 240);
    frame.show();
    } } class MainFrameWnd extends Frame { MenuBar mbMainMenuBar; Menu mnFile; Menu mnHelp; public MainFrameWnd(String sTitle) { super(sTitle);
    setSize(400, 200);
    setBackground(Color.yellow);
    setForeground(Color.black);
    setLayout(new FlowLayout());
    mbMainMenuBar = new MenuBar();
    mnFile = new Menu("File");
    mnFile.add("New");
    mnFile.add("-");
    mnFile.add("Exit");
    mnHelp = new Menu("Help");
    mnHelp.add("Content");
    mnHelp.add("-");
    mnHelp.add("About");
    mbMainMenuBar.add(mnFile);
    mbMainMenuBar.add(mnHelp);
    setMenuBar(mbMainMenuBar);
    } public void paint(Graphics g) { g.setFont(new Font( "Helvetica", Font.PLAIN, 12));
    g.drawString("Frame window", 10, 70);
    super.paint(g);
    } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { setVisible(false);
    System.exit(0);
    return true; } else return super.handleEvent(evt);
    } public boolean action(Event evt, Object obj) { MenuItem mnItem; if(evt.target instanceof MenuItem) { mnItem = (MenuItem)evt.target; if(obj.equals("Exit")) { System.exit(0);
    } else if(obj.equals("New")) { MessageBox mbox; mbox = new MessageBox( "Item New selected", this, "Dialog from Frame", true);
    mbox.show();
    } else if(obj.equals("Content")) { MessageBox mbox; mbox = new MessageBox( "Item Content selected", this, "Dialog from Frame", true);
    mbox.show();
    } else if(obj.equals("About")) { MessageBox mbox; mbox = new MessageBox( "Item About selected", this, "Dialog from Frame", true);
    mbox.show();
    } else return false; return true; } return false; } } class MessageBox extends Dialog { Label lbMsg; Button btnOK; public MessageBox(String sMsg, Frame parent, String sTitle, boolean modal) { super(parent, sTitle, modal);
    resize(200, 100);
    setLayout(new GridLayout(2, 1));
    lbMsg = new Label(sMsg, Label.CENTER);
    add(lbMsg);
    btnOK = new Button("OK");
    add(btnOK);
    } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { dispose();
    return true; } else return super.handleEvent(evt);
    } public boolean action(Event evt, Object obj) { Button btn; if(evt.target instanceof Button) { btn = (Button)evt.target; if(evt.target.equals(btnOK)) { dispose();
    } else return false; return true; } return false; } }

    Меню MenuBar

    Меню MenuBar


    Меню в окне класса Frame

    Меню в окне класса Frame

    Как мы уже говорили, окно класса Frame может иметь главное меню (Menu Bar) или, как еще говорят, строку меню. Главное меню создается на базе класса MenuBar, краткое описание которого приведено ниже.

    Метод action класса MessageBox

    Метод action класса MessageBox

    Если пользователь нажимает кнопку OK, расположенную в окне диалоговой панели, метод action вызывает для панели метод dispose, удаляя эту панель с экрана и из памяти:
    if(evt.target.equals(btnOK)) { dispose(); }

    Метод action

    Метод action

    Этот метод обрабатывает события, возникающие при выборе строка из меню.
    В начале своей работы метод action проверяет, действительно ли событие вызвано меню:
    MenuItem mnItem; if(evt.target instanceof MenuItem) { . . . } return false; Если это так, в поле mnItem сохраняется ссылка на элемент меню, вызвавший событие:
    mnItem = (MenuItem)evt.target; Тем не менее, для определения строки, выбранной пользователем, нам достаточно проанализировать второй параметр метода action:
    if(obj.equals("Exit")) { System.exit(0); } else if(obj.equals("New")) { MessageBox mbox; mbox = new MessageBox( "Item New selected", this, "Dialog from Frame", true); mbox.show(); } else if(obj.equals("Content")) { . . . } else if(obj.equals("About")) { . . . } В данном случае второй параметр метода action будет представлять собой ссылку на строку, выбранную из меню, поэтому для определения выбранной строки мы можем выполнить простое сравнение методом equals.
    Если пользователь выбрал из меню File строку Exit, мы вызываем метод System.exit, предназначенный для завершения работы виртуальной машины Java.
    В том случае когда пользователь выбирает любую другую строку из меню, метод action создает диалоговую панель на базе определенного нами класса MessageBox. В этой диалоговой панели отображаетя название выбранной строки меню.
    Заметим, что сразу после создания конструктором диалоговая панель не появляется на экране. Мы отображаем ее, вызывая метод show.

    Метод handleEvent класса MessageBox

    Метод handleEvent класса MessageBox

    Когда пользователь пытается закрыть окно диалоговой панели, например, сделав двойной щелчок левой клавишей мыши по системному меню или одиночный щелчок по кнопке удаления окна, возникает событие Event.WINDOW_DESTROY. Мы его обрабатываем следующим образом:
    if(evt.id == Event.WINDOW_DESTROY) { dispose(); return true; } else return super.handleEvent(evt); Вызывая метод dispose, мы удаляем окно диалоговой панели и освобождаем все связанные с ним ресурсы.

    Метод handleEvent

    Метод handleEvent

    Для того чтобы определить реакцию окна на попытку пользователя закрыть окно с помощью органов управления, расположенных в заголовке окна, или другим способом, мы переопределили метод handleEvent.
    При получении кода события Event.WINDOW_DESTROY (удаление окна) мы скрываем окно, вызывая метод setVisible с параметром false.
    Затем с помощью статического метода exit класса System мы завершаем работу интерпретатора:
    public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { setVisible(false); System.exit(0); return true; } else return super.handleEvent(evt); }

    Метод paint

    Метод paint

    Метод paint получает в качестве параметра ссылку на контекст отображения, пригодный для рисования в нашем окне. Пользуясь этим контекстом, мы устанавливаем шрифт текста и рисуем текстовую строку. Затем мы вызываем метод paint из базового класса Frame, на основе которого создан наш класс MainFrameWnd:
    public void paint(Graphics g) { g.setFont(new Font( "Helvetica", Font.PLAIN, 12)); g.drawString("Frame window", 10, 70); super.paint(g); }

    Методы

    Методы

  • addNotify
  • Вызов метода createFrame
    public void addNotify(); dispose
    Удаление окна и освобождение связанных с ним ресурсов
    public void dispose(); getCursorType
    Определение типа курсора
    public int getCursorType();
  • getIconImage
  • Получение пиктограммы, установленной для окна
    public Image getIconImage();
  • getMenuBar
  • Получение ссылки на главное меню
    public MenuBar getMenuBar();
  • getTitle
  • Получение заголовка окна
    public String getTitle();
  • isResizable
  • Определение возможности изменения размеров окна пользователем
    public boolean isResizable();
  • paramString
  • Получение строки параметров
    protected String paramString();
  • remove
  • Удаление компоненты меню
    public void remove(MenuComponent m);
  • setCursor
  • Установка типа курсора
    public void setCursor(int cursorType);
  • setIconImage
  • Установка пиктограммы
    public void setIconImage(Image image);
  • setMenuBar
  • Установка главного меню
    public void setMenuBar(MenuBar mb);
  • setResizable
  • Включение или выключение возомжности изменения размеров окна
    public void setResizable(boolean resizable);
  • setTitle
  • Установка заголовка окна
    public void setTitle(String title);

    Методы

    Методы

  • add
  • Добавление меню в главное меню окна
    public Menu add(Menu m);
  • addNotify
  • Вызов метода createMenuBar
    public void addNotify();
  • countMenus
  • Определение количества меню, добавленных в главное меню
    public int countMenus();
  • getHelpMenu
  • Получение ссылки на меню Help
    public Menu getHelpMenu();
  • getMenu
  • Получение ссылки на меню с заданным номером
    public Menu getMenu(int i);
  • remove
  • Удаление меню с заданным номером из главного меню
    public void remove(int index); Удаление компоненты меню
    public void remove(MenuComponent m);
  • removeNotify
  • Извещение об удалении меню
    public void removeNotify();
  • setHelpMenu
  • Установка меню Help
    public void setHelpMenu(Menu m);

    Методы

    Методы

  • add
  • Добавление элемента меню
    public MenuItem add(MenuItem mi); Добавление строки в меню
    public void add(String label);
  • addNotify
  • Вызов метода createMenu
    public void addNotify();
  • addSeparator
  • Добавление разделителя в меню
    public void addSeparator();
  • countItems
  • Определение количества строк в меню
    public int countItems();
  • getItem
  • Получение ссылки на элемент меню с заданным номером
    public MenuItem getItem(int index);
  • isTearOff
  • Проверка, остается ли меню на экране после того как пользователь отпустил клавишу мыши
    public boolean isTearOff();
  • remove
  • Удаление заданного элемента меню
    public void remove(int index); Удаление заданной компоненты меню
    public void remove(MenuComponent item);
  • removeNotify
  • Извещение об удалении меню
    public void removeNotify();

    Методы

    Методы

  • addNotify
  • Вызов метода createMenuItem
    public void addNotify();
  • disable
  • Блокирование элемента меню
    public void disable();
  • enable
  • Разблокирование элемента меню
    public void enable(); Блокирование или разблокирование элемента меню
    public void enable(boolean cond);
  • getLabel
  • Получение текстовой строки меню
    public String getLabel();
  • isEnabled
  • Проверка, является ли элемент меню заблокированным
    public boolean isEnabled();
  • paramString
  • Получение строки параметров
    public String paramString();
  • setLabel
  • Установка текстовой строки для элемента меню
    public void setLabel(String label);

    Методы

    Методы

  • addNotify
  • Вызов метода createDialog
    public void addNotify();
  • getTitle
  • Получение строки заголовка диалоговой панели
    public String getTitle();
  • isModal
  • Определение, является ли диалоговая панель модальной
    public boolean isModal();
  • isResizable
  • Определение возможности изменения размеров окна диалоговой панели
    public boolean isResizable();
  • paramString
  • Получение строки параметров
    protected String paramString(); setResizable
    Включение или выключение возможности изменения размеров окна диалоговой панели
    public void setResizable(boolean resizable);
  • setTitle
  • Установка заголовка диалоговой панели
    public void setTitle(String title);

    Окна и диалоговые панели


    Окна и диалоговые панели

    До сих пор мы рисовали только в окне аплета или в окнах панелей, расположенных внутри окна аплета. Однако есть и другая возможность - приложения Java, полноценные и аплеты, могут создавать обычные перекрывающиеся окна, такие, например, как окно браузера. Эти окна могут иметь меню (в отличие от окон аплетов). Пользователь может изменять размер таких окон при помощи мыши, перемещая рамку окна.
    В составе библиотеки классов AWT имеется несколько классов, предназначенных для работы с окнами. Это класс Window, который произошел от класса Container, и его дочерние классы - Frame, Dialog и FileDialog (Рисунок 1).

    Окна класса Frame


    Окна класса Frame

    Ниже мы привели краткое описание класса Frame. Так как этот класс реализует интерфейс java.awt.MenuContainer, окно класса Frame может содержать меню.

    Описание исходного текста приложения MenuApp

    Описание исходного текста приложения MenuApp

    Как мы уже говорили, приложение MenuApp работает автономно. Поэтому мы импортируем только класс java.awt.*, необходимый для работы с окнами:
    import java.awt.*; В нашем приложении определено три класса - MenuApp, MainFrameWnd и MessageBox.

    Поля класса MainFrameWnd

    Поля класса MainFrameWnd

    Поле mbMainMenuBar предназанчено для хранения ссылки на главное меню приложения, создаваемое как объект класса MenuBar:
    MenuBar mbMainMenuBar; Поля mnFile и mnHelp хранят ссылки на меню File и Help, соответственно:
    Menu mnFile; Menu mnHelp; Данные меню создаются на базе класса Menu.

    Поля класса MessageBox

    Поля класса MessageBox

    Внутри диалоговой панели мы расположили текстовое поле класса Label, предназначенное для отображения сообщения, и кнопку с надписью OK, с помощью которой можно завершить работу диалоговой панели.
    Ссылка на текстовое поле хранится в поле lbMsg, на кнопку - в поле btnOK.

    Поля

    Поля

    С помощью полей класса Frame вы можете задавать для своего окна различные типы курсоров:
    public final static int CROSSHAIR_CURSOR; public final static int DEFAULT_CURSOR; public final static int E_RESIZE_CURSOR; public final static int HAND_CURSOR; public final static int MOVE_CURSOR; public final static int N_RESIZE_CURSOR; public final static int NE_RESIZE_CURSOR; public final static int NW_RESIZE_CURSOR; public final static int S_RESIZE_CURSOR; public final static int SE_RESIZE_CURSOR; public final static int SW_RESIZE_CURSOR; public final static int TEXT_CURSOR; public final static int W_RESIZE_CURSOR; public final static int WAIT_CURSOR;

    Приложение MenuApp


    Приложение MenuApp

    Автономное приложение MenuApp, работающее под управлением интерпертатора Java, демонстрирует способы создания меню. В его окне (Рисунок 1) имеется панель с меню File и Help.

    Применение класса Frame

    Применение класса Frame

    Для того чтобы создать свое окно на базе класса Frame, вы должны определить свой класс, унаследовав его от класса Frame следующим образом:
    class MainFrameWnd extends Frame { . . . public MainFrameWnd(String sTitle) { super(sTitle); . . . resize(400, 200); } . . . } Если мы будем создавать окно с заголовком, нам необходимо соответствующим образом определить конструктор класса этого окна. В частности, наш конструктор должен вызывать конструктор базового класса, передавая ему в качестве параметра строку заголовка окна. Напомним, что конструктор базового класса должен вызываться в конструкторе дочернего класса перед выполнением каких-либо других действий.
    Обратите также внимание на вызов метода resize. Этот вызов необходим для задания размеров окна.
    В конструкторе вы можете определить различные параметры создаваемого вами окна, например, указать форму курсора, пиктограмму, представляющую окно, задать меню, определить возможность изменения размеров окна и так далее. Мы остановимся подробнее на процедуре добавления меню к окну класса Frame, так как она требует пояснений. С изменением других характеристик окна вы справитесь самостоятельно.
    При создании окна классов Frame и Dialog для них устанавливается режим размещения BorderLayout. Если вам нужен другой режим размещения, необходимо установить его явным образом.
    Кроме того, созданное окно появится на экране только после вызова для него метода show.
    Убрать окно с экрана вы можете методом hide. Этот метод прячет окно, но оставляет в памяти все связанные с ним ресурсы, поэтому вы сможете вновь отобразить спрятанное окно, вызвав метод show.
    В отличие от метода hide, метод dispose удаляет окно и освобождает все связанные с ним ресурсы. Этот метод применяется для окончательного удаления окна с экрана и из памяти.
    Еще одно замечание касается обработки операции уничтожения окна при помощи двойного щелчка левой клавиши мыши по системному меню окна или при помощи кнопки уничтожения окна, расположенной в правой части заголовка.
    Когда пользователь пытается уничтожить окно класса Frame или Dialog подобным образом, возникает событие Event.WINDOW_DESTROY. Вы должны предусмотреть обработку этого события, выполняя действия, соответствующие логике работы вашего окна. Обычно окно уничтожается вызовом метода dispose, как это показано ниже:
    public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { dispose(); return true; } else return super.handleEvent(evt); }

    Работа с классом Menu

    Работа с классом Menu

    Метод addSeparator используется для добавления в меню разделительной строки. Аналогичный результат достигается и при добавлении в меню стоки "-":
    mnHelp.add("-"); Заметим, что вы можете просто добавлять в меню строки по их названию, пользуясь методом add(String label), либо добавлять в меню элементы класса MenuItem, вызывая метод add(MenuItem mi).

    Работа с классом MenuBar

    Работа с классом MenuBar

    Для формирования главного меню окна вы должны создать объект класса MenuBar с помощью конструктора, а затем добавить в него отдельные меню.
    Объект главного меню создается следующим образом:
    MenuBar mbMainMenuBar; mbMainMenuBar = new MenuBar(); Отдельные меню создаются на базе класса Menu, например:
    Menu mnFile; Menu mnHelp; mnFile = new Menu("File"); mnHelp = new Menu("Help"); Создав меню, вы должны добавить в них строки. Для этого нужно вызвать метод add, передав ему в качестве параметра текст строки меню, например:
    mnFile.add("New"); mnFile.add("-"); mnFile.add("Exit"); mnHelp.add("Content"); mnHelp.add("-"); mnHelp.add("About"); Далее сформированные меню добавляются в главное меню:
    mbMainMenuBar.add(mnFile); mbMainMenuBar.add(mnHelp); И, наконец, теперь можно устанавливать главное меню в окне класса, созданного на базе класса Frame:
    setMenuBar(mbMainMenuBar);

    Главное окно автономного приложения MenuApp

    Рисунок 1. Главное окно автономного приложения MenuApp

    Главное окно автономного приложения MenuApp
    В меню File мы добавили строки New и Exit, а также разделитель в виде горизонтальной линии (Рисунок 2).

    Иерархия классов предназначенных для создания окон

    Рисунок 1. Иерархия классов, предназначенных для создания окон

    Иерархия классов предназначенных для создания окон
    Окно, созданное на базе класса Frame, больше всего похоже на главное окно обычного приложения Windows. Оно может иметь главное меню, для него можно устанавливать форму курсора. Внутри такого окна можно рисовать. Так как окно класса Frame (так же как и другие окна AWT) произошли от класса Container, вы можете добавлять в них различные компоненты и панели, как мы это делали с окнами аплетов и панелей.
    На базе класса Dialog создаются окна диалоговых панелей, очень похожих на обычные диалоговые панели Windows. Такие панели не могут иметь меню и обычно предназначены для запроса какой-либо информации у пользователя.
    Класс FileDialog предназначен для создания диалоговых панелей диалоговые панели, с помощью которых можно выбирать файлы на локальных дисках компьютера.
    Что же касается класса Window, то непосредственно этот класс редко применяется для создания окон, так как классы Frame, Dialog и FileDialog более удобны и обеспечивают все необходимые возможности.

    Меню File

    Рисунок 2. Меню File

    Меню File
    Меню Help (Рисунок 3) содержит строки Content и About. Между ними также имеется разделительная линия.

    Меню Help

    Рисунок 3. Меню Help

    Меню Help
    Если выбрать любую строку, кроме строки Exit из меню File, на экране появится диалоговая панель с названием выбранной строки и кнопкой OK (Рисунок 4).

    Диалоговая панель которая

    Рисунок 4. Диалоговая панель, которая появляется при выборе строки New из меню File

    Диалоговая панель которая
    Выбор строки Exit из меню File приводит к завершению работы приложения MenuApp.

    Создание диалоговых панелей

    Создание диалоговых панелей

    Диалоговые панели создаются на базе класса Dialog, краткое описание которого приведено ниже.

    Подробное руководство по программированию на Java

    Аплет Rectangles


    Аплет Rectangles

    В качестве примера многопоточного приложения мы приведем аплет Rectangles (Рисунок 1). Он создает три потока. Первый поток рисует в окне аплета прямоугольники случайного размера и цвета, второй - эллипсы, а третий управляет потоком рисования эллипсов.

    Блокировка на заданный период времени

    Блокировка на заданный период времени

    С помощью метода sleep можно заблокировать поток на заданный период времени:
    try { Thread.sleep(500); } catch (InterruptedException ee) { . . . } В данном примере работа потока Thread приостанавливается на 500 миллисекунд. Заметим, что во время ожидания приостановленный поток не отнимает ресурсы процессора.
    Так как метод sleep может создавать исключение InterruptedException, необходимо предусмотреть его обработку. Для этого мы использовали операторы try и catch.

    Блокировка потока

    Блокировка потока

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

    Исходные тексты аплета Rectangles

    Исходные тексты аплета Rectangles

    Исходные тексты аплета Rectangles приведены в листинге 1.

    Конструктор класса DrawRectangles

    Конструктор класса DrawRectangles

    В качестве параметра конструктору передается ссылка на класс аплета. Конструктор использует эту ссылку для получения и сохранения в полях класса контекста отображения и размеров окна аплета:
    public DrawRectangles(Applet Appl) { g = Appl.getGraphics(); dimAppWndDimension = Appl.getSize(); }

    Конструктор класса NotifyTask

    Конструктор класса NotifyTask

    Конструктор класса NotifyTask записывает в поле STask ссылку на задачу рисования эллипсов:
    public NotifyTask(Thread SynchroTask) { STask = SynchroTask; }

    Конструкторы

    Конструкторы

    Создание нового объекта Thread
    public Thread(); Создвание нового объекта Thread с указанием объекта, для которого будет вызываться метод run
    public Thread(Runnable target); Аналогично предыдущему, но дополнительно задается имя нового объекта Thread
    public Thread(Runnable target, String name); Создание объекта Thread с указанием его имени
    public Thread(String name); Создание нового объекта Thread с указанием группы потока и объекта, для которого вызывается метод run
    public Thread(ThreadGroup group, Runnable target); Аналогично предыдущему, но дополнительно задается имя нового объекта Thread
    public Thread(ThreadGroup group, Runnable target, String name); Создание нового объекта Thread с указанием группы потока и имени объекта
    public Thread(ThreadGroup group, String name);

    public class Rectangles extends Applet

    Листинг 1

    . Файл Rectangles,java import java.applet.*; import java.awt.*; public class Rectangles extends Applet { DrawRectangles m_DrawRectThread = null; DrawEllipse m_DrawEllipseThread = null; NotifyTask m_NotifyTaskThread = null public String getAppletInfo() { return "Name: Rectangles"; } public void paint(Graphics g) { Dimension dimAppWndDimension = getSize();
    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);
    } public void start() { if (m_DrawRectThread == null) { m_DrawRectThread = new DrawRectangles(this);
    m_DrawRectThread.start();
    } if (m_DrawEllipseThread == null) { m_DrawEllipseThread = new DrawEllipse(this);
    m_DrawEllipseThread.start();
    } if (m_NotifyTaskThread == null) { m_NotifyTaskThread = new NotifyTask(m_DrawEllipseThread);
    m_NotifyTaskThread.start();
    } } public void stop() { if (m_DrawRectThread != null) { m_DrawRectThread.stop();
    m_DrawRectThread = null; } if (m_DrawEllipseThread == null) { m_DrawEllipseThread.stop();
    m_DrawEllipseThread = null; } if (m_NotifyTaskThread != null) { m_NotifyTaskThread.stop();
    m_NotifyTaskThread = null; } } } class DrawRectangles extends Thread { Graphics g; Dimension dimAppWndDimension; public DrawRectangles(Applet Appl) { g = Appl.getGraphics();
    dimAppWndDimension = Appl.getSize();
    } public void run() { while (true) { int x, y, width, height; int rColor, gColor, bColor; x = (int)(dimAppWndDimension.width * Math.random());
    y = (int)(dimAppWndDimension.height * Math.random());
    width = (int)(dimAppWndDimension.width * Math.random()) / 2; height = (int)(dimAppWndDimension.height * Math.random()) / 2; rColor = (int)(255 * Math.random());
    gColor = (int)(255 * Math.random());
    bColor = (int)(255 * Math.random());
    g.setColor(new Color(rColor, gColor, bColor));
    g.fillRect(x, y, width, height);
    try { Thread.sleep(50);
    } catch (InterruptedException e) { stop();
    } } } } class DrawEllipse extends Thread { Graphics g; Dimension dimAppWndDimension; public DrawEllipse(Applet Appl) { g = Appl.getGraphics();
    dimAppWndDimension = Appl.getSize();
    } public synchronized void run() { while (true) { int x, y, width, height; int rColor, gColor, bColor; x = (int)(dimAppWndDimension.width * Math.random());
    y = (int)(dimAppWndDimension.height * Math.random());
    width = (int)(dimAppWndDimension.width * Math.random()) / 2; height = (int)(dimAppWndDimension.height * Math.random()) / 2; rColor = (int)(255 * Math.random());
    gColor = (int)(255 * Math.random());
    bColor = (int)(255 * Math.random());
    g.setColor(new Color(rColor, gColor, bColor));
    g.fillOval(x, y, width, height);
    try { this.wait();
    } catch (InterruptedException e) { } } } } class NotifyTask extends Thread { Thread STask; public NotifyTask(Thread SynchroTask) { STask = SynchroTask; } public void run() { while (true) { try { Thread.sleep(30);
    } catch (InterruptedException e) { } synchronized(STask) { STask.notify();
    } } } }

    Метод run класса DrawEllipse

    Метод run класса DrawEllipse

    Класс DrawEllipse очень похож на только что рассмотренный класс DrawRectangles. Отличие есть только в финальном фрагменте метода run, который мы и рассмотрим.
    Вместо задержки на 50 миллисекунд метод run из класса DrawEllipse переходит в состояние ожидания извещения, вызывая метод wait:
    try { this.wait(); } catch (InterruptedException e) { } Это извещение создается управляющим потоком класса NotifyTask, к описанию которого мы переходим.

    Метод run класса DrawRectangles

    Метод run класса DrawRectangles

    Программный код метода run работает в рамках отдельного потока. Он рисует в окне аплета закрашенные прямоугольники. Прямоугольники имеют случайные координаты, расположение и цвет.
    Для того чтобы рисовать, необходимо получить контекст отображения. Этот контекст был получен конструктором класса DrawRectangles и может быть использован методом run.
    Вооружившись контекстом отображения и размерами окна аплета, поток входит в бесконечный цикл рисования прямоугольников.
    В качестве генератора случайных чисел мы используем метод random из класса Math, который при каждом вызове возвращает новое случайное число типа double, лежащее в диапазоне значений от 0.0 до 1.0.
    Координаты по осям X и Y рисуемого прямоугольника определяются простым умножением случайного числа, полученного от метода random, соответственно, на ширину и высоту окна аплета:
    x = (int)(dimAppWndDimension.width * Math.random()); y = (int)(dimAppWndDimension.height * Math.random()); Аналогично определяются размеры прямоугольника, однако чтобы прямоугольники не были слишком крупными, мы делим полученные значения на 2:
    width = (int)(dimAppWndDimension.width * Math.random()) / 2; height = (int)(dimAppWndDimension.height * Math.random()) / 2; Так как случайное число имеет тип double, в обоих случаях мы выполняем явное преобразование результата вычислений к типу int.
    Для случайного выбора цвета прямоугольника мы вычисляем отдельные цветовые компоненты, умножая значение, полученное от метода random, на число 255:
    rColor = (int)(255 * Math.random()); gColor = (int)(255 * Math.random()); bColor = (int)(255 * Math.random()); Полученные значения цветовых компонент используются в конструкторе Color для получения цвета. Этот цвет устанавливается в контексте отображения методом setColor:
    g.setColor(new Color(rColor, gColor, bColor)); Теперь все готово для рисования прямоугольника, которое мы выполняем при помощи метода fillRect:
    g.fillRect(x, y, width, height); После рисования прямоугольника метод run задерживает свою работу на 50 миллисекунд, вызывая метод sleep:
    try { Thread.sleep(50); } catch (InterruptedException e) { stop(); } Для обработки исключения InterruptedException, которое может возникнуть во время работы этого метода, мы предусмотрели блок try - catch. При возникновении указанного исключения работа потока останавливается вызовом метода stop.

    Метод run класса NotifyTask

    Метод run класса NotifyTask

    Метод run класса NotifyTask периодически разблокирует поток рисования эллипсов, вызывая для этого метод notify в цилке с задержкой 30 миллисекунд. Обращение к объекту STask, который хранит ссылку на поток рисования эллипсов, выполняется с использованием синхронизации:
    public void run() { while (true) { try { Thread.sleep(30); } catch (InterruptedException e) { } synchronized(STask) { STask.notify(); } } }

    Метод start класса Rectangles

    Метод start класса Rectangles

    Этот метод последовательно создает три потока и запускает их на выполнение:
    if(m_DrawRectThread == null) { m_DrawRectThread = new DrawRectangles(this); m_DrawRectThread.start(); } if(m_DrawEllipseThread == null) { m_DrawEllipseThread = new DrawEllipse(this); m_DrawEllipseThread.start(); } if(m_NotifyTaskThread == null) { m_NotifyTaskThread = new NotifyTask(m_DrawEllipseThread); m_NotifyTaskThread.start(); } В качестве параметра конструкторам классов DrawRectangles и DrawEllipse мы передаем ссылку на аплет Rectangles. Эта ссылка будет нужна для получения контекста отображения и рисования геометрических фигур.
    Поток класса NotifyTask будет управлять работой потока DrawEllipse, поэтому мы передаем его конструктору ссылку на соответствующий объект m_DrawEllipseThread.

    Метод stop класса Rectangles

    Метод stop класса Rectangles

    Когда пользователь покидает страницу сервера Web с аплетом, метод stop класса Rectangles последовательно останавливает gjnjrb рисования прямоугольников и эллипсов, а также управляющий поток:
    if(m_DrawRectThread != null) { m_DrawRectThread.stop(); m_DrawRectThread = null; } if(m_DrawEllipseThread == null) { m_DrawEllipseThread.stop(); m_DrawEllipseThread = null; } if(m_NotifyTaskThread != null) { m_NotifyTaskThread.stop(); m_NotifyTaskThread = null; }

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

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

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

    Методы

    Методы

  • activeCount
  • Текущее количество активных потоков в группе, к которой принадлежит поток
    public static int activeCount();
  • checkAccess
  • Текущему потоку разрешается изменять объект Thread
    public void checkAccesss();
  • countStackFrames
  • Определение количества фреймов в стеке
    public int countStackFrames();
  • currentThread
  • Определение текущего работающего потока
    public static Thread currentThread();
  • destroy
  • Принудительное завершение работы потока
    public void destroy();
  • dumpStack
  • Вывод текущего содержимого стека для отладки
    public static void dumpStack();
  • enumerate
  • Получение всех объектов Tread данной группы
    public static int enumerate(Thread tarray[]);
  • getName
  • Определение имени потока
    public final String getName();
  • getPriority
  • Определение текущего приоритета потока
    public final int getPriority();
  • getThreadGroup
  • Определение группы, к которой принадлежит поток
    public final ThreadGroup getThreadGroup();
  • interrupt
  • Прерывание потока
    public void interrupt();
  • interrupted
  • Определение, является ли поток прерванным
    public static boolean interrupted();
  • isAlive
  • Определение, выполняется поток или нет
    public final boolean isAlive();
  • isDaemon
  • Определение, является ли поток демоном
    public final boolean isDaemon();
  • isInterrupted
  • Определение, является ли поток прерванным
    public boolean isInterrupted();
  • join
  • Ожидание завершения потока
    public final void join(); Ожидание завершения потока в течение заданного времени. Время задается в миллисекундах
    public final void join(long millis); Ожидание завершения потока в течение заданного времени. Время задается в миллисекундах и наносекундах
    public final void join(long millis, int nanos);
  • resume
  • Запуск временно приостановленного потока
    public final void resume();
  • run
  • Метод вызывается в том случае, если поток был создан как объект с интерфейсом Runnable
    public void run();
  • setDaemon
  • Установка для потока режима демона
    public final void setDaemon(boolean on);
  • setName
  • Устаовка имени потока
    public final void setName(String name);
  • setPriority
  • Установка приоритета потока
    public final void setPriority(int newPriority);
  • sleep
  • Задержка потока на заднное время. Время задается в миллисекундах и наносекундах
    public static void sleep(long millis); Задержка потока на заднное время. Время задается в миллисекундах и наносекундах
    public static void sleep(long millis, int nanos);
  • start
  • Запуск потока на выполнение
    public void start();
  • stop
  • Остановка выполнения потока
    public final void stop(); Аварийная остановка выполнения потока с заданным исключением
    public final void stop(Throwable obj);
  • suspend
  • Приостановка потока
    public final void suspend();
  • toString
  • Строка, представляющая объект-поток
    public String toString();
  • yield
  • Приостановка текущего потока для того чтобы управление было передано другому потоку
    public static void yield();

    Многопоточность и анимация

    Многопоточность и анимация


    Многопоточность


    Многопоточность

    Наверное, сегодня уже нет необходимости объяснять, что такое многопоточность. Все современные операционные системы, такие как Windows 95, Windows NT, OS/2 или UNIX способны работать в многопоточном режиме, повышая общую производительность системы за счет эффективного распараллеливания выполняемых потоков. Пока один поток находится в состоянии ожидания, например, завершения операции обмена данными с медленным периферийным устройством, другой может продолжать выполнять свою работу.
    Пользователи уже давно привыкли запускать параллельно несколько приложений для того чтобы делать несколько дел сразу. Пока одно из них занимается, например, печатью документа на принтере или приемом электронной почты из сети Internet, другое может пересчитывать электронную таблицу или выполнять другую полезную работу. При этом сами по себе запускаемые приложения могут работать в рамках одного потока - операционная система сама заботится о распределении времени между всеми запущенными приложениями.
    Создавая приложения для операционной системы Windows на языках программирования С или С++, вы могли решать многие задачи, такие как анимация или работа в сети, и без использования многопоточности. Например, для анимации можно было обрабатывать сообщения соответствующим образом настроенного таймера.
    Приложениям Java такая методика недоступна, так как в этой среде не предусмотрено способов периодического вызова каких-либо процедур. Поэтому для решения многих задач вам просто не обойтись без многопоточности.

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

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

    В этом приложении мы создаем на базе класса Thread три класса. Первый из них предназначен для создания потока рисования прямоугольников, второй - для создания потока рисования закрашенных эллипсов, а третий - для управления потоком рисования эллипсов.
    Что же касается основного класса аплета, то он унаследован, как обычно, от класса Applet и не реализует интерфейс Runnable:
    public class Rectangles extends Applet { . . . }

    Описание текстов

    Описание текстов


    Ожидание извещения

    Ожидание извещения

    Если вам нужно организовать взаимодействие потоков таким образом, чтобы один поток управлял работой другого или других потоков, вы можете воспользоваться методами wait, notify и notifyAll, определенными в классе Object.
    Метод wait может использоваться либо с параметром, либо без параметра. Этот метод переводит поток в состояние ожидания, в котором он будет находиться до тех пор, пока для потока не будет вызван извещающий метод notify, notifyAll, или пока не истечет период времени, указанный в параметре метода wait.
    Как пользоваться методами wait, notify и notifyAll?
    Метод, который будет переводиться в состояние ожидания, должен быть синхронизированным, то есть его следует описать как synchronized:
    public synchronized void run() { while (true) { . . . try { this.wait(); } catch (InterruptedException e) { } } } В этом примере внутри метода run определен цикл, вызывающий метод wait без параметров. Каждый раз при очередном проходе цикла метод run переводится в состояние ожидания до тех пор, пока другой поток не выполнит извещение с помощью метода notify.
    Ниже мы привели пример потока, вызывающией метод notify:
    public void run() { while (true) { try { Thread.sleep(30); } catch (InterruptedException e) { } synchronized(STask) { STask.notify(); } } } Этот поток реализован в рамках отдельного класса, конструктору которого передается ссылка на поток, вызывающую метод wait. Эта ссылка хранится в поле STask.
    Обратите внимание, что хотя сам метод run не синхронизированный, вызов метода notify выполняется в синхронизированном режиме. В качестве объекта синхронизации выступает поток, для которого вызывается метод notify.

    Ожидание завершения потока

    Ожидание завершения потока

    С помощью метода join вы можете выполнять ожидание завершения работы потока, для которой этот метод вызван.
    Существует три определения метода join:
    public final void join(); public final void join(long millis); public final void join(long millis, int nanos); Первый из них выполняет ожидание без ограничения во времени, для второго ожидание будет прервано принудительно через millis миллисекунд, а для третьего - через millis миллисекунд и nanos наносекунд. Учтите, что реально вы не сможете указывать время с точностью до наносекунд, так как дискретность системного таймера компьютера намного больше.

    Поля класса DrawRectangles

    Поля класса DrawRectangles

    Класс DrawRectangles определен для потока рисования прямоугольников:
    class DrawRectangles extends Thread { . . . } В поле g класа хранится контекст отображения окна аплета, а в поле dimAppWndDimension - размеры этого окна:
    Graphics g; Dimension dimAppWndDimension; Значения этих полей определяются конструктором класса по ссылке на главный класс аплета.

    Поля класса NotifyTask

    Поля класса NotifyTask

    В классе NotifyTask мы определили одно поле STask класса Thread. Это поле которое хранит ссылку на поток, работой которого управляет данный класс:
    class NotifyTask extends Thread { Thread STask; . . . }

    Поля класса Rectangles

    Поля класса Rectangles

    В классе Rectangles мы определили три поля с именами m_DrawRectThread, m_DrawEllipseThread и m_NotifyTaskThread:
    DrawRectangles m_DrawRectThread = null; DrawEllipse m_DrawEllipseThread = null; NotifyTask m_NotifyTaskThread = null Эти поля являются ссылками на классы, соответственно DrawRectangles, DrawEllipse и NotifyTask . Первый из них создан для рисования прямоугольников, второй - эллипсов, а третий - для управления потоком рисования эллипсов.
    Указанные поля инициализируются занчением null, что соответствует неработающим или несозданным задачам.

    Поля

    Поля

    Три статических поля предназначены для назначения приоритетов потокам.
  • NORM_PRIORITY

  • Нормальный
    public final static int NORM_PRIORITY;
  • MAX_PRIORITY
  • Максимальный
    public final static int MAX_PRIORITY;
  • MIN_PRIORITY
  • Минимальный
    public final static int MIN_PRIORITY;

    Поток

    Поток

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

    Потокидемоны


    Потоки-демоны

    Вызвав для потока метод setDaemon, вы превращаете обычную поток в поток-демон. Такой поток работает в фоновом режиме независимо от породившего его потока. Если поток-демон создает другие потоки, то они также станут получат статус потока-демона.
    Заметим, что метод setDaemon необходимо вызывать после создания потока, но до момента его запуска, то есть перед вызовом метода start.
    С помощью метода isDaemon вы можете проверить, является поток демоном, или нет.

    Применение многопоточности для анимации

    Применение многопоточности для анимации

    Одно из наиболее распространенных применений аплетов - это создание анимационных эффектов типа бегущей строки, мерцающих огней или аналогичных, привлекающих внимание пользователя. Для того чтобы достичь такого эффекта, необходим какой либо механизм, позволяющий выполнять перерисовку всего окна аплета или его части периодически с заданным временным интервалом.
    Работа аплетов, так же как и обычных приложений операционной системы Windows, основана на обработке событий. Для классического приложения Windows событие - это приход сообщения в функцию окна. Основной класс аплета обрабатывает события, переопределяя те или иные методы базового класса Applet.
    Проблема с периодическим обновлением окна аплета возникает из-за того, что в языке Java не предусмотрено никакого механизма для создания генератора событий, способного вызывать какой-либо метод класса аплета с заданным интервалом времени. Вы не можете поступить так, как поступали в этой ситуации, разрабатывая обычные приложения Windows - создать таймер и организовать обработку периодически поступающих от него сообщений WM_TIMER.
    Напомним, что перерисовка окна аплета выполняется методом paint, который вызывается виртуальной машиной Java асинхронно по отношению к выполнению другого кода аплета.
    Можно ли воспользоваться методом paint для периодической перерисовки окна аплета, организовав в нем, например, бесконечный цикл с задержкой?
    К сожалению, так поступать ни в коем случае нельзя. Метод paint после перерисовки окна аплета должен сразу возвратить управление, иначе работа аплета будет заблокирована.
    Единственный выход из создавшейся ситуации - создание потока (или нескльких потоков), которые будут выполнять рисование в окне аплета асинхронно по отношению к работе кода аплета. Например, вы можете создать поток, который периодически обновляет окно аплета, вызывая для этого метод repaint, или рисовать из потока непосредственно в окне аплета, получив предварительно для этого окна контекст отображения.

    Приоритеты потоков в приложениях Java

    Приоритеты потоков в приложениях Java

    Если процесс создал несколько потоков, то все они выполняются параллельно, причем время центрального процессора (или нескольких центральных процессоров в мультипроцессорных системах) распределяется между этими потоками.
    Распределением времени центрального процессора занимается специальный модуль операционной системы - планировщик. Планировщик по очереди передает управление отдельным потокам, так что даже в однопроцессорной системе создается полная иллюзия параллельной работы запущенных потоков.
    Распределение времени выполняется по прерываниям системного таймера. Поэтому каждому потоку дается определенный интервал времени, в течении которого он находится в активном состоянии.
    Заметим, что распределение времени выполняется для потоков, а не для процессов. Потоки, созданные разными процессами, конкурируют между собой за получение процессорного времени.
    Каким именно образом?
    Приложения Java могут указывать три значения для приоритетов потоков. Это NORM_PRIORITY, MAX_PRIORITY и MIN_PRIORITY.
    По умолчанию вновь созданный поток имеет нормальный приоритет NORM_PRIORITY. Если остальные потоки в системе имеют тот же самый приоритет, то все потоки пользуются процессорным времени на равных правах.
    При необходимости вы можете повысить или понизить приоритет отдельных потоков, определив для них значение приоритета, соответственно, MAX_PRIORITY или MIN_PRIORITY. Потоки с повышенным приоритетом выполняются в первую очередь, а с пониженным - только при отсутствии готовых к выполнению потоков, имеющих нормальный или повышенный приоритет.

    Процесс

    Процесс

    Процесс (process) - это объект, который создается операционной системой, когда пользователь запускает приложение. Процессу выделяется отдельное адресное пространство, причем это пространство физически недоступно для других процессов. Процесс может работать с файлами или с каналами связи локальной или глобальной сети. Когда вы запускаете текстовый процессор или программу калькулятора, вы создаете новый процесс.

    Процессы потоки и приоритеты


    Процессы, потоки и приоритеты

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

    Реализация интерфейса Runnable

    Реализация интерфейса Runnable

    Описанный выше способ создания потоков как объектов класса Thread или унаследованных от него классов кажется достаточнао естественным. Однако этот способ не единственный. Если вам нужно создать только один поток, работающую одновременно с кодом аплета, проще выбрать второй способ с использованием интерфейса Runnable.
    Идея заключается в том, что основной класс аплета, который является дочерним по отношению к классу Applet, дополнительно реализует интерфейс Runnable, как это показано ниже:
    public class MultiTask extends Applet implements Runnable { Thread m_MultiTask = null; . . . public void run() { . . . } public void start() { if (m_MultiTask == null) { m_MultiTask = new Thread(this); m_MultiTask.start(); } } public void stop() { if (m_MultiTask != null) { m_MultiTask.stop(); m_MultiTask = null; } } } Внутри класса необходимо определить метод run, который будет выполняться в рамках отдельного потока. При этом можно считать, что код аплета и код метода run работают одновременно как разные потоки.
    Для создания потока используется оператор new. Поток создается как объект класса Thread, причем конструктору передается ссылка на класс аплета:
    m_MultiTask = new Thread(this); При этом, когда поток запустится, управление получит метод run, определенный в классе аплета.
    Как запустить поток?
    Запуск выполняется, как и раньше, методом start. Обычно поток запускается из метода start аплета, когда пользователь отображает страницу сервера Web, содержащую аплет. Остановка потока выполняется методом stop.

    Реализация многопоточности в Java


    Реализация многопоточности в Java

    должны воспользоваться классом java.lang.Thread. В этом классе определены все методы, необходимые для создания потоков, управления их состоянием и синхронизации. Как пользоваться классом Thread?
    Есть две возможности.
  • Во-первых, вы можете создать свой дочерний класс на базе класса Thread. При этом вы должны переопределить метод run. Ваша реализация этого метода будет работать в рамках отдельного потока.
  • Во-вторых, ваш класс может реализовать интерфейс Runnable. При этом в рамках вашего класса необходимо определить метод run, который будет работать как отдельный поток.

  • Второй способ особенно удобен в тех случаях, когда ваш класс должен быть унаследован от какого-либо другого класса (например, от класса Applet) и при этом вам нужна многопоточность. Так как в языке программирования Java нет множественного наследования, невозможно создать класс, для которого в качестве родительского будут выступать классы Applet и Thread. В этом случае реализация интерфейса Runnable является единственным способом решения задачи.

    Окно аплета Rectangles

    Рисунок 1. Окно аплета Rectangles

    Окно аплета Rectangles
    Расположение прямоугольников и эллипсов также выбирается случайно.

    Синхронизация методов

    Синхронизация методов

    Возможность синхронизации как бы встроена в каждый объект, создаваемый приложением Java. Для этого объекты снабжаются защелками, которые могут быть использованы для блокировки потоков, обращающихся к этим объектам.
    Чтобы воспользоваться защелками, вы можете объявить соответствующий метод как synchronized, сделав его синхронизированным:
    public synchronized void decrement() { . . . } При вызове синхронизированного метода соответствующий ему объект (в котором он определен) блокируется для использования другими синхронизированными методами. В результате предотвращается одновременная запись двумя методами значений в область памяти, принадлежащую данному объекту.
    Использование синхронизированных методов - достаточно простой способ синхронизации потоков, обращающихся к общим критическим ресурсам, наподобие описанного выше банковского счета.
    Заметим, что не обязательно синхронизовать весь метод - можно выполнить синхронизацию только критичного фрагмента кода.
    . . . synchronized(Account) { if(Account.check(3000000)) Account.decrement(3000000); } . . . Здесь синхронизация выполняется для объекта Account.

    Синхронизация потоков


    Синхронизация потоков

    Многопоточный режим работы открывает новые возможности для программистов, однако за эти возможности приходится расплачиваться усложнением процесса проектирования приложения и отладки. Основная трудность, с которой сталкиваются программисты, никогда не создававшие ранее многопоточные приложения, это синхронизация одновременно работающих потоков.
    Для чего и когда она нужна?
    Однопоточная программа, такая, например, как программа MS-DOS, при запуске получает в монопольное распоряжение все ресурсы компьютера. Так как в однопоточной системе существует только один процесс, он использует эти ресурсы в той последовательности, которая соответствует логике работы программы. Процессы и потоки, работающие одновременно в многопоточной системе, могут пытаться обращаться одновременно к одним и тем же ресурсам, что может привести к неправильной работе приложений.
    Поясним это на простом примере.
    Пусть мы создаем программу, выполняющую операции с банковским счетом. Операция снятия некоторой суммы денег со счета может происходить в следующей последовательности:
  • на первом шаге проверяется общая сумма денег, которая хранится на счету;
  • если общая сумма равна или превышает размер снимаемой суммы денег, общая сумма уменьшается на необходимую величину;
  • значение остатка записывается на текущий счет.

  • Если операция уменьшения текущего счета выполняется в однопоточной системе, то никаких проблем не возникнет. Однако представим себе, что два процесса пытаются одновременно выполнить только что описанную операцию с одним и тем же счетом. Пусть при этом на счету находится 5 млн. долларов, а оба процесса пытаются снять с него по 3 млн. долларов.
    Допустим, события разворачиваются следующим образом:
  • первый процесс проверяет состояние текущего счета и убеждается, что на нем хранится 5 млн. долларов;
  • второй процесс проверяет состояние текущего счета и также убеждается, что на нем хранится 5 млн. долларов;
  • первый процесс уменьшает счет на 3 млн. долларов и записывает остаток (2 млн. долларов) на текущий счет;
  • второй процесс выполняет ту же самую операцию, так как после проверки считает, что на счету по-прежнему хранится 5 млн. долларов.

  • В результате получилось, что со счета, на котором находилось 5 млн. долларов, было снято 6 млн. долларов, и при этом там осталось еще 2 млн. долларов! Итого - банку нанесен ущерб в 3 млн. долларов.
    Как же составить программу уменьшения счета, чтобы она не позволяла вытворять подобное?
    Очень просто - на время выполнения операций над счетом одним процессом необходимо запретить доступ к этому счету со стороны других процессов. В этом случае сценарий работы программы должен быть следующим:
  • процесс блокирует счет для выполнения операций другими процессами, получая его в монопольное владение;
  • процесс проводит процедуру уменьшения счета и записывает на текущий счет новое значение остатка;
  • процесс разблокирует счет, разрешая другим процессам выполнение операций.

  • Когда первый процесс блокирует счет, он становится недоступен другим процессам. Если второй процесс также попытается заблокировать этот же счет, он будет переведен в состояние ожидания. Когда первый процесс уменьшит счет и на нем останется 2 млн. долларов, второй процесс будет разблокирован. Он проверит остаток, убедится, что сумма недостаточна и не будет проводить операцию.
    Таким образом, в многопоточной среде необходима синхронизация потоков при обращении к критическим ресурсам. Если над такими ресурсами будут выполняться операции в неправильной последовательности, это приведет к возникновению трудно обнаруживаемых ошибок.
    В языке программирования Java предусмотрено несколько средств для синхронизации потоков, которые мы сейчас рассмотрим.

    Создание дочернего класса на базе класса Thread

    Создание дочернего класса на базе класса Thread

    Рассмотрим первый способ реализации многопоточности, основанный на наследовании от класса Thread. При использовании этого способа вы определяете для потока отдельный класс, например, так:
    class DrawRectangles extends Thread { . . . public void run() { . . . } } Здесь определен класс DrawRectangles, который является дочерним по отношению к классу Thread.
    Обратите внимание на метод run. Создавая свой класс на базе класса Thread, вы должны всегда определять этот метод, который и будет выполняться в рамках отдельного потока.
    Заметим, что метод run не вызывается напрямую никакими другими методами. Он получает управление при запуске потока методом start.
    Как это происходит?
    Рассмотрим процедуру запуска потока на примере некоторого класса DrawRectangles.
    Вначале ваше приложение должно создать объект класса Thread:
    public class MultiTask2 extends Applet { Thread m_DrawRectThread = null; . . . public void start() { if (m_DrawRectThread == null) { m_DrawRectThread = new DrawRectangles(this); m_DrawRectThread.start(); } } } Создание объекта выполняется оператором new в методе start, который получает управление, когда пользователь открывает документ HTML с аплетом. Сразу после создания поток запускается на выполнение, для чего вызывается метод start.
    Что касается метода run, то если поток используется для выполнения какой либо периодической работы, то этот метод содержит внутри себя бесконечный цикл. Когда цикл завершается и метод run возвращает управление, поток прекращает свою работу нормальным, не аварийным образом. Для аварийного завершения потока можно использовать метод interrupt.
    Остановка работающего потока выполняется методом stop. Обычно остановка всех работающих потоков, созданных аплетом, выполняется методом stop класса аплета:
    public void stop() { if (m_DrawRectThread != null) { m_DrawRectThread.stop(); m_DrawRectThread = null; } } Напомним, что этот метод вызывается, когда пользователь покидает страницу сервера Web, содержащую аплет.

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

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

    Методы suspend и resume позволяют, соответственно, временно приостанавливать и возобновлять работу потока.
    В следующем фрагменте кода поток m_Rectangles приостанавливает свою работу, когда курсор мыши оказывается над окном аплета:
    public boolean mouseEnter(Event evt, int x, int y) { if (m_Rectangles != null) { m_Rectangles.suspend(); } return true; } Работа потока возобновляется, когда курсор мыши покидает окно аплета:
    public boolean mouseExit(Event evt, int x, int y) { if (m_Rectangles != null) { m_Rectangles.resume(); } return true; }

    

        Бизнес: Предпринимательство - Малый бизнес - Управление