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

         

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

Аплет FormLayout


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

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

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

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



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


Исходный текст аплета FormLayout практически повторяет исходный текст аплета FormDemo, рассмотренный в нашей предыдущей статье. Единственное отличие заключается в том, что в методе init мы выполнили настройку системы Layout Manager, установив режим GridLayout:

public void init() { setLayout(new GridLayout(4, 3)); . . . }

Здесь для размещения компонент в окне аплета создается таблица из четырех строк и трех столбцов.

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

Листинг 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.

Листинг 2. Файл FormLayout.tmp.html

<applet name="FormLayout" code="FormLayout" codebase= "file:/e:/sun/articles/vol7/src/FormLayout" width="500" height="600" align="Top" alt="If you had a java-enabled browser, you would see an applet here."> </applet>



Использование режима размещения 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:



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


Без указания выравнивания и зазора между компонентами

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 GridLayout( int rows, int cols);

Создание таблицы с заданным количеством строк и столбцов и с заданным зазором между компонентами

public GridLayout(int rows, int cols, int hgap, int vgap);



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


Ниже приведено краткое описание конструкторов класса BorderLayout.

public BorderLayout(); public BorderLayout(int hgap, int vgap);

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



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


Режим без зазоров

public CardLayout();

Режим с зазорами по вертикали и горизонтали между компонентами и окном контейнера

public CardLayout(int hgap, int vgap);



Методы


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();





Методы класса 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


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();



Поля


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

CENTER

Центрирование

public final static int CENTER;

LEFT

По левой границе

public final static int LEFT;

RIGHT

По правой границе

public final static int RIGHT;



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


Добавляя компоненты к контейнеру, вы должны использовать метод add с двумя параметрами, первый из которых указывает направление размещения, а второй - ссылку на добавляемый объект:

add("North", btn1); add("East", btn2); add("West", btn3); add("South", btn4); add("Center", btn5);





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


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

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

В чем трудность создания пользовательского интерфейса для мультиплатформных систем?

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

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





Режим BorderLayout


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



Режим CardLayout


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

Класс CardLayout содержит два конструктора и несколько методов.



Режим FlowLayout


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



Режим GridBagLayout


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

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

Если вы создаете аплеты для размещения в документах HTML, никто не заставляет вас ограничиваться только одним аплетом для одного документа HTML - вы можете разместить там произвольное количество аплетов, организовав взаимодействие с одной стороны, между отдельными аплетами, а с другой - между аплетами и расширениями сервера Web.

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





Режим GridLayout


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

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

Заметим, что оба параметра rows и cols не могут быть равны нулю одновременно.

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



Режимы системы Layout Manager


Прежде чем мы рассмотрим различные режимы компоновки системы Layout Manager, вспомним, как происходит наследование класса Applet (рис. 1).

Рис. 1. Наследование класса Applet

Класс Applet наследуется от класса Panel, который, в свою очередь, наследуется от класса Container и Component. Класс Container пользуется интерфейсом LayoutManager, что позволяет выбирать для контейнеров один из нескольких режимов размещения компонент в окне контейнера.

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

Ниже мы перечислили все возможные режимы системы Layout Manager:

Режим размещения компонент Описание
FlowLayout Компоненты заполняют окно контейнера "потоком" по мере их добавления методом add. Они размещаются слева направо и сверху вниз
GridLayout Компоненты размещаются в виде таблицы по мере добавления слева направо и сверху вниз. Для этой таблицы можно указать количество столбцов и строк
GridBagLayout Аналогично предыдущему, однако при добавлении компонент в таблицу можно указать координаты ячейки, в которую помещается компонента
BorderLayout При размещении компоненты указывается одно из нескольких направлений: юг, север, запад, восток, центр. Направление определяется относительно центра окна контейнера
CardLayout Размещение компонент друг над другом в одном окне. Этот режим позволяет организовать набор диалоговых панелей в виде блокнота

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

Далее на примере конкретного приложения мы рассмотрим использование перечисленных выше режимов системы Layout Manager.





Аплет Options


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

В окне аплета Options мы создали три панели (рис. 2).

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

В верхней панели отображается текстовая строка First panel. Цвет и шрифт этой строки, а также цвет фона можно задавать при помощи второй панели, расположенной в центре окна нашего аплета.

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

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

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

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





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


