    Глава 4 

    Меню и элементы управления AWT 

    Графические пользовательские интерфейсы (GUI) являются, можно сказать, 
важнейшими компонентами коммерческих программ. Неважно, насколько быстро и 
эффективно работает созданная вами программа, но если у нее нет интерфейса 
(UI), который был бы легок в использовании и визуально привлекателен, значит, 
у нее нет и будущего — такой продукт не выдержит конкуренции. Еще более это 
утверждение справедливо в отношении распределенных программ, работающих в 
World Wide Web (WWW). Любители WWW становятся такими же разборчивыми и 
требовательными, как и зрители MTV в начале 80-х годов. 
    У WWW-страницы имеется лишь несколько секунд для привлечения внимания 
пользователя. После этого программа должна стать интуитивно понятной 
пользователю и способной достаточно эффективно работать. 
    Очень удобно, что большинство задач GUI решаются с использованием 
небольшого количества управляющих элементов. Кнопка, контрольный 
переключатель, список, меню — это проверенные временем элементы GUI, которые 
всем понятны и имеются в каждой операционной системе, работающей с окнами. 
Кнопки выглядят и действуют совершенно одинаково как на платформе Windows 95, 
так и на Macintosh, X-Window и OS/2. 
    С точки зрения пользователей, эти элементы в разных операционных системах 
выглядят одинаково, но для разработчиков их коды выглядят совершенно 
по-разному. Программист, работающий в системе Windows, вряд ли сможет создать 
GUI для Macintosh. 
    Появление языка Java избавило от дублирования работы. Создатели Java были 
не первыми, кто признал важность развития платформа-независимого 
инструментария для разработки оконных интерфейсов. В частности, популярный 
пакет программ Galaxy в течение нескольких лет использовался для создания 
платформа-независимых программ, применяющих оконный интерфейс; в пакете 
Coconet определялась среда GUI для работы в сети, что весьма похоже на 
применение апплетов в Java. Создатели Java, действительно, были не первыми на 
этом пути, но лишь у них это получилось хорошо и дешево (два условия, без 
которых невозможно произвести переворот в программировании). 

    107 

    В этой главе описываются классы пакета AWT (Abstract Windows Toolkit), 
служащие для создания GUI в Java, и утилита ResourceWizard, позволяющая 
ускорить разработку GUI. Стандартные элементы GUT, которые используются в 
операционных системах с оконным интерфейсом, включены в пакет java.awt как 
классы, порожденные от класса Component. Классы меню не относятся к классам 
типа Component, а являются ветвью дерева классов AWT. Меню также описаны в 
настоящей главе. 
    ResourceWizard может автоматически создавать классы Java из ресурсов меню 
и диалоговых окон, определенных в файлах ресурсов, таких как файлы с 
расширением RCT или RES. В этой главе рассказывается, как это можно сделать, 
сэкономив таким образом определенное время. 

    Встроенные элементы управления AVVT 

    В класс Component пакета java.awt включены классы, описывающие кнопки, 
метки, контрольные переключатели, селекторные кнопки, списки, поля ввода, 
текстовые окна (многостроковые поля ввода), выпадающие списки. Все эти классы 
порождены от класса Component. Иерархия описанных в данном параграфе классов 
показана на рис. 4.1. 

    Object 
    Component 
    Label 
    Button 
    Text Component 
       Text Field 
       Text Area

    Рис. 4.1. Иерархия классов, порожденных от класса Component пакета java.awt 


    108 Visual J++: основы программирования 

    Встроенные классы типа Component извещают программу о взаимодействии с 
пользователем при помощи процедур обработки событий. Например, при щелчке 
мышью на изображении кнопки вызывается метод action() объекта типа Container, 
чтобы сообщить о нажатии кнопки. Более подробно о взаимодействии 
компонент/контейнер и о методах обработки событий было рассказано в главе 3. 

    Класс Label 

    Класс Label является простейшим из встроенных классов типа Component. 
Метка — это просто компоненет, который отображает одну строку текста. Метки 
обычноГразмещаются рядом с компонентом GUI и содержат информацию о нем. Ниже 
показаны две метки, описывающие использование двух различных наборов 
компонентов. Обычно метки располагаются вблизи списков, выпадающих списков, 
полей ввода, текстовых окон или группы родственных компонентов. Контрольные 
переключатели и кнопки, в отличие от остальных классов, получают метки 
автоматически. 

    Для создания метки необходимо конструктору класса Label передать строку 
текста. В полученном объекте типа Label будет отображаться заданный 
пользователем текст. Метка может содержать только одну строку текста. В 
противном случае следует использовать вертикальный ряд меток или текстовое 
окно. 
    Методы getText() и setText() класса Label предназначены для модификации 
строки текста, появляющейся в объекте типа Label. Их можно использовать и для 
изменения текста при изменении состояния программы. В пользовательском 
интерфейсе можно создать несколько меток, причем, таким образом, чтобы в 
каждый момент времени была видна только одна из них. 
   Метка не является элементом взаимодействия. В Java нет событий, получаемых 
от объектов типа Label и описывающих взаимодействие пользователя с объектом. 
Поэтому при щелчке мышью на метке или в результате подведения к ней курсора 
никакое сообщение не появляется. Метки нужны лишь для того, чтобы обозначить 
какой-то другой элемент. Применяя описанные в главе 3 методы создания 
пользовательских компонентов, можно создать интерактивную метку. 

    Глава Ч. Меню п элементы управления AVVT 109 

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

import  java.awt.*; 

public class MyFrame extends Frame { 
	public MyFrame(String strTitle) { 
		super (strTitle); 
		// Создание элемента интерфейса. 
		setLayout(new FlowLayout(FlowLayout.RIGHT, 5,10)); 
		add(new Label( "Choose Item:", Label.RIGHT )); 
		m_list = new List(); 
		add(m_list); 
		add(new Label( "Choose Color:", Label.RIGHT )); 
		m_radioWhite = new Checkbox("White"); 
		m_radioBlack = new Checkbox("Black"); 
		add(m_radioWhite); 
		add(m_radioBlack); 
	} 
	private List m_list; 
	private Checkbox m_radioWhite; 
	private Checkbox m_radioBlack; 
}

    В этом примере у конструктора класса Label есть два параметра. Первый — 
это строка, которую следует отобразить, второй — параметр выравнивания. Для 
определения способа выравнивания строки текста внутри метки используются три 
public-константы класса Label: LEFT, CENTER и RIGHT. Метод setAlignment() 
предназначен для изменения способа выравнивания после создания метки. 

    Класс Button 

    Самым известным элементом пользовательского интерфейса наряду с меню 
является кнопка. Едва ли найдется программа, написанная в среде Windows, в 
пользовательском интерфейсе которой не будет меню или панели инструментов с 
кнопками. Рассмотрим интерфейсы самых популярных программ среды Windows: 
Netscape Navigator, Microsoft Internet Explorer и др. Все они имеют кнопки. 
Ниже показан экран программы Netscape Navigator 2.0, в основном 
пользовательском интерфейсе которого имеется некоторое количество кнопок. 

    110 Visual J++: основы программирования 

    Класс Button абстрагирует понятие кнопки в AWT. Объект типа Button может 
отображать одну строку текста, размещаемую на верхней части кнопки. Обычно 
функции кнопки описываются с помощью глагола или слова, дающего наглядное 
представление о ее действии (примером могут служить кнопки ОК и Cancel). 
Надпись, которая отображается на кнопке, должна быть передана конструктору 
класса Button. 
    Методы setLabel() и getLabel() класса Button, аналогично методам 
setText() и getText() класса Label, используются для получения и задания 
текста кнопки. (Обратите внимание на разницу в именах: имена setLabel и 
getLabel внесли бы путаницу при их использовании в классе Label.) 
    В примере 4.1 определяется класс типа Toolbar, соответствующий панели 
инструментов Directory Buttons в программе Netscape Navigator (начинается с 
кнопки "What's new"): 

    Пример 4.1. Класс Navigation Toolbar 

import   java.awt.*; 

public class NavToolbar extends Panel { 
	public NavToolbar() { 
		setLayout(new FlowLayout(FlowLayout.LEFT, 3, 3); 
		add(m_buttonWhatsNew = new Button("What's New!")); 
		add(m_buttonWhatsCool = new Button("What's Cool!")); 
		add(m_buttonHandbook = new Button("Handbook")); 
		add(m_buttonNetSearch = new Button("Net Search!)); 
		add(m_buttonNetDirectory = new Button ("Net Directory!")); 
		add(m buttonSoftware = new Button("Software!"));
	}
	public boolean action(Event evt, Object arg) {
		if(m_buttonWhatsNew == evt.target) 
			getParent().postEvent(new Event(this, WHATS_NEW, null)); 
		else if(m_buttonWhatsCool == evt.target) 
			getParentO .postEvent(new Event(this, WHATS_COOL, null)); 
		else if(m_buttonHandbook == evt.target) 
			getParent().postEvent(new Event(this, HANDBOOK, null)); 


    Глава 4. Меню и элементы управления AWT 111 


		else if(m_buttonNetSearch == evt.target) 
			getParent().postEvent(new Event(this, NET_SEARCH, null)); 
		else if(m_buttonNetDirectory == evt.target) 
			getParent().postEvent(new Event(this, NET_DIRECTORY, null)); 
		else if(m_buttonSoftware == evt.target) 
			getParent().postEvent(new Event(this, SOFTWARE, null)); 
		else
			return false; ?
		return true;  ?
	}
	// Private-переменные и константы, 
	private Button m_buttonWhatsNew; 
	private Button m_buttonWhatsCool; 
	private Button m_buttonHandbook; 
	private Button m_buttonNetSearch; 
	private Button m_buttonNetDirectory; 
	private Button m_buttonSoftware; 
	public static final int WHATS^_NEW = -I; 
	public static final int WHATS_COOL = -2; 
	public static final int HANDBOOK = -3; 
	public static final int NET_SEARCH = -4; 
	public static final int NET_DIRECTORY = -5; 
	public static final int SOFTWARE = -6; 
} 

    Из этого примера видно, что события передаются в контейнер объекта типа 
Button всякий раз, когда пользователь щелкает мышью на кнопке. Параметр arg 
содержит то же значение, что и переменная arg объекта Event, являющееся 
строкой метки на объекте типа Button. Например, если щелкнуть на кнопке 
"What's Cool!" панели инструментов NavToolbar, то параметр arg метода action()
класса Toolbar станет строкой "What's Cool!". Можно идентифицировать щелчок 
мыши, используя параметр arg, но лучше проверить переменную target объекта 
Event, как показано в реализации класса NavToolbar. У нескольких объектов типа 
Button могут быть одинаковые метки — в таком случае метод action() не даст 
полезной информации. 

    Класс Checkbox 

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

    112 Visual J++: основы программирования 

переключатели AWT используются подобным образом, то в среде Windows вместо 
обычных переключателей применяются селекторные кнопки. Конечно, Java-код не 
подозревает о такой замене, но программист должен об этом помнить. Ниже 
показано окно, содержащее как простые переключатели, так и переключатели, 
реализующие выбор "один из многих". 

    Простой контрольный переключатель действует аналогично кнопке, однако 
управляется он с помощью лишь одной булевой переменной состояния. Как и у 
кнопки, у контрольного переключателя имеется собственная метка. Создавать для 
него дополнительные объекты типа Label нет необходимости. 
    Самому простому конструктору не требуется задавать параметры; он создает 
простой переключатель, у которого нет метки, описывающей "сброшенное" 
состояние. У другого конструктора в качестве метки используется строка. Как и 
в классе Button, методы setLabel() и getLabel() класса Checkbox используются для 
модификации отображаемой строки. Методы getState() и setState() класса Checkbox 
предназначены для изменения состояния элемента от true (выбран) до false (сброшен). 
    Выбор одного из вариантов осуществляется в Java путем объединения 
нескольких различных объектов типа Checkbox в один объект типа Check-boxGroup. 
Класс CheckboxGroup — это не графический элемент, а просто набор объектов типа 
Checkbox, которые объединяются в группу с помощью третьей версии конструктора 
класса Checkbox: 

    CheckboxGroup group = new CheckboxGroup(); 
    Checkbox chkbxOne =	new Checkbox("One", group, false); 
    Checkbox chkbxTwo =	new Checkbox("Two", group, true); 
    Checkbox chkbxThree	= new Checkbox ("Three", group, false); 

    В группе может иметься и несколько контрольных переключателей, но только 
один из них может нaxoдится в состоянии выбран. Если при выборе из группы 
используется метод setState() класса Checkbox, то элемент, который был 
выбран ранее, автоматически выключается. В классе CheckboxGroup 
объявлены public-методы getCurrent() и setCurrent(), которые могут изменять 
"выбранный" переключатель, используя вместо объектов типа Checkbox 
оБъёкт типа CheckboxGroup. 

    Глава 4. Меню и элементы управления AVVT 113 

    Однако класс CheckboxGroup недостаточно гибок. В частности, вы не сможете 
получить список элементов группы объекта типа CheckboxGroup, добавить или 
убрать элементы из группы. Чтобы смоделировать удаление нежелательных 
элементов из окна, надо временно скрыть их и снова отобразить, когда это понадобится. 
    В следующем примере объясняется, как с помощью класса Checkbox можно 
создать окно, показанное на предыдущем рисунке. 

    Пример 4.2. Пример создания контрольных переключателей 

	import   java.awt.*; 

	public class MyFrame extends Frame { 
		public MyFrame() { 
			setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5)); 
			add(new Label("Single-selection Checkboxes:")); 
			add(new Checkbox ("One")); 
			add(new Checkbox("Two")); 
			add(new Checkbox ("Three")); 
			add(new Label("One-of-many Checkboxes:")); 
			add(new Checkbox("First")); 
			add(new Checkbox("Second")); 
			add(new Checkbox("Third")); 
		}
	}


    Класс Scrollbar 

    Полоса прокрутки (scrollbar) дает возможность выбрать поддиапазон 
некоторого диапазона величин. Как кнопки и меню, полосы прокрутки являются 
достаточно распространенными элементами интерфейса. Обычно их используют для 
управления вертикальной или горизонтальной прокруткой полей списков, полей 
ввода, окон просмотра документов. Полосу прокрутки можно создать для 
собственного окна или для элемента, который будет выбирать определенное 
значение из диапазона значений. Последний случай (выбор значения из диапазона 
Slow...Fast) проиллюстрирован ниже. 

    Класс Scrollbar объединяет полосы прокрутки для Java-программ. Здесь 
имеется несколько public-методов управления внешним видом и поведением полосы 
прокрутки, и несколько предназначенных именно для этой цели идентификаторов 
событий. Так, идентификатор SCROLL_LINE_UP в классе 

    114 Visual J++: основы программирования 

Event используется только тогда, когда пользователь щелкает мышью на 
кнопке Line Up полосы прокрутки. 
    Состояние объектов типа Scrollbar определяется семью переменными 
внутреннего состояния, перечисленными ниже: 
    •    Orientation. Полоса прокрутки ориентирована либо горизонтально, либо 
вертикально. Связанные с ней термины подразумевают вертикальную ориентацию. 
Значение SCROLL_LINE_UP используется и для горизонтальных полос, указывая на 
прокрутку влево. Значение SCROLL_LINE_DOWN для горизонтальных полос прокрутки 
обозначает движение вправо. Два возможных значения этой переменной — 
Scrollbar.HORIZONTAL и Scrollbar.VERTICAL. 
    •    Value. Текущее значение счетчика полосы прокрутки, находящееся в 
интервале между максимальным и минимальным значениями. 
    •    Minimum. Наименьшее значение счетчика, достигаемое с помощью полосы 
прокрутки. Когда ползунок (thumb) для вертикальной полосы прокрутки находится 
в самом верхнем, а для горизонтальной — в самом левом положении, то 
соответствующее ему значение минимально. 
    •    Maximum. Наибольшее значение счетчика, достигаемое с помощью полосы 
прокрутки. Оно соответствует самому правому положению ползунка для 
горизонтальной и самому нижнему его положению для вертикальной полос прокрутки. 
    •    PageSize. Величина постраничного приращения. Когда пользователь 
выполняет постраничное перемещение посредством щелчка мышью на той части 
полосы, которая находится вне ползунка, или нажатием клавиши Page Down (когда 
окно полосы имеет фокус ввода), то значение, соответствующее полосе прокрутки, 
изменяется на эту величину. 
    •    LineSize Размер одной строки полосы прокрутки. Если пользователь 
выполняет операцию перехода на следующую строку с помощью щелчка мышью на 
кнопке Line Down или путем нажатия клавиши [ ], значение, соответствующее 
полосе прокрутки, увеличивается на эту величину. До тех пор, пока эта 
переменная не будет изменена при явном вызове метода setLineIncrement() класса 
Scrollbar, она считается равной единице. 
    •    VisibleSize. Размер ползунка. Может иметь значение в диапазоне от 
нуля до разницы между максимальным и минимальным значениями счетчика. 
    Один из трех конструкторов класса Scrollbar принимает начальные значения 
для пяти переменных: 

    public Scrollbar (int orientation, int value, int visible, int minimum, 
int maximum) 

    При создании объекта класса Scrollbar необходимо указать хотя бы 
ориентацию полосы прокрутки. Если у конструктора нет аргументов, то полоса 
прокрутки будет ориентирована вертикально. Другая версия конструктора 
принимает признак ориентации полосы прокрутки в качестве единственного параметра. 

    Глава 4. Меню п элементы управления AVVT	115 

    Начальные значения остальных четырех переменных внутреннего состояния 
могут задаваться не только в конструкторе, но и с помощью различных методов 
класса Scrollbar. Действительно, если используется конструктор без параметров 
или конструктор с одним параметром, то значения внутреннего состояния надо 
задавать явно. Проще всего это сделать с помощью метода setValues(): 

    public void setValues(int value, int visible, int minimum, int maximum) 

    Следующие методы позволяют изменять значения переменных Value, LineSize и 
PageSize внутреннего состояния полосы прокрутки: 

    setValue(int value), setLinelncrement(int line_inc), setPagelncrement(int page_inc). 

    Внутреннее состояние полосы прокрутки можно проверять с помощью следующих 
методов: getMinimum(), getMaximum(), getLinelncrement(), getPagelncrement(), 
getValue() и getVisible(). 
    Ниже (пример 4.3) представлен код программы, результаты работы которой 
показаны на предыдущем рисунке. 

    Пример 4.3. Приложение, использующее полосы прокрутки 

import java.awt.*;

public class ScrollbarExample extends Frame implements Runnable { 
	public ScrollbarExample() {
		super ("Scrollbar Example Application"); 
		setLayout(new BorderLayout(5, 5)); 
		m_scroll = new Scrollbar(Scrollbar.HORIZONTAL, 0, 10, 0, 100); 
		add("South", m_scroll); 
		m_label = new Label ("Scroll val: move scrollbar"); 
		add("Center", m_label); 
	} 
	public boolean handleEvent(Event evt) { 
		switch (evt.id) { 
			case Event.SCROLL_LINE_UP: 
			case Event.SCROLL_LINE_DOWN: 
			case Event.SCROLL_PAGE_UP: 
			case Event.SCROLL_PAGE_DOWN: 
			case Event.SCROLL_ABSOLUTE 
				updateValue (m_scroll.getValue()); 
				return true; 
		} 
    		return false; 
	} 
	private void updateValue(int val) { 
		m_label.setText("Scroll val: " + val); 
	}


    116	Visual J++: основы программирования 


	// Private-переменные, 
	private Scrollbar m_scroll = null; 
	private Label m_label = null; 
} 

    О событиях SCROLL_LINE_UP/DOWN и SCROLL_PAGE_UP/DOWN уже поминалось. 
Событие SCROLL_ABSOLUTE показывает, что пользователь передвинул 
ползунок с помощью курсора мыши. Переменная arg класса Event содержит новое 
значение, соответствующее полосе прокрутки. 

    Классы TextField и TextArea 

    Поле ввода может быть элементом с одной или несколькими строками и в 
зависимости от этого относится к двум различным классам. Класс TextField 
включает в себя поле ввода с одной строкой, класс TextArea — поле ввода с 
большим количеством строк. Использование таких элементов, представляющих собой 
простые текстовые редакторы с возможностями резать, соединять, копировать и 
выбирать части текста, позволяет вводить текст в программу с клавиатуры. 
    Оба класса (TextField и TextArea) порождены от класса TextComponent, в 
котором определено большинство их функциональных возможностей. Текстовые поля 
и области можно рассматривать в качестве текстовых компонентов. 
    Состояние текстового компонента определяется несколькими переменными 
внутреннего состояния. Эти переменные можно проверять и модифицировать с 
помощью public-методов класса TextComponent. Дополнительную информацию о 
состоянии можно получить с помощью методов классов TextField и TextComponent. 
Ниже приведены переменные состояния текстовых компонентов: 
    •    isEditable. Поле ввода может быть редактируемым или нередактируемым. 
Нередактируемое поле ввода подобно метке, но между ними могут быть различия. 
Нередактируемый объект типа TextArea можно использовать в качестве метки с 
несколькими строками текста. Редактируемые поля ввода являются таковыми по 
умолчанию, но их можно сделать и нередактируемыми. 
    •    Text. Текст, содержащийся в текстовом компоненте. Символы задаются 
переменной position текстового компонента. Позиция соответствует 
отсчитываемому от нуля индексу символа в тексте текстового компонента. Позиция 
первого символа — 0, второго — 1 и т. д. 
    •    Selection Range. Весь текст компонента либо какая-то его часть, 
являющаяся выбранной областью. При установке области выбора текст здесь обычно 
выделяется. Пользователь может установить область выбора (для редактируемых 
текстовых окон) с помощью мыши или клавиатуры. Область выбора определяется 
позициями начального и последнего символов. Позиция начального символа 
указывает на начало области выбора (включая и этот символ). Последний символ 
также входит в область выбора. 

    Глава 4. Меню n элементы управления AVVT	117 

    В определенных ситуациях (правда, достаточно редко) используются 
нередактируемые текстовые компоненты. Предполагается, что текстовые компоненты 
являются редактируемыми, но их можно сделать и нередактируемыми (и наоборот) 
при помощи метода setEditable() класса TextComponent. Метод getEditable()
сообщает, каким именно является компонент в настоящий момент. 
    В классе TextComponents имеются методы для изменения текста в текстовых 
компонентах. Весь текст можно получить с помощью метода getText(). Метод 
setText() используется для замещения всего текста в текстовом компоненте. 
Методы getText() и setText() класса Label аналогичны соответствующим методам 
класса TextComponent. 
    Выбор текста можно проверить и изменить с помощью public-методов класса 
TextComponent. В классе TextArea реализованы методы, позволяющие легче 
производить эти действия. Методами класса TextComponent для получения позиции 
начала и конца области выбора являются getSelectionStart() и getSelectionEnd(). 
Если возвращаемые этими методами значения одинаковы, то они указывают на место 
расположения вставки. Если значение начальной позиции больше, чем значение 
конечной позиции, значит, точка вставки размещается в самом начале области 
выбора. В противном случае она находится в конце этой области. 
    Метод getSelectionText() возвращает копию выбранной строки. Методу select()
передаются значения начальной и конечной позиций области выбора, и он 
используется для выбора текста программным путем. С помощью метода selectAll() 
можно выбрать весь текст компонента типа TextComponent. 

    Класс TextField 

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

    Синтаксис конструктора		Инициализируемый  Инициализируемые 
						текст			строки 

    TextField()					Нет		Нет 
    TextField(int rows)				Нет		Есть 
    TextField(String strText)			Есть		Нет 
    TextField(String strText, int rows)	Есть		Есть 


    118	Visual J++: основы программирования 

    Первый и третий конструкторы создают экземпляр класса TextField без явных 
ограничений по длине текста. Максимальная его длина зависит от максимальной 
длины текста в поле ввода, определяемой операционной системой. 
    Компонент типа TextField можно использовать в качестве поля ввода пароля. 
Когда в компьютер вводят пароль, необходимо, чтобы никто из посторонних не 
подсмотрел его на экране. В большинстве компьютерных программ, написанных для 
операционных систем, которые используют окна, поле ввода не отображает 
набираемый пароль. Вместо него на экране появляется так называемое эхо, т.е. 
звездочки или точки, соответствующие каждому введенному символу. Класс 
TextField позволяет создать компонент типа TextField в виде поля ввода пароля. 
Символы, которые отображаются в нем вместо набираемых, называются 
эхо-символами (echo character). 
    При созданий~поля ввода пароля для установки эхо-символов используется 
метод setEchoCharacter() класса TextField. Следует отметить, что создание поля 
ввода пароля из компонента типа TextField — процесс необратимый. Если данный 
метод вызван, то отказаться от использования эхо-символов невозможно. Метод 
getEchoCharacter() возвращает значение эхо-символа. Метод echoCharlsSet()
сообщает, является ли компонент полем ввода пароля. 
    Даже когда в TextField используется эхо-символ, методы getText() и 
getSelectedText() класса TextComponent возвращают действительное 
содержание компонента TextField, а не строку эхо-символов. Поэтому для 
ограничения доступа к паролю недостаточно использовать эхо-символы, поскольку 
другой объект с помощью метода getText() может определить содержание компонента 
TextField. Чтобы помешать такому "опасному" доступу, другим классам необходимо 
просто запретить получать ссылки на компонент TextField. 

    Класс TextArea 

    Область текста является полем ввода с большим количеством строк. Как и 
класс TextField, класс TextArea порожден от класса TextComponent, поэтому у 
него имеются все элементы внутреннего состояния, характерные для базового 
класса: флаг редактируемости, строка отображаемого текста, диапазон выбора. 
Кроме того, здесь есть счетчик числа строк области текста и счетчик числа 
позиций символов. Число строк и число позиций в строке определяют размер 
текста на экране. Максимальная длина текста зависит от максимальной длины 
текста в поле ввода для данной операционной системы. С помощью класса TextArea 
невозможно создать поле ввода пароля, как в классе TextField. Если кто-либо из 
читателей посчитает, что многостроковые поля ввода пароля необходимы, пусть он 
напишет об этом автору на адрес издательства, ибо еще никому подобная мысль не 
приходила в голову. 
    Класс TextArea содержит методы проверки числа строк и числа позиций в 
строке, из которых создана область текста, а именно методы getRows() и 
getColumns(). Однако методов, предназначенных для изменения указанных значений, 
не существует. 

    Глава 4. Меню п элементы управления AVVT	119 

    Класс TextArea позволяет идентифицировать символы по их позиции в строке, 
как это делается в классах TextComponent и TextField. Идентификация символов 
по номеру строки и номеру позиции в строке невозможна. Поэтому, к сожалению, 
без сканирования текста и подсчета количества символов перевода строки 
невозможно угадать, какое место в строке занимает конкретный символ. 
    Как уже говорилось, в классе TextArea имеются дополнительные методы 
изменения текста, которых нет в классе TextComponent. Например, метод 
insertText() класса TextArea может вставлять строку в указанное место области 
текста, метод appendText() добавляет строку текста к концу области текста, 
метод replaceText() заменяет текст между указанными позициями альтернативной 
строкой текста. Конечно, методы getText() и setText() класса TextField тоже 
имеют силу. Таким образом, класс TextArea улучшает возможности своего 
родительского класса. 
    Если строка в области текста слишком объемна и ее невозможно отобразить в 
указанных рамках, задаваемых количеством строк и их длиной, то область текста 
автоматически создает полосу прокрутки, с тем чтобы пользователь мог 
просматривать содержимое всего текста области. 

    Класс List 

    Список — это элемент, позволяющий пользователю выбирать строку из группы 
строк. Списки используются, например, при выборе имени файла из каталога или 
имени канала из списка Chat-каналов. Список является обычным элементом 
пользовательского интерфейса для большинства операционных систем, работающих с 
окнами, поэтому в пакете java.awt ему соответствует отдельный класс — класс 
List. Простое окно со списком представлено на следующем рисунке. 
    Списки могут содержать одну или несколько строк. Список, включающий 
нескольких строк, позволяет пользователю выбрать несколько элементов 

    120 Visual J++: основы программирования 

списка,  обычно путем нажатия специальной клавиши во время щелчка мышью на 
нужных элементах. 
    Конструктор без параметров класса List создает список с одиночным выбором, 
размеры которого изменяются в соответствии с выделенной ему областью экрана. 
Второй конструктор позволяет указать количество видимых строк в списке и то, 
сколько (одну или более) строк можно выбирать. Метод isMultipleSelect() класса 
List возвращает значение true, если в списке можно выбрать несколько строк. 
Метод setMultipleSelect() используется для переключения объекта типа List в 
другое состояние с выбором одной или нескольких строк после того, как список 
был создан. 
    Public-интерфейс класса List выглядит так же, как и интерфейс класса 
связанных списков. Что такое список, как не упорядоченная очередь строк! 
Детали графического интерфейса класса List определены в public-интерфейсе 
этого класса, поэтому его можно рассматривать просто как связанный список. 
    В предлагаемой далее таблице показаны функциональные возможности класса 
связанных списков и эквивалентного ему по своим возможностям интерфейса 
класса List.        

    Функциональная возможность			Метоп класса List 

    Подсчитать элементы списка			countltems() 
    Очистить список					clear() 
    Добавить элемент в конец списка			addltem(String) 
    Вставить элемент в список				addItem(String, index) 
    Заменить элемент из списка другим элементом	replaceItem(String, index) 
    Удалить элемент из списка				delltem(index) 

    Во втором конструкторе класса List подразумевается, что у объектов имеется 
установленное число строк. Метод getRows() возвращает число строк, указанное 
конструктору класса List. Нулевое значение свидетельствует о том, что 
использован конструктор без параметров и объект типа List будет иметь такую 
величину, какая необходима для заполнения отведенной ему на экране области. 
    В интерфейсе класса List есть дополнительные методы управления выбором 
количества строк. Методы, которые используются в списках с одиночным выбором, 
проще. В предлагаемом ниже фрагменте, который демонстрирует применение методов 
getSelectedlndex() и getSelectedltem() класса List, выбранная из такого списка 
строка будет выводиться в поток System.out: 

    public void displaySelection(List list) { 
	    System.out.println("Item #" + list.getSelectlndex() + 
		    ": " + list.getSelectedltem()); 
    }

    Глава Ч. Меню и элементы управления AVVT	121 

    Список с множественным выбором несколько сложнее. Следующий код, подобно 
предыдущему, выводит текст и номера выбранных строк списка в поток System.out: 

    public void displaySelection(List list) { 
	int[] an = list.getSelectedlndexes(); 
	String[] astr = list.getSelectedltems(); 
    	for(int i=0; i<an.length; i++) 
	    System.out.println("Item #" + an[i] + :" + astr[i]);
    } 

    Методы getSelectedlndex() и getSelectedlndexes() выполняют одно и то же; 
различие между ними заключается лишь в том, что второй метод возвращает массив 
индексов. Аналогично, методы getSelectedltem() и getSelectedltems()различаются 
только тем, что последний возвращает массив строк. 
    В списках обоих типов для программного изменения выбранных элементов 
используются одни и те же методы. Метод select() имеет единственный параметр — 
индекс. При его вызове указанный элемент становится выбранным, если он еще не 
был таковым. В списке, предусматривающем выбор одной строки, вызов этого метода 
приведет к отмене ранее заданного элемента, поскольку здесь не могут 
использоваться два элемента одновременно. В списке, в котором возможен выбор 
нескольких строк, этот метод можно вызывать для каждого необходимого элемента. 
Метод deselect() отменяет выбор элемента с указанным индексом и может работать 
со списками обоих типов. Метод isSelected() сообщает о том, был ли выбран 
элемент с определенным индексом. 
    Когда несколько элементов списка имеют длину, большую, чем можно 
отобразить в отведенном прямоугольнике, то список автоматически создает полосу 
прокрутки и добавляет ее в свой интерфейс. Из программы доступно только 
ограниченное управление полосами прокрутки. Метод makeVisible() перемещает 
ползунок полосы прокрутки вверх или вниз таким образом, чтобы на экране 
отобразился элемент с указанным индексом. Это позволяет координировать 
действия списка и поля ввода. В примере 4.4 приведен текст программы, 
использующей данный метод, а на следующем рисунке показан фрагмент ее работы. 


    122 Visual J++: основы программирования 


    Пример 4.4. Координированная работа списка и поля ввода 

import java.awt.*; 
import java.util.*; 

public class CoordExample extends Frame { 
	public static void main(String astrArgs[]) { 
		CoordExample ce = new CoordExample(); 
		ce.show(); 
	}
	public  CoordExample ()    {	
		super("Coord  List  Example");                  
		m_list  = new List(); 
		m_vect  =   new Vector(); 
		m_vsTct.addElement ("Albert") ; 
		m_vect.addElement("Brian"); 
		m_vect.addElement("Chris"); 
		m_vect.addElement ("David") ; 
		m_vect.addElement("Edwin"); 
		m_vect.addElement("Frank"); 
		m_vect.addElement("Gershom"); 
		m_vect.addElement("Hank"); 
		m_vect.addElement("Igor"); 
		m_vect.addElement("Justin"); 

		// Добавление строк в список. 
		Enumeration enum = m_vect.elements(); 
		while(enum.hasMoreElements()) 
			m_list.addltem((String)enum.nextElement()); 

		// Модификация строк объекта vector. Все буквы преобразуются 
		// в строчные. 
		enum = m_vect.elements(); 
		while(enum.hasMoreElements()) 
			((String)enum.nextElement()).toLowerCase(); 

		// Список и объект vector инициализированы. 
		// Создание пользовательского интерфейса. 
		setLayout(new BorderLayout(5, 5)); 
		add("North", m_text = new TextField()); 
		add("South", m_list); 
	}
	public boolean keyUp(Event evt, int key) ( 
		if(evt.target == m_text) { 
			int i = m_vect.indexOf(m_text.getText().toLowerCase()); 
			if (-i !+ i)
			select (i) ;
		} 
		return super.keyUp(evt, key); 
	}


    Глава 4. Меню п элементы управления AVVT 123 


	public boolean handleEvent(Event evt) {
		return false; 
	}
	//Private-переменные экземпляра. 
	private TextField m_text; 
	private List m_list; 
	private Vector m_vect; 
} 

    Из этой программы не понятно одно: как обнаружить факт взаимодействия 
пользователя с элементом списка. Когда пользователь выполняет двойной щелчок 
мышью на элементе списка, объект типа List автоматически посылает сообщение о 
событии ACTION_EVENT родительскому окну списка. Когда пользователь выполняет 
одиночный щелчок мышью на элементе списка, родительское окно получает 
сообщение о событии со специальным идентификатором, зарезервированным для 
применения только в классе List,— LIST_SELECT. Таким образом, если 
пользователь выполнит двойной щелчок мышью на элементе списка, то программа 
сначала получит сообщение LIST_SELECT, а затем — сообщение ACTION_EVENT. Для 
списка с множественным выбором зарезервирован идентификатор LIST_DESELECT. 
Когда выбор одного из элементов такого списка отменяется, родительское окно 
получает сообщение о событии LIST_DESELECT. 

    Класс Choice 

    Выпадающий список похож на обычный список. Функционально они совершенно 
одинаковы. Различие состоит лишь в их внешнем виде. Выпадающий список обычно 
занимает на экране одну строку. Когда пользователь щелкает на строке, из нее 
"выпадает" (drops down) список с возможностью выбора. Список остается на 
экране до тех пор, пока имеет фокус ввода. Если элемент теряет фокус ввода, то 
список сжимается до одной строки, отображающей выбранный элемент. На рис. 4.2 
показана программа, использующая выпадающий список. Следует помнить, что 
выпадающие списки не имеют возможности множественного аыбора. 
    В Java для создания выпадающих списков используется элемент класса 
Java.awt.Choice. В классе Choice имеется только один конструктор, у которого 
нет аргументов. Обычно объект класса Choice по ширине занимает всю отведенную 
ему область экрана. Ширина объекта должна быть достаточной для размещения 
самой длинной из добавляемых в него строк. 
    В отличие от простых списков выпадающие списки включают только те методы, 
которые совершенно необходимы для управления содержимым объекта данного 
класса. Для опроса содержимого объекта используются методы addltem(), getltem() 
и countltem(). Элемент, уже добавленный в список, удалить невозможно. В этом 
случае необходимо создать совершенно новый объект типа Choice и заменить им 
существующий. 

    124	Visual J++: основы программирования 


    Рис. 4.2. Пример использования выпадающего списка 

    Для управления выбором строк из списка предназначено большее количество 
методов, чем для управления содержимым списков. Методы getSelectedlndex() и 
setSelectedItem() полностью соответствуют одноименным методам класса List. 
Имеются две перегруженные версии метода select(), позволяющие выбирать элемент 
списка как по индексу, так и по значению. В представленной ниже программе 
показано, как используются элементы класса Choice: 

    Пример 4.5. Программа, демонстрирующая применение элементов класса Choice 

import java.awt.*; 

public class ChoiceDemo extends Frame { 
	public static void main(String[] astrArgs) { 
		ChoiceDemo cd = new ChoiceDemo(); 
		cd.show(); 
	}

	public ChoiceDemo() { 
		super ("Choice Demonstration Program");
		Canvas canvRed = new Canvas(); 
		Canvas canvBlue = new Canvas(); 
		Canvas canvYellow = new Canvas(); 
		Canvas canvWhite = new Canvas(); 
		Canvas canvBlack = new Canvas(); 
		Canvas canvGreen = new Canvas(); 

    Глава 4. Меню п элементы управления AVVT 125 

		canvRed.setBackground(Color.red); 
		canvBlue.setBackground(Color.blue); 
		canvYellow.setBackground(Color.yellow); 
		canvWhite.setBackground(Color.white); 
		canvBlack.setBackground(Color.black); 
		canvGreen.setBackground(Color.green); 

		m_panelCanvases = new Panel(); 
		m_panelCanvases.setLayout(m_cardLayout = new CardLayout());
		m_panelCanvases.add("Red", canvRed); 
		m_panelCanvases.add("Blue", canvBlue); 
		m_panelCanvases.add("Yellow", canvYellow); 
		m_panelCanvases.add("White", canvWhite) 
		m_panelCanvases.add("Black", canvBlack) 
		m_panelCanvases.add("Green", canvGreen) 
	
		setLayout(new BorderLayout ()); 
		add("North", m_choice = new Choice ()); 
		add("Center", m_panelCanvases); 

		m_choice.addltern("Red"); 
		m_choice.addltem("Blue") ; 
		m_choice.addltem("Yellow"); 
		m_choice.addltem("White"); 
		m_choice.addltem("Black"); 
		m_choice.addltem("Green"); 
	}

	public boolean handleEvent(Event evt) { 
		if((evt.id == Event. ACTION__EVENT) && (evt. target == m__choice) ; 
			m_cardlayout.show(m_panelCanvases, (String)evt.arg); 
			return true; 
		} 
		return false; 
	}
	// Private-переменные экземпляра, 
	private Choice m_choice; 
	private Panel m_panelCanvases; 
	private CardLayout m_cardLayout; 
} 

    В этой программе показано, как обрабатывать выбор пользователем элементов 
списка. В момент выбора элемента генерируется событие АСTION_EVENT. При этом 
переменная target содержит ссылку на выбранный элемент. Это событие подобно 
событию, которое передается родительскому окну списка при двойном щелчке мышью 
на его элементе. 

    126 Visual J++: основы программирования 


    Создание элементов интерфейса с помошыо ResourceWizard 

    Программисты на С и C++, знакомые со средами разработки Windows SDK и 
Visual C++/MFC, без сомнения, имеют представление о диалоговых ресурсах 
(diglog resources). Они определяют интерфейс, составленный из встроенных 
оконных компонентов. 
    Visual J++ является одним из модулей среды Microsoft Developer Studio, 
поэтому здесь можно использовать встроенный редактор ресурсов. Редактор 
ресурсов предназначен для создания и изменения стандартных оконных 
компонентов. Разработчики программ для Windows уже встречались с редактором 
диалоговых окон. Экран этой программы показан на рис. 4.3. 

    Рис. 4.3. Окно редактора диалоговых окон Visual J++ 

    Visual J++ добавляет к редактору диалоговых окон утилиту ResourceWizard, 
которая позволяет преобразовать диалоговый ресурс в работающий класс Java. Это 
очень просто делается и способствует значительной экономии времени. На рис. 
4.4 показано окно апплета после того, как утилита ResourceWizard создала класс 
Dialog на основе окна, показанного на рис. 4.3. Создание интерфейса с помощью 
редактора диалоговых окон Visual J++ и утилиты ResourceWizard занимает порядка 
15 минут. Диалоговые окна, 

    Глава 4. Меню п элементы управления AVVT 127 

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

    Рис. 4.4. Использование диалогового окна в качестве интерфейса апплета 

    Чтобы создать класс Dialog, надо запустить редактор диалоговых окон Visual 
J++. Этот редактор запускается при создании нового диалогового ресурса в 
проекте Java. Используемые при этом кнопки панели инструментов показаны ниже. 
    Для открытия нового диалогового окна можно также воспользоваться командой 
New меню File. 
    Диалоговые окна можно редактировать: добавлять новые видимые элементы, 
по-разному располагать их, изменять при необходимости размеры. 

    128 Visual 1++: основы программирования 

    После редактирования диалоговому ресурсу нужно присвоить имя. Двойной 
щелчок мышью на открытой части диалогового окна в редакторе или использование 
команды Dialog меню Edit обеспечивают доступ к списку свойств диалогового 
окна. Идентификатор диалогового окна станет именем класса (хотя имеется 
возможность изменить это значение во время преобразования), а текст 
диалогового окна станет его заголовком. 
    Для сохранения файла ресурса используется команда Save меню File. Если 
этот ресурс является первым в новом файле ресурсов, последует приглашение 
ввести имя файла. Возможно, есть смысл использовать имя файла главного класса 
в проекте. В этом файле можно сохранять все ресурсы меню и диалогового окна. 
Расширением файла будет RCT. Если поле ввода "Save as type:" не содержит 
строку "Resource Template (*.rct)", следует щелкнуть на стрелке выпадающего 
списка и выбрать "Resource Template." 
    Далее необходимо преобразовать диалоговый ресурс в класс Java. После 
выбора в меню Tools команды Java ResourceWizard поступит запрос об имени файла 
шаблона ресурсов (RCT) или файла откомпилированных ресурсов (RES), в котором 
содержится описание диалоговых окон и меню, используемых в приложении. 
Определив нужный шаблон ресурсов в созданном диалоговом окне, следует нажать 
кнопку Next. ResourceWizard отобразит таблицу диалоговых окон и меню, 
определенных в шаблоне ресурсов. Предназначение этой таблицы — предоставить 
список диалоговых окон и меню, которые можно преобразовать в классы Java, и 
дать имена созданным классам. По умолчанию имя диалогового окна, создаваемого 
редактором ресурсов, будет выглядеть приблизительно так: IDD_DIALOG1. Это не 
очень удачное название для класса Java, поэтому желательно его изменить. 
Щелкните мышью на колонке ClassName и наберите желаемое название. Момент 
преобразования с помощью ResourceWizard диалогового окна в класс Java показан 
на рис. 4.5. 

    Рис. 4.5. Изменение имени класса, созданного с помощью ResourceWiiard 


    Глава 4. Меню и элементы управления AVVT 129 

    Затем ResourceWizard создаст два класса, которые необходимо добавить в 
проект,— типа Dialog и типа DialogLayout. С этой целью используется команда 
Insert to Project меню File. В проект также следует добавить файлы 
DialogLayout.java и <имя_класса>.java. (Файл DialogLayout.java записывается 
только один раз, даже в том случае, если создается несколько классов типа 
Dialog.) 
    В новом классе типа Dialog имеется конструктор с одним параметром — 
контейнером. Создайте диалоговое окно, передав конструктору ссылку на 
окно-контейнер. Для размещения элементов управления в контейнере 
воспользуйтесь методом CreateControls(). Диалоговый интерфейс появится в 
контейнере автоматически. Рассмотрим, как можно использовать класс типа 
Dialog, созданный с помощью ResourceWizard и названный MyDialog: 

	Panel p = new Panel();			//  Контейнер,   в  котором размещается 
							//  диалоговое окно. 
	MyDialog dig = new MyDialog(p);	//  Связывание  диалогового  окна   с 
							//  контейнером. 
	dlg.CreateControls();			//  Создание  элементов  управления 
							//  и размещение  их  в  контейнере. 


    Как выглядят классы, созданные ResourceWizard 

    Экран с диалоговым окном, которое было создано описанным способом, показан 
на рис. 4.6. Ниже приводится код этого диалогового окна. Если вы внимательно 
ознакомились с предыдущими примерами настоящей главы, то пример 4.6 не вызовет 
никаких вопросов. 

    Рис. 4.6. Диалоговый интерфейс, созданный при помощи Resource Wizard 


    130 Visual J++: основы программирования 


    Пример 4.6. Класс типа Dialog, созданный при помощи ResourceWizard 

public class MyDialog  { 
	Container m_Parent = null; 
	boolean m_fInitialized = false; 
	DialogLayout m_Layout; 

	// Определение элементов управления. 
	// _________________________________________________________ 
	Button	IDOK; 
	Button	IDCANCEL; 
	List	m_listNames; 
	Label	m_labelNamesl; 
	Checkbox	m_chkbxReadOnly; 
	TextField	m_tfKey; 
	TextField	m_tfVal; 
	Label	m_labelKeyVal; 

	// Конструктор. 
	// ________________________________________________________ 
	public MyDialog (Container parent) { 
		m_Parent = parent; 
	} 

	// Инициализация. 
	// _________________________________________________________ 
	public boolean CreateControls () { 
		// CreateControls надо вызвать только один раз. 
		// _____________________________________________________ 
		if (m fInitialized || m_Parent == null) 
			return false; 

		// m_Parent должен быть порожден от класса Container. 
		// _____________________________________________________ 
		if (!(m_Parent instanseof Container)) 
			return false; 
		// Поскольку не все платформы могут поддерживать данный 
		// шрифт, то безопасно будет модифицировать только 
		// размер шрифта, но не его тип. 
		// _____________________________________________________ 
		Font OldFnt = m_Parent.getFont(); 
		if (OldFnt != null) { 
			Font NewFnt = new Font(OldFnt.getNarae(), OldFnt.getStyle(),8); 
			m_Parent.setFont(NewFnt); 
		} 


    Глава 4. Меню и элементы управления AWT	131 


		// Все позиции и размеры определяются в логических 
		// элементах диалогового окна, поэтому DialogLayout 
		// используется в качестве менеджера компоновки. 
		// ______________________________________________________ 
		m_Layout = new DialogLayout(m_Parent, 310, 230); 
		m_Parent.setLayout(m_Layout); 
		m_Parent.addNotifу(); 

		Dimension size = m_Layout.getDialogSize(); 
		Insets insets = m_Parent.insets(); 

		m_Parent.resize(insets.left = size.width + insets.right, insets top + 
			size.height + insets.bottom); 

		// Создание элементов управления. 
		// _____________________________________________________ 
		IDOK = new Button ("OK"); 
		m_Parent.add(IDOK); 
		m_Layout.setShape{IDOK, 94, 195, 55, 18); 

		IDCANCEL = new Button ("CANCEL"); 
		m_Parent.add(IDCANCEL); 
		m_Layout.setShape(IDCANCEL, 161, 195, 55, 18); 

		m_listNames = new List (1, false); 
		m_Parent.add(m_listNames); 
		m_Layout.setShape(m_listNames, 17, 23, 271, 107); 

		m_labelNamesl = new Label ("Select Name:", Label.LEFT); 
		m_Parent.add(m_labelNamesl); 
		m_Layout.setShape(m_labelNamesl, 17, 7, 116, 12); 

		m_chkbxReadOnly = new Checkbox ("Read Only"); 
		m_Parent.add(m_chkbxReadOnly); 
		m_Layout.setShape(m_chkbxReadOnly, 19, 140, 69, 16); 

		m_chkbxHidden = new Checkbox ("Hidden"); 
		m_Parent.add(m_chkbxHidden) ; 
		m_Layout.setShape(m_chkbxHidden, 19, 158, 69, 16); 

		m_tfKey = new TextField (" "); 
		m_Parent.add(m_tfKey) ; 
		m_Layout.setShape(m_tfKey, 114, 145, 173, 16); 

		m_tfVal = new TextField (" "); 
		m_Parent.add(m_tfVal); 
		m_Layout.setShape(m_tfVal, 114, 167, 173, 15); 

		m_labelKeyVal = new Label("Key and Value", Label.LEFT); 
		m_Parent.add(m_labelKeyVal); 
		m_Layout.setShape(m_labelKeyVal, 116, 134, 115, 10); 

    132	Visual J++: основы программирования 


		m_fInitialized = true; 
		return true; 
	}
}

    Учтите, что ResourceWizard также сгенерировал ряд методов обработки 
событий в классе Dialog. Это очень удобно поскольку для большинства 
классов каркасный код выглядит одинаково. Не следует обижаться на скудность 
комментариев ResourceWizard, ведь слишком много программ в среде Windows 
снабжены только комментариями, созданными "мастерами" — ResourceWizard и 
AppletWizard в VJ++ и AppWizard в VC++. 

    Класс DialogLayout 

    ResourceWizard при создании класса Dialog автоматически добавляет к 
проекту класс DialogLayout. Этот класс размещает компоненты, составляющие 
интерфейс класса Dialog, таким же образом, как при создании диалогового окна в 
редакторе ресурсов. 
    Конструктору класса DialogLayout передаются размеры ограничивающего 
прямоугольника для каждого из компонентов, добавляемых в интерфейс диалога. 
Размер прямоугольника измеряется не в пикселях, а в диалоговых единицах 
(dialog units). Диалоговая единица — это масштабируемая величина, значение 
которой зависит от разрешения экрана. При более высоком разрешении диалоговая 
единица равна большему числу пикселей, при меньшем разрешении — меньшему их числу. 
    Размеры диалогового окна изменяются таким образом, что все его компоненты 
остаются видимыми для пользователя. Так, изображение диалогового ресурса, 
созданного с помощью диалогового редактора на экране с разрешением 800x600, 
при запуске программы в системе с экраном, имеющим разрешение 1200x800, 
уменьшится на 25%, следовательно, выглядеть оно будет по-другому. 
    Для решения этой проблемы предназначен класс DialogLayout. Диалоговые 
единицы масштабируются в зависимости от размеров диалогового шрифта 
(dialogfont). В любой системе диалоговый шрифт — это шрифт, используемый по 
умолчанию для отображения меток, надписей в контрольных переключателях и 
других элементах. В операционных системах, использующих окна, размер этого 
щрифта меняется в зависимости от разрешения экрана, так что для экрана с 
более высоким разрешением используется более крупный шрифт и наоборот. Ширина 
диалоговой единицы равна 1/8 средней ширины символов диалогового шрифта, а 
высота — 1/4 высоты диалогового шрифта. (В отличите от ширины, меняющейся от 
символа к символу, высота шрифта постоянна для всех символов, даже если у 
отдельных из них она разная.) 
    Теперь вы понимаете предназначение класса DialogLayout. Имея представление 
о менеджерах компоновки (о них рассказывалось в главе 3), можно также сделать 
вывод о самом большом недостатке класса DialogLayout: его компоненты не 
масштабируются в зависимости от размеров контейнера. 

    Глава 4. Меню и элементы управления AWT	133 

    Диалоговому окну в редакторе присваивается размер (в диалоговых единицах), 
и если контейнер изменит свои параметры, окно уже не будет так хорошо в нем 
выглядеть. Худшее, что может произойти, — это усечение компонентов правой или 
нижней гранью контейнера. В таком случае окно станет совершенно бесполезным. 
    Этот недостаток сводится к минимуму при использовании встроенного апплета. 
Задаваемые здесь ширина и высота определяются HTML-документом, в который 
встроен апплет. Значит, размер контейнера остается постоянным и, основываясь 
на нем, можно создавать диалоговый интерфейс. (Или, наоборот, можно определить 
размер апплета на основе размера диалогового ресурса.) 
    В классе DialogLayout размеры компонентов выражаются в диалоговых 
единицах. Необходимо лишь принять меры, чтобы апплет был несколько больше, чем 
этого требует диалоговый ресурс. Определенные трудности будут возникать только 
у тех пользователей, у кого разрешение экрана близко к экстремальному. Чтобы 
избежать и этого, необходимо для данного проекта модифицировать класс 
DialogLayout, создаваемый ResourceWizard. Это позволит оперировать не 
диалоговыми единицами, а какими-то другими, задав их в коде. 

    Меню 

    Меню, как уже было отмечено, — широко распространенный элемент GUI. Если 
вам когда-нибудь приходилось конструировать или программировать интерфейс, вы, 
несомненно, знакомы с меню. Рассмотрим приложение Java, использующее меню. 
    Меню — это список команд, представленных в порядке иерархии. Возглавляют 
иерархию команды крупных категорий. По неписанному правилу 

    134 Visual J++: основы программирования 

почти во всех меню встречаются категории File, Edit и Help. Все они 
присутствуют в приведенном меню, как и в других меню операционной системы 
Windows, созданной фирмой Microsoft. 
    Под командами, относящимися к главным категориям (располагаются в строке 
меню (menu bar)), размещаются отдельные команды или подменю. Пример главного 
меню с командами и подменю приведен на рис. 4.7. 

    Рис. 4.7. Главное меню с командами и подменю 

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

    Классы Menu. Menultem и Mervubar 

    Иерархия объектов, используемая в Java, полностью соответствует иерархии 
компонент/контейнер. В иерархии пользовательского интерфейса все элементы 
порождены от класса Component. Корневым здесь является класс MenuComponent. 
    В классах java.awt.Component и MenuComponent определены функциональные 
возможности, одинаковые для всех видимых элементов. 
    Простейший неабстрактный класс типа MenuComponent — это класс Menultem. 
Элемент меню в Java представляет простую команду. 
    В пакете AWT имеется класс Container, который может содержать ноль или 
более компонентов. Класс Menu, порожденный от класса MenuComponent, также 
содержит компоненты, включая другие меню. Используя объекты классов Menu и 
Menultem, можно создать иерархию команд и подменю в родительском меню. 
    Класс меню верхнего уровня называется Menubar. Родственные меню должны 
находиться в одном и том же главном меню. Только главное меню 

    Глава 4. Меню п элементы управления AVVT 135 

должно быть связано с объектом верхнего уровня типа Frame, что позволит 
создавать полностью укомплектованные меню с помощью AWT. Меню можно создать 
только в окне верхнего уровня, причем оно не будет включать окна, порожденные 
от класса Dialog. Чтобы содержать работающее основное меню, объект типа Frame 
должен быть окном верхнего уровня, не имеющим родительского окна. Метод 
Frame.setMenubar() связывает главное меню с окном верхнего уровня типа Frame. 
    Иерархия некоего меню показана на рис. 4.8. Здесь имеются стандартные меню 
File, Edit и Help. Код, с помощью которого такое меню может быть создано, 
приведен в примере 4.7. 

    Menubar 
       File Menu 
          New Menu Item 
          Save Menu Item 
          Save As Menultem 
          Exit Menultem 

       Edit Menu 
         Cut Menultem 
         Copy Menultem 
         Paste Menultem 
         Clear Menultem 

       Commands Menu 
         Command 1 Menultem 
         Command 2 Menultem 
         Dialog Menultem 
         Another Command Menultem 
         Subcommands Menu 
           Subcommand 1 Menultem 
           Subcommand 2 Menultem 

       Help Menu 
         Help Menultem 
         About this App Menultem 

    Рис. 4.8. Пример иерархии меню приложения 


    136 Visual J++: основы программирования 


    Пример 4.7. Создание главного меню 

public Menubar createMenu() { 
	Menubar mbar = new Menubar(); 

	// Создание меню File. 
	Menu menuFile = new Menu("File"); 
	menuFile.add(new MenulYem ("New...")); 
	menuFile.add(new Menultem ("Open...") ) ; 
	menuFile.add(new MenuItem("Save")); 
	menuFile.add(new Menultem ("Save As...")); 
	menuFile.add("-");  // Разделитель. 
	menuFile.add(new Menultem("Exit")); 

	// Создание меню Edit. 
	Menu menuEdit = new Menu("Edit"); 
	menuEdit.add(new MenuItem("Cut")); 
	menuEdit.add(new Menultem("Copy")); 
	menuEdit.add(new Menultem("Paste")); 
	menuEdit.add(new Menultem("Clear")) ; 

	// Создание меню Commands. 
	Menu menuCommands = new Menu("Commands"); 
	menuCommands.add(new Menultem("Commandl")); 
	menuCommands.add(new Menultem("Command2")); 
	menuCommands.add("-");  // Разделитель. 
	menuCommands.add (new Menultem ("Dialog Item...")); 
	menuCommands.add(new Menultem("Another Command"));
	menuCommands.add("-");  // Разделитель. 

	// Подменю меню Commands. 
	Menu menuSubCommands = new Menu("Subcommands"); 
	menuSubCommands.add(new Menultem("SubCommandl")); 
	menuSubCommands.add(new Menultem("SubCommand2")); 
	menuCommands.add(menuSubCommands)); 

	// Создание меню Help. 
	Menu menuHelp = new Menu("Help"); 
	menuHelp.add(new Menultem ("Help") ) ; 
	menuHelp.add("-");  // Разделитель. 
	menuHelg.add(new Menultem ("About this app...")); 

	// Добавление пунктов меню в главное меню, 
	mbar.add(MenuFile);
	mbar.add(ftenuEdit); 
	mbar.add(MenuCommands); 
	mbar.add(MenuHelp); 

	return mbar; 
}


    Глава И. Меню п элементы управления AWT	137 


    Класс Menu Item 

    Для объектов класса Menultem, представляющих в меню одиночные команды, 
характерны две переменные состояния: 
    •    Label. Содержит текст, отображаемый в меню. Обычно это глагол, с 
помощью которого задается простая команда (Open, Paste, Help). Для более 
сложных команд приходится создавать модальные диалоговые окна. Многоточие 
после командной метки означает, что при выборе этого пункта меню появится 
модальное диалоговое окно (как, например, после "Open...", 
"About this application..."). 
    •    isEnabled. Определяет, доступен ли пункт меню в данный момент. 
Недоступные пункты меню помечаются серым цветом. Пользователь выбрать такой 
пункт не может. 
    В классе Menultem имеется несколько методов проверки и модификации 
переменных состояния. Для изменения отображаемого в элементе меню текста 
используется метод setLabel(). Метод getLabel() возвращает строку метки, 
отображаемую в меню в данный момент. Для выяснения, доступен элемент меню или 
нет, применяется метод isEnabled(). Методы enable() и disable() устанавливают 
состояние доступности элемента меню. 
    Конструктор класса Menultem создает элемент меню и инициализирует 
переменные его внутреннего состояния. Первой версии конструктора необходимо 
передать строку метки: 

    public Menultem(String strLabel) 

    Когда пользователь выбирает доступный элемент меню, окно типа Frame 
главного меню получает сообщение о событии ACTION_EVENT. Это сообщение 
посылается при выборе элемента меню; переменная arg объекта Event содержит 
строку метки выбранного элемента. В примере 4.8 приведен код обработки событий 
меню для окна типа Frame. 

    Пример 4.8. Обработка событий меню 

public boolean action(Event evt, Object arg) { 
	if(evt.target instanceof Menultem) 
		return handleMenuAction(evt, (Menultem)evt.target, (String)arg); 
} 

public boolean handleMenuAction(Event evt, Menultem target, String strLabel) { 
	if(evt.target == m_menuitemCommandl) { 
		doCommandl(); 
		return true; 
	} e%se if(evt.target == m_menuitemCommand2) { 
		doCommand2(); 
		return true; 
	} else 
	return false;


    138	Visual J++: основы программирования 


    Класс Menu 

    Для объектов класса Menu характерны те же переменные внутреннего 
состояния, что и для объектов класса Menultem. У меню имеются метка и флаг 
доступности. Как и в классе Menultem, метку можно изменить с помощью методов 
getLabel() и setLabel(). Фактически класс Menu является порожденным от Menultem, 
поэтому здесь имеются и методы данного класса — isEnable(), enable(), disabie(). 
    Меню может служить контейнером для других меню и для элементов меню. Таким 
образом, в интерфейс класса Menu, объявленный как public, включены методы 
проверки и модификации подменю и команд, находящихся на более низкой ступени 
иерархии. С помощью метода add(), как уже упоминалось, в меню добавляют 
подменю и элементы меню. Подменю — это дочернее меню. В предыдущем примере не 
была показана версия метода add(), которая создает элементы меню следующим образом: 

    Menu menu = new Menu("Menu"); 
    menu.add("Sample Menultem");   //  Menultem создано  автоматически. 

    Интерфейс класса Menu, объявленный как public, не позволит получить ссылку 
на созданный элемент меню, когда применяется последняя версия метода add(). 
Поэтому, если такую ссылку необходимо использовать, останавливаться на 
указанной версии метода add() не стоит. 
    Метод remove() дополняет метод add(). При удалении какого-либо элемента или 
подменю необходимо указать его индекс. Значения индексов определяются порядком 
добавления элементов в меню; отсчет начинается с О, то есть первому элементу 
соответствует индекс 0, второму — 1 и т. д. Элемент можно удалить из меню и по 
ссылке на него, воспользовавшись другой версией метода remove(): 

    Menu menu = new Menu("Menu"); 
    menu.add(new Menultem("Remove Me!"); 
    menu.remove(0) ; 

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

    Menu menu = new Menu("Menu"); 
    Menultem mi = new Menultem ("Remove Me!"); 
    menu.add(mi); 
    ...
    menu.remove(mi); 


    Использование ResourceWizard пая создания классов типа Menu 

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

    Глава 1. Меню и элементы управления AWT	139 

типа Menu. Редактор ресурсов Visual J++ позволяет создавать меню 
визуально. Для этого надо выбрать команду Resource меню Insert из основного 
меню VJ++ и задать тип добавляемых ресурсов как Menu. Когда ресурс будет 
создан и сохранен, ResourceWizard создаст из него класс Menu, обеспечивая 
таким образом значительную экономию времени. Судя по предыдущим примерам меню, 
их код не так уж мал. Создание меню из ресурсов — операция гораздо более 
эффективная, чем набивание кода вручную. 
    В редакторе меню имеется диалоговое окно свойств меню, в котором можно 
задать метку и идентификатор для каждого элемента меню (хотя можно указать 
только метки меню и подменю). Идентификатор используется как 
private-переменная созданного для этого элемента меню класса. Для указания 
разделителя в меню используется опция Separator. 
    Создав меню, следует сохранить его ресурсы. В одном файле с расширением 
RCT можно хранить несколько ресурсов меню и диалоговых ресурсов, что облегчает 
управление проектом. Созданному классу необходимо дать имя с учетом 
идентификатора меню из редактора меню. Так, если для ресурса меню использовали 
идентификатор "MyMenu", то при создании класса типа Menu из ресурса меню будет 
образован файл с именем MyMenu.java, который определяет класс MyMenu. Его 
необходимо добавить в проект. Ниже показан код, созданный с помощью 
ResourceWizard для образца меню, представленного в предыдущем примере: 

    Пример 4.9. Код класса МепиВаг, созданный при помощи Resource Wizard 

public class MyMenu {       
	Frame m_Frame = null; 
	boolean m_fInitialized = false; 

	// Создание объекта MenuBar. 
	//___________________________________________________________ 
	MenuBar mb; 
	// Создание объектов Menu и 
	//			Menultem. 
	// 
	Menu ml ;	// File 
	MenuItem	m miNew;	//	New... 
	MenuItem	m miOpen;	//	Open... 
	MenuItem	m miSave;	//	Save 
	MenuItem	m miSaveAs;	//	Save As... 
	MenuIfeem	ID_FILE;	//	
	MenuItem	m miExit;	//	Exit 
	Menu m8 ;	// Edit 
	MenuItem	m miCut;	//	Cut 
	MenuItem	m mi Copy;	//	Copy 
	MenuItem	m miPaste;	//	Paste 
	MenuItem	m miClear;	//	Clear 
	Menu m13;	// Commands 
	MenuItem m_miCommand1;	//	Command1 . 


    140	Visual J++: основы программирования 


	MenuItem m_miCommand2;      // Command2. 
	Menu ml6;   // Subcommands. 
	MenuItem m_miSubCommand1;   // Subcommand1. 
	MenuItem m_miSubCommand2;   // SubCommand2. 
	Menu ml9;   			// Help 
	MenuItem m_miHelp;         // Help 
	Menultem m_miAbout;        // About this Application... 

	// Конструктор. 
	// ________________________________________________________ 
	public MyMenu (Frame frame) { 
		m_Frame = frame; 
	} 

	// Инициализация. 
	// _________________________________________________________ 
	public boolean Create Menu() {
	// Элементы управления можно инициализировать только 
	// один раз. 
	//_______________________________ 
		if (m_fInitialized || m_Frame == null) 
			return false; 
		// Создание основного меню и присоединение его 
		// к окну типа Frame. 
		//____________________________________ 
		mb = new MenuBar(); 
		m_Frame.setMenuBar(mb); 
		// Создание элементов меню и добавление их к главному меню. 
		// ________________________________________________________ 
		m1 = newMenu("File"); mb.add(ml); 
		m_miNew = new Menultem ("New...") ; 
		m1.add(m_miNew); 
		m_miOpen = new Menultem ("Open...") ; 
		m1.add(m_miOpen); 
		m_miSave = new Menultem("Save"); 
		m1.add(m_miSave); 
		m_miSaveAs = new Menultem ("Save As..."); 
		mi.add(m_miSaveAs); 
		m1.add("-"); 
		m_miExit = new Menultem("Exit"); 
		m1.add(m_miExit); 
		m8 = new Menu("Edit"); 
		mb.add(m8); 
		m_miCut = new Menultem("Cut"); 
		m8.add(m_miCut); 
		m_miCopy = new Menultem("Copy"); 
		m8.add(m miCopy); 


    Глава 4. Меню и элементы управления AWT	141 


		m_miPaste = new Menultem("Paste"); 
		m8.add(m_miPaste); 
		m_miClear = new Menultem("Clear"); 
		m8.add(m_miClear); m!3 = new Menu("Commands"); 
		mb.add(m13); 
		m_miCommandl = new Menultem("Commandl"); 
		m13.add(m_miCommandl); 
		m_miCommand2 = new Menultem("Command2"); 
		ml3.add(m_miCommand2); 
		m16 = new Menu ("Subcommands"); 
		ml3.add(ml6); 
		m_miSubCommandl = new Menultem("SubCommandl"); 
		ml6.add (m__miCommandl) ; 
		m_miSubCommand2 = new Menultem("SubCommand2"); 
		ml6.add(m_miSubCommand2); 
		ml9 = new Menu("Help"); 
		mb.add(mb9); 
		m_miHelp = new Menultem("Help"); 
		ml9.add(m_miHelp); 
		m_miAbout = new Menultem ("About this Application..."); 
		ml9.add(m_miAbout); 
		m_fInitialized = true; 
		return true; 
	} 
} 

    Заметьте, что переменным меню и подменю были присвоены стандартные имена
m1, m2 и т. д., которые несложно заменить на более подходящие им имена 
m_menuFile, mjnenuEdit и т. д. 
    При создании класса MyMenu его конструктору следует передать ссылку на 
окно типа Frame, в котором меню будет использоваться. В соответствующем месте 
программы необходимо будет вызвать метод CreateMenu() класса Menu, который 
создаст главное меню и свяжет его с окном типа Frame, как показано ниже: 

	Frame f = new Frame(); 
	MyMenu menu = new MyMenu(f); 
	menu.CreateMenu(); 


    Резюме 

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

    142	Visual J++: основы программирования 

    В пакете java.awt содержатся классы типа Component, экземплярами которых 
являются указанные стандартные элементы окон. Они, подобно другим компонентам, 
содержатся в контейнере, получают и обрабатывают сообщения, имеют границы и 
т.д. Пакет java.awt объединяет классы Label, Button, Scrollbar, Checkbox, 
List, Choice, TextField, TextArea. 
    Иерархия классов Menu/Menultem, служащих для создания меню в окне верхнего 
уровня типа Frame, аналогична иерархии классов Component/Container. Однако 
элементы меню являются гораздо более простыми объектами, чем компоненты. 
Элемент меню представляет собой метку и содержит небольшое количество 
информации о состоянии (isEnable и пр.). 
    ResourceWizard облегчает создание диалогового интерфейса и главного меню 
из ресурсов. Встроенные в VJ++ редактор диалоговых ресурсов и редактор 
ресурсов меню упрощают создание файлов с расширением RCT для диалоговых 
интерфейсов и меню. Затем ResourceWizard создает классы из этих ресурсов. 
Использовать ResourceWizard гораздо быстрее и легче, чем набирать исходные 
тексты диалоговых окон и меню. 