Для добавления компонент в панель вы должны указать, для какой панели вызывается метод 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 мы определили три поля с именами pPanel1, pCard и pControl:

FirstPanel pPanel1; CardPanel pCard; ControlPanel pControl;

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



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


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

Листинг 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

<applet name="Options" code="Options" codebase= "file:/E:/Sun/Articles/vol8/src/Options" width="500" height="600" align="Top" alt="If you had a java-enabled browser, you would see an applet here."> <hr>If your browser recognized the applet tag, you would see an applet here.<hr> </applet>



Класс CardPanel


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



Класс ControlPanel


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



Класс 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);

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



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



Метод 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 выдвигает нужную страницу на передний план с помощью метода 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 устанавливает для окна аплета режим размещения 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 в нашем аплете создается еще три класса для панелей с именами FirstPanel, CardPanel и ControlPanel.

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



Поля класса 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


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

Button btNext; Button btPrev; Button btBgColor; Button btFgColor; Button btFont;

Поле pCard хранит ссылку на панель блокнота:

Panel pCard;

Эта ссылка инициализируется конструктором класса.



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


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

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

Рис. 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.





Создание нового класса на базе класса 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.





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


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

Листинг 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; } }





Использование класса 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 создан на базе класса Frame:

class MainFrameWnd extends Frame { . . . }

В нем мы определили три поля, конструктор, методы paint, handleEvent и action.



Класс Menu


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



Класс 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 вы можете блокировать или разблокировать отдельные строки меню. Это нужно делать, например, если в данный момент функция, соответствующая строке меню, недоступна или не определена. Вы также можете изменять текстовые строки, соответствующие элементам меню, что может пригодиться для переопределения их назначения.



Класс MessageBox


Для отображения названий выбранных строк меню мы создаем диалоговую панель, определив свой класс MessageBox на базе класса Dialog, как это показано ниже:

class MessageBox extends Dialog { . . . }

В классе MessageBox есть два поля, конструктор, методы handleEvent и action.



Конструктор класса 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


Наш конструктор создает диалоговую панель с заданным сообщением внутри нее. Ссылка на строку сообщения передается конструктору через первый параметр. Остальные параметры используются конструктором базового класса 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);



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


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



Метод 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.



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


Если пользователь нажимает кнопку OK, расположенную в окне диалоговой панели, метод action вызывает для панели метод dispose, удаляя эту панель с экрана и из памяти:

if(evt.target.equals(btnOK)) { dispose(); }





Метод 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); }



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


Когда пользователь пытается закрыть окно диалоговой панели, например, сделав двойной щелчок левой клавишей мыши по системному меню или одиночный щелчок по кнопке удаления окна, возникает событие Event.WINDOW_DESTROY. Мы его обрабатываем следующим образом:

if(evt.id == Event.WINDOW_DESTROY) { dispose(); return true; } else return super.handleEvent(evt);

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



Методы


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).

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

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

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

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

Что же касается класса Window, то непосредственно этот класс редко применяется для создания окон, так как классы Frame, Dialog и FileDialog более удобны и обеспечивают все необходимые возможности.





Окна класса Frame


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



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


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

import java.awt.*;

В нашем приложении определено три класса - MenuApp, MainFrameWnd и MessageBox.



Поля


С помощью полей класса 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;



Поля класса MainFrameWnd


Поле mbMainMenuBar предназанчено для хранения ссылки на главное меню приложения, создаваемое как объект класса MenuBar:

MenuBar mbMainMenuBar;

Поля mnFile и mnHelp хранят ссылки на меню File и Help, соответственно:

Menu mnFile; Menu mnHelp;

Данные меню создаются на базе класса Menu.



Поля класса MessageBox


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

Ссылка на текстовое поле хранится в поле lbMsg, на кнопку - в поле btnOK.



Приложение MenuApp


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

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

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

Рис. 2. Меню File

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

Рис. 3. Меню Help

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

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

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





Применение класса 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


Метод addSeparator используется для добавления в меню разделительной строки. Аналогичный результат достигается и при добавлении в меню стоки "-":

mnHelp.add("-");

Заметим, что вы можете просто добавлять в меню строки по их названию, пользуясь методом add(String label), либо добавлять в меню элементы класса MenuItem, вызывая метод add(MenuItem mi).





Работа с классом 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);





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


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