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

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

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

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

Органы управления создаются как объекты классов, порожденных от класса Component (рис. 5.1). Поэтому в дальнейшем мы будем называть органы управления компонентами.

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

Класс Button позволяет создавать стандартные кнопки. Если вам нужна нестандартная кнопка (например, графическая кнопка), вы можете создать ее на базе класса Canvas.

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

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

Класс List, как нетрудно догадаться из названия, предназначен для создания списков.

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

Класс TextComponent служит базовым для двух других классов - TextField и TextArea. Первый из них предназначен для создания однострочных редакторов текста, второй - для создания многострочных редкаторов текста.

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

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

Класс Component служит в качестве базового класса для класса Container. Объекты этого класса, которые мы будем называть контейнерами, могут содержать объекты классов Component и Container. Таким образом, внутри контейнеров могут находиться компоненты и другие контейнеры.

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

Заметим, что класс Applet наследуется от класса Container через класс Panel, в котором определены методы системы Layout Manager. Настраивая соответствующим образом Layout Manager, мы можем менять стратегию размещения компонент внутри окна аплета.

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

Теперь после такого краткого введения в контейнеры и компоненты мы перейдем к описанию методов создания отдельных компонент.

Кнопки

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

public class java.awt.Button
  extends java.awt.Component
{
  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------
  public Button();
  public Button(String label);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Вызов метода createButton
  public void addNotify();

  // Получение надписи на кнопке
  public String getLabel();

  // Получение строки параметров, отражающей
  // состоние кнопки
  protected String paramString();

  // Установка надписи на кнопке
  public void setLabel(String  label);
}

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

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

Обычно аплет создает в своем окне кнопки в процессе своей инициализации при обработке метода init, например:

Button btn1;
. . .
public void init()
{
  btn1 = new Button("Button 1");
  add(btn1);
}

Здесь мы создали кнопку с надписью Button 1 и добавили ее в контейнер, которым является окно аплета, с помощью метода add.

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

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

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

Прототип метода action представлен ниже:

public boolean action(Event evt, Object obj)
{
  . . .
}

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

Как обрабатывать событие в методе action?

Прежде всего необходимо проверить, объект какого типа создал событие. Это можно сделать, например, следующим образом:

if(evt.target instanceof Button)
{
  . . .
  return true;
}
return false;

Здесь мы с помощью оператора instanceof проверяем, является ли объект, вызвавший появление события, объектом класса Button.

Далее, если в окне аплета имеется несколько кнопок, необходимо выполнить ветвление по ссылкам на объекты кнопок, как это показано ниже:

if(evt.target.equals(btn1))
{
  . . .
}
else if(evt.target.equals(btn2))
{
  . . .
}

. . .

else
{
  return false;
}
return true;

Тем из вас, кто создавал приложения Windows на языке программирования С, этот фрагмент кода может напомнить длинный переключатель switch обработки сообщений Windows.

Приложение ButtonPress

В окне приложения ButtonPress мы создаем четыре кнопки с названиями от Button 1 до Button 4. Когда пользователь нажимает на одну из кнопок, название нажатой кнопки отображается в окне аплета и в строке состояния навигатора (рис. 5.3).

Рис. 5.3. Кнопки в окне аплета ButtonPress

Обратите внимание на расположение кнопок. По мере добавления, кнопки располагаются по горизонтали справа налево и центрируются в окне аплета. Если бы ширины окна аплета не хватило для размещения четырех кнопок, не поместившиеся кнопки были бы нарисованы ниже. Такую стратегию размещения выбирает по умолчанию система Layout Manager класса Panel, от которого, как вы знаете, произошел класс Applet.

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

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

Листинг 5.1. Файл ButtonPress\ButtonPress.java

// =========================================================
// Работа с кнопками
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class ButtonPress extends Applet
{
  // Создаем четыре ссылки на объекты типа Button
  Button btn1;
  Button btn2;
  Button btn3;
  Button btn4;

  // Строка для записи названия нажатой кнопки
  String sTextLabel;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающий строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: ButtonPress\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Author: Alexandr Frolov\r\n" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Создаем четыре кнопки
    btn1 = new Button("Button 1");
    btn2 = new Button("Button 2");
    btn3 = new Button("Button 3");
    btn4 = new Button("Button 4");

    // Добавляем кнопки в контейнер, которым является
    // окно аплета
    add(btn1);
    add(btn2);
    add(btn3);
    add(btn4);

    // Название кнопки, нажатой в последний раз
    sTextLabel = new String("");
  }

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Ссылка на кнопку, от которой пришло сообщение
    Button btn;

    // Проверяем, что событие вызвано кнопкой, а не
    // другим компонентом
    if(evt.target instanceof Button)
    {
      // Получам ссылку на кнопку, вызвавшую событие
      btn = (Button)evt.target;

      // Получаем название кнопки
      sTextLabel = btn.getLabel();

      // Выполняем ветвление по кнопкам. Для каждой кнопки
      // записываем ее название 
      // в строку состояния навигатора
      if(evt.target.equals(btn1))
      {
        showStatus(
          "Button 1 (\"" + sTextLabel + "\") pressed");
      }

      else if(evt.target.equals(btn2))
      {
        showStatus(
          "Button 2 (\"" + sTextLabel + "\") pressed");
      }

      else if(evt.target.equals(btn3))
      {
        showStatus(
           "Button 3 (\"" + sTextLabel + "\") pressed");
      }
      
      else if(evt.target.equals(btn4))
      {
        showStatus(
           "Button 4 (\"" + sTextLabel + "\") pressed");
      }

      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Перерисовываем окно аплета
      repaint();

      // возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }
      
  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения желтый цвет
    g.setColor(Color.yellow);
    
    // Закрашиваем внутреннюю область окна аплета
    g.fillRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Рисуем название нажатой кнопки
    g.drawString("Button (\"" + sTextLabel + "\") pressed",
      10, 70);
  }
}

Исходный текст документа HTML, созданный для аплета ButtonPress, представлен в листинге 5.2.

Листинг 5.2. Файл ButtonPress\ButtonPress.html

<html>
<head>
<title>ButtonPress</title>
</head>
<body>
<hr>
<applet
    code=ButtonPress.class
    id=ButtonPress
    width=320
    height=240 >
</applet>
<hr>
<a href="ButtonPress.java">The source.</a>
</body>
</html>

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

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

Поля класса ButtonPress

Четыре поля класса Button с именами btn1, btn2, btn3 и btn4 предназначены для хранения ссылок на кнопки, размещенные в окне нашего аплета:

Button btn1;
Button btn2;
Button btn3;
Button btn4;

В поле sTextLabel класса String хранится строка, предназначенная для записи названия нажатой кнопки:

String sTextLabel;

Метод getAppletInfo

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

Метод init

При инициализации аплета метод init создает четыре кнопки, сохраняя ссылки на них в соответствующих полях нашего класса, а также добавляет эти кнопки в окно аплета, вызывая для этого метод add:

public void init()
{
  btn1 = new Button("Button 1");
  btn2 = new Button("Button 2");
  btn3 = new Button("Button 3");
  btn4 = new Button("Button 4");

  add(btn1);
  add(btn2);
  add(btn3);
  add(btn4);

  sTextLabel = new String("");
}

После добавления кнопок в строку sTextLabel записывается пустое значение, так как ни одна кнопка еще не была нажата.

Метод action

Метод action проверяет, является ли объект, создавший событие, кнопкой. Для этого он сравнивает ссылку на объект, передаваемую через поле evt.target, с объектом Button, пользуясь оператором instanceof. Так как поле evt.target может содержать ссылку на любой объект, способный создавать события, а не только на объект типа Button, эта проверка необходима для исключения ложных срабатываний на чужие события.

Если событие создано кнопкой, ссылка на эту кнопку сохраняется в переменной btn:

Button btn;
btn = (Button)evt.target;

При этом мы выполняем преобразование типов.

Далее метод action получает название кнопки (то есть строку, написанную на поверхности кнопки) и сохраняет его в переменной sTextLabel:

sTextLabel = btn.getLabel();

Для получения строки названия кнопки используется метод getLabel, определенный в классе Button.

Затем метод action проверяет, от какой конкретно кнопки пришло событие, выполняя ветвление с помощью оператора if - else if - else:

if(evt.target.equals(btn1))
{
  showStatus("Button 1 (\"" + sTextLabel + "\") pressed");
}

else if(evt.target.equals(btn2))
{
  showStatus("Button 2 (\"" + sTextLabel + "\") pressed");
}
. . .
else
{
  return false;
}

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

Если ваша реализация метода action не обрабатывает событие, она может передать его методу action базового класса, как это показано ниже:

super.action(evt, obj); 

В том случае, когда событие было обработано, метод action перерисовывает окно аплета, вызывая метод repaint, и затем возвращает значение true:

repaint();
return true;

Метод paint

Метод paint не содержит никакого кода для рисования кнопок, так как эта задача решается в рамках класса Button. После раскрашивания фона окна аплета и рисования рамки вокруг него, метод paint пишет название нажатой кнопки в окне аплета с помощью метода drawString:

g.drawString("Button (\"" + sTextLabel + "\") pressed",
  10, 70);

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

Аплеты Java могут создавать в своем окне переключатели двух типов: с независимой фиксацией и с зависимой фиксацией.

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

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

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

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

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

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

public class java.awt.Checkbox
  extends java.awt.Component
{
  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------
  
  // Создание переключателя с независимой фиксацией 
  // без названия
  public Checkbox();

  // Создание переключателя с независимой фиксацией 
  // и названием
  public Checkbox(String label);

  // Создание переключателя с зависимой фиксацией 
  // и названием
  public Checkbox(String label, CheckboxGroup group, 
    boolean state);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Вызов метода createCheckbox
  public void addNotify();

  // Получение группы, к которой относится
  // данный переключатель с зависимой фиксацией
  public CheckboxGroup getCheckboxGroup();

  // Получение названия переключателя
  public String getLabel();

  // Определение текущего состояния переключателя
  public boolean getState();

  // Получение строки параметров
  protected String paramString();

  // Установка группы, к которой относится
  // данный переключатель с зависимой фиксацией
  public void setCheckboxGroup(CheckboxGroup g);

  // Установка названия переключателя
  public void setLabel(String label);

  // Установка нового состояния переключателя
  public void setState(boolean state);
}

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

Checkbox rdbox1;
. . .
public void init()
{
  chbox1 = new Checkbox("Switch 1");
  add(chbox1);
}

В этом фрагменте кода мы создаем переключатель chbox1 с названием Switch 1, а затем с помощью метода add добавляем его в контейнер, которым является окно аплета.

Для определения текущего состояния переключателя вы можете использовать метод getState. Если переключатель включен, этот метод возвращает значение true, а если выключен - значение false.

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

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

public  class  java.awt.CheckboxGroup
    extends  java.lang.Object
{
  // -----------------------------------------------------
  // Конструктор
  // -----------------------------------------------------
  public CheckboxGroup();

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------
  
  // Получение ссылки на переключатель, который
  // находится во включенном состоянии
  public Checkbox getCurrent();

  // Установка указанного переключателя в группе
  // во включенное состояние
  public void setCurrent(Checkbox box);

  // Получение строки, которая представляет группу
  public String toString();
}

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

CheckboxGroup grModeGroup;
Checkbox rdbox1;
Checkbox rdbox2;
Checkbox rdbox3;
Checkbox rdbox4;
. . .
public void init()
{
  grModeGroup = new CheckboxGroup();
    
  rdbox1 = new Checkbox("Mode 1",grModeGroup, true);
  rdbox2 = new Checkbox("Mode 2",grModeGroup, false);
  rdbox3 = new Checkbox("Mode 3",grModeGroup, false);
  rdbox4 = new Checkbox("Mode 4",grModeGroup, false);

  add(rdbox1);
  add(rdbox2);
  add(rdbox3);
  add(rdbox4);
}

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

Приложение CheckBoxes

Для демонстрации методов работы с различными переключателями мы подготовили приложение CheckBoxes. Окно соответствующего аплета показано на рис. 5.4.

Рис. 5.4. Окно аплета CheckBoxes с переключателями и кнопкой

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

Одновременно может быть включен только один из переключателей Mode 1 - Mode 4, так как эти переключатели составляют группу переключателей с зависимой фиксацией. Переключатели Switch 1, Switch 2 и Switch 3 могут находиться в произвольном состоянии независимо друг от друга.

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

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

Файл исходного текста приложения CheckBoxes представлен в листинге 5.3.

Листинг 5.3. Файл CheckBoxes\CheckBoxes.java

// =========================================================
// Работа с переключателями
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class CheckBoxes extends Applet
{
  // Создаем три ссылки на объекты типа Checkbox
  Checkbox chbox1;
  Checkbox chbox2;
  Checkbox chbox3;
  
  // Создаем ссылку на объект типа CheckboxGroup
  CheckboxGroup grModeGroup;

  // Создаем четыре ссылки на объекты типа Checkbox
  Checkbox rdbox1;
  Checkbox rdbox2;
  Checkbox rdbox3;
  Checkbox rdbox4;

  // Создаем ссылку на объект типа Button
  Button btnGet;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: CheckBoxes\r\n" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "E-mail: frolov@glas.apc.org" +
      "Author: Alexandr Frolov\r\n" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Устанавливаем желтый цвет фона
    setBackground(Color.yellow);
    
    // Создаем три переключателя с независимой фиксацией
    chbox1 = new Checkbox("Switch 1");
    chbox2 = new Checkbox("Switch 2");
    chbox3 = new Checkbox("Switch 3");
    
    // Создаем группу переключателей с зависимой фиксацией
    grModeGroup = new CheckboxGroup();
    
    // Создаем четыре переключателя с зависимой фиксацией,
    // принадлежащие группе grModeGroup
    rdbox1 = new Checkbox("Mode 1",grModeGroup, true);
    rdbox2 = new Checkbox("Mode 2",grModeGroup, false);
    rdbox3 = new Checkbox("Mode 3",grModeGroup, false);
    rdbox4 = new Checkbox("Mode 4",grModeGroup, false);

    // Создаем кнопку, предназначенную для определения
    // текущего состояния переключателей
    btnGet = new Button("Get CheckBoxes state");

    // Добавляем в окно аплета четыре переключателя
    // с зависимой фиксацией
    add(rdbox1);
    add(rdbox2);
    add(rdbox3);
    add(rdbox4);

    // Добавляем в окно аплета три переключателя
    // с независимой фиксацией
    add(chbox1);
    add(chbox2);
    add(chbox3);

    // Добавляем в окно аплета кнопку
    add(btnGet);
  }

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Проверяем, что событие вызвано кнопкой, а не
    // другим компонентом
    if(evt.target instanceof Button)
    {
      // Выполняем ветвление по кнопкам. 
      if(evt.target.equals(btnGet))
      {
        showStatus("Button 1 pressed");
      }

      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Перерисовываем окно аплета
      repaint();

      // возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Строка для записи списка 
    // состояния переключателей
    String s = new String("> ");

    // Проверяем переключатели с независимой фиксацией
    if(chbox1.getState())
      s = s + chbox1.getLabel() + ", ";
    
    if(chbox2.getState())
      s = s + chbox2.getLabel() + ", ";
    
    if(chbox3.getState())
      s = s + chbox3.getLabel() + ", ";
    
    if(rdbox1.getState())
      s = s + rdbox1.getLabel();

    // Проверяем переключатели с зависимой фиксацией
    else if(rdbox2.getState())
      s = s + rdbox2.getLabel();

    else if(rdbox3.getState())
      s = s + rdbox3.getLabel();

    else if(rdbox4.getState())
      s = s + rdbox4.getLabel();

    // Рисуем строку состояния переключателей
    g.drawString(s, 10, 150);
  }
}

В листинге 5.4 вы найдете исходный текст документа HTML, который был создан системой Java Applet Wizard для нашего аплета.

Листинг 5.4. Файл CheckBoxes\CheckBoxes.html

<html>
<head>
<title>CheckBoxes</title>
</head>
<body>
<hr>
<applet
    code=CheckBoxes.class
    id=CheckBoxes
    width=320
    height=240 >
</applet>
<hr>
<a href="CheckBoxes.java">The source.</a>
</body>
</html>

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

Рассмотрим поля класса CheckBoxes и переопределенные нами методы.

Поля класса CheckBoxes

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

Ссылки на переключатели имеют тип Checkbox:

Checkbox chbox1;
Checkbox chbox2;
Checkbox chbox3;

Checkbox rdbox1;
Checkbox rdbox2;
Checkbox rdbox3;
Checkbox rdbox4;

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

CheckboxGroup grModeGroup;

Кроме того, нам потребуется ссылка на объект класса Button:

Button btnGet;

Метод getAppletInfo

Метод getAppletInfo возвращает информацию о нашем аплете.

Метод init

До сих пор для изменения цвета фона окна наших аплетов мы раскрашивали окно в желтый цвет явным образом в методе paint. Однако есть и другой способ, основанный на вызове метода setBackground:

setBackground(Color.yellow);

Дополнением к этому методу может послужить метод setForeground, с помощью которого можно установить цвет для рисования в окне.

Почему мы выбрали другой способ изменения фона окна?

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

После установки цвета фона метод init создает три переключателя с независимой фиксацией, указывая их название:

chbox1 = new Checkbox("Switch 1");
chbox2 = new Checkbox("Switch 2");
chbox3 = new Checkbox("Switch 3");

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

grModeGroup = new CheckboxGroup();

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

rdbox1 = new Checkbox("Mode 1",grModeGroup, true);
rdbox2 = new Checkbox("Mode 2",grModeGroup, false);
rdbox3 = new Checkbox("Mode 3",grModeGroup, false);
rdbox4 = new Checkbox("Mode 4",grModeGroup, false);

Затем метод init создает кнопку с названием Get CheckBoxes state, предназначенную для определения текущего состояния переключателей:

btnGet = new Button("Get CheckBoxes state");

После создания компонент они добавляются в контейнер, которым является окно аплета. Для этого используется метод add.

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

add(rdbox1);
add(rdbox2);
add(rdbox3);
add(rdbox4);

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

Далее метод init добавляет в окно аплета переключатели с независимой фиксацией и кнопку:

add(chbox1);
add(chbox2);
add(chbox3);
add(btnGet);

Метод action

Метод action обрабатывает только те события, которые вызваны кнопкой btnGet:

if(evt.target instanceof Button)
{
  if(evt.target.equals(btnGet))
    showStatus("Button 1 pressed");
  else
    return false;
  repaint();
  return true;
}

Когда пользователь нажимает кнопку, метод action выводит сообщение об этом в строку состояния навигатора и перерисывавает окно аплета. Текущее состояние кнопок определяется методом paint во время перерисовки окна.

Метод paint

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

Основная задача метода paint заключается в отображении в нижней части окна аплета списка включенных переключателей. Для формирования этой строки мы создаем объект s класса String:

String s = new String("> ");

Далее мы проверяем по очереди состояние всех переключателей с независимой фиксацией, дописывая к строке s название включенных переключателей:

if(chbox1.getState())
  s = s + chbox1.getLabel() + ", ";
if(chbox2.getState())
  s = s + chbox2.getLabel() + ", ";
if(chbox3.getState())
  s = s + chbox3.getLabel() + ", ";

Для определения текущего состояния переключателей мы вызываем метод getState. Этот метод возвращает значение true для включенного переключателя и false - для выключенного. Название переключателя легко определить с помощью метода getLabel.

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

if(rdbox1.getState())
  s = s + rdbox1.getLabel();
else if(rdbox2.getState())
  s = s + rdbox2.getLabel();
else if(rdbox3.getState())
  s = s + rdbox3.getLabel();
else if(rdbox4.getState())
  s = s + rdbox4.getLabel();

После завершения формирования строки s она отображается в окне аплета методом drawString:

g.drawString(s, 10, 150);

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

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

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

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

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

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

Рассмотрим класс Choice. Определение этого класса выглядит несложно:

public class java.awt.Choice
  extends java.awt.Component
{
  // -----------------------------------------------------
  // Конструктор
  // -----------------------------------------------------
  public Choice();

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Добавление элемента в список
  public void addItem(String item);

  // Вызов метода createChoice
  public void addNotify();

  // Определение количества элементов в списке
  public int countItems();

  // Получение строки списка по номеру соответствующего
  // ему элемента списка
  public String getItem(int index);

  // Получение номера текущего выбранного элемента 
  public int getSelectedIndex();

  // Получение строки, соответствующей текущему
  // выбранному элементу списка
  public String getSelectedItem();

  // Получение строки параметров
  protected String paramString();

  // Выбор в списке элемента по заданному номеру
  public void select(int pos);

  // Выбор в списке элемента по заданной строке
  public void select(String str);
}

Конструктор класса Choice не имеет параметров. Создание списка с его помощью не вызовет у вас никаких затруднений:

Choice chBackgroundColor;
chBackgroundColor = new Choice();

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

chBackgroundColor.addItem("Yellow");

Далее список можно добавить в окно аплета как компонент с помощью метода add:

add(chBackgroundColor);

Заметим, что список можно заполнять до или после добавления в окно аплета.

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

Когд пользователь выбирает новую строку в списке, возникает событие. Обработчик этого события, реализованный, например, переопределением метода action, может получить номер выбранной строки при помощи метода getSelectedIndex. Пример обработки такого события вы найдете в разделе “Приложение ChoiceList”.

Если вас интересует не номер выбранного элемента, а строка, связанная с выбранным элементом, воспользуйтесь методом getSelectedItem.

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

Приложение ChoiceList

В прложении ChoiceList мы создали два списка, первый из которых управляет цветом фона окна аплета, а второй - цветом изображения, то есть цветом, которым рисуется изображение в этом окне (рис. 5.7).

Рис. 5.7. Окно аплета ChoiceList, в котором создано два списка класса Choice

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

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

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

Листинг 5.5. Файл ChoiceList\ChoiceList.java

// =========================================================
// Списки типа Drop Down
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class ChoiceList extends Applet
{
  // Создаем ссылки на объекты класса Choice
  Choice chBackgroundColor;
  Choice chForegroundColor;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: ChoiceList\r\n" +
      "Author: Alexandr Frolov\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Создаем списки для выбора цвета фона и
    // цвета изображения
    chBackgroundColor = new Choice();
    chForegroundColor = new Choice();

    // Добавляем списки в окно аплета
    add(chBackgroundColor);
    add(chForegroundColor);

    // Заполняем список цвета фона
    chBackgroundColor.addItem("Yellow");
    chBackgroundColor.addItem("Green");
    chBackgroundColor.addItem("White");

    // Заполняем список цвета изображения
    chForegroundColor.addItem("Black");
    chForegroundColor.addItem("Red");
    chForegroundColor.addItem("Blue");

    // Устанавливаем цвет фона
    setBackground(Color.yellow);

    // Устанавливаем цвет изображения
    setForeground(Color.black);
  }

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Переменная для хранения ссылки на список,
    // вызвавший событие
    Choice ch;

    // Получаем ссылку на список
    ch = (Choice)evt.target;

    // Проверяем, что событие вызвано списком, а не
    // другим компонентом
    if(evt.target instanceof Choice)
    {
      // Выполняем ветвление по спискам
      
      // Список цвета фона
      if(evt.target.equals(chBackgroundColor))
      {
        // Получаем номер текущего элемента списка
        // и устанавливаем соответствующий
        // цвет фона
        if(ch.getSelectedIndex() == 0)
          setBackground(Color.yellow);
        
        else if(ch.getSelectedIndex() == 1)
          setBackground(Color.green);

        else if(ch.getSelectedIndex() == 2)
          setBackground(Color.white);
      }

      // Список цвета изображения
      else if(evt.target.equals(chForegroundColor))
      {
        // Получаем номер текущего элемента списка
        // и устанавливаем соответствующий
        // цвет изображения
        if(ch.getSelectedIndex() == 0)
          setForeground(Color.black);
        
        else if(ch.getSelectedIndex() == 1)
          setForeground(Color.red);

        else if(ch.getSelectedIndex() == 2)
          setForeground(Color.blue);
      }

      // Если событие возникло от неизвестного списка,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Перерисовываем окно аплета
      repaint();

      // возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Рисуем строку
    g.drawString("Смотри на цвет фона и текста!", 10, 50);
  }
}

Исходный текст документа HTML, созданного для нашего аплета, приведен в листинге 5.6.

Листинг 5.6. Файл ChoiceList\ChoiceList.html

<html>
<head>
<title>ChoiceList</title>
</head>
<body>
<hr>
<applet
    code=ChoiceList.class
    id=ChoiceList
    width=320
    height=240 >
</applet>
<hr>
<a href="ChoiceList.java">The source.</a>
</body>
</html>

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

Рассмотрим поля класса ChoiceList и переопределенные нами методы.

Поля класса ChoiceList

В нашем классе мы определили два поля для хранения ссылок на списки цвета фона и цвета изображения:

Choice chBackgroundColor;
Choice chForegroundColor;

Метод getAppletInfo

Метод getAppletInfo возвращает информацию об аплете ChoiceList.

Метод init

В методе init мы создаем два списка как объекты класса Choice:

chBackgroundColor = new Choice(); chForegroundColor = new Choice();

Созданные списки пока пустые, но мы можем добавить их в окно аплета, вызвав метод add:

add(chBackgroundColor);
add(chForegroundColor);

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

chBackgroundColor.addItem("Yellow");
chBackgroundColor.addItem("Green");
chBackgroundColor.addItem("White");

chForegroundColor.addItem("Black");
chForegroundColor.addItem("Red");
chForegroundColor.addItem("Blue");

Элементы, добавленные в список первыми, будут выбраны в списке по умолчанию. В нашем случае будет выбран фон желтого цвета и изображение черного цвета.

Такие же цвета мы устанавливаем для окна аплета, вызывая методы setBackground и setForeground:

setBackground(Color.yellow);
setForeground(Color.black);

Метод action

Метод action обрабатывает событие, вызванное списками, - выбор элемента из списка.

Прежде всего, метод action сохраняет ссылку на список, в котором произошел выбор, в переменной ch:

Choice ch;
ch = (Choice)evt.target;

Далее выполняется проверка факта, что событие вызванно именно списком, после чего происходит анализ, в каком именно списке сделан выбор нового элемента:

if(evt.target.equals(chBackgroundColor))
{
  if(ch.getSelectedIndex() == 0)
    setBackground(Color.yellow);
  else if(ch.getSelectedIndex() == 1)
    setBackground(Color.green);
  else if(ch.getSelectedIndex() == 2)
    setBackground(Color.white);
}
else if(evt.target.equals(chForegroundColor))
{
  if(ch.getSelectedIndex() == 0)
    setForeground(Color.black);
  else if(ch.getSelectedIndex() == 1)
    setForeground(Color.red);
  else if(ch.getSelectedIndex() == 2)
    setForeground(Color.blue);
}
else
  return false;

Обратите внимание, что мы вначале выполняем преобразование типа evt.target к классу Choice, а только затем проверяем, действительно ли событие вызвано списком. Правильно ли это?

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

Корректнее было бы вначале проверить ссылку evt.target на принаддлежность к классу Choice с помощью оператора instanceof, а только потом выполнять преобразование типов. Так мы и будем делать в следующих примерах аплетов, обрабатывающих события от различных источников.

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

Метод paint

Обработчик метода paint рисует рамку вокруг окна аплета и текстовую строку в средней части этого окна.

Dimension dimAppWndDimension = size();
g.drawRect(0, 0, 
  dimAppWndDimension.width  - 1, 
  dimAppWndDimension.height - 1);
g.drawString("Смотри на цвет фона и текста!", 10, 50);

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

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

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

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

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

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

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

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

public class java.awt.List
  extends java.awt.Component
{
  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------

  // Конструктор без параметров
  public List();

  // Конструктор, позволяющий указать количество 
  // отображаемых строк и флаг одновременного 
  // выбора нескольких элементов
  public List(int rows, boolean multipleSelections);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------
  
  // Добавление элемента в список
  public void addItem(String item);

  // Добавление элемента в список с указанием номера позиции
  public void addItem(String item, int index);

  // Вызов метода createList
  public void addNotify();

  // Переключение списка в режим, при котором возможно
  // выбирать одновременно несколько элементов
  public boolean allowsMultipleSelections();

  // Удаление из списка всех элементов
  public void clear();

  // Определение количества элементов в списке
  public int countItems();

  // Удаление элемента из заданной позиции
  public void delItem(int position);	

  // Удаление нескольких элементов
  public void delItems(int start, int end);

  // Отмена выделения элемента с заданной позицией
  public void deselect(int index);

  // Получение строки, связанной с элементом, по
  // позиции этого элемента
  public String getItem(int index);

  // Определение количества элементов, которые
  // видны в окне списка
  public int getRows();

  // Определение номера выделенного элемента
  public int getSelectedIndex();

  // Определение номеров выделенных элементов
  public int[] getSelectedIndexes();

  // Получение текстовой строки, связанной с
  // выделенным элементом
  public String getSelectedItem();

  // Получение ссылки на массив строк, связанных
  // с выделенными элементами
  public String[] getSelectedItems();	

  // Определение номера элемента массива, который
  // был сделан в последний раз выделенным
  // с помощью метода makeVisible
  public int getVisibleIndex();

  // Проверка, является ли выделенной 
  // строка с заданным номером
  public boolean isSelected(int index);

  // Выполняется свертка элементов списка таким
  // образом, чтобы элемент с заданным номером
  // стал видимым
  public void makeVisible(int index);

  // Минимальные размеры области, необходимые 
  // для отображения списка
  public Dimension minimumSize();

  // Минимальные размеры области, необходимые 
  // для отображения списка с заданным 
  // количеством строк
  public Dimension minimumSize(int rows);

  // Получение строки параметров
  protected String paramString();

  // Предпочтительные размеры области, необходимые 
  // для отображения списка
  public Dimension preferredSize();

  // Предпочтительные размеры области, необходимые 
  // для отображения списка с заданным 
  // количеством строк
  public Dimension preferredSize(int rows);
  
  // Извещение об уничтожении узла
  public void removeNotify();

  // Замещение элемента списка с заданным номером
  public void replaceItem(String newValue, int index);

  // Выделение элемента с заданным номером
  public void select(int index);

  // Установка или сброс режима одновременного
  // выделения нескольких строк
  public void setMultipleSelections(boolean v);
}

Процесс создания списка класса List несложен:

List chBackgroundColor;
chBackgroundColor = new List(6, false);

При создании списка вы передаете конструктору количество одновременно отображаемых строк и флаг разрешения одновременного выбора нескольких строк. Если значение этого флага равно true, пользователь сможет выбирать из списка одновременно несколько строк, а если false - только одну строку.

Для наполнения списка вы можете использовать уже знакомый вам метод addItem:

chBackgroundColor.addItem("Yellow");
chBackgroundColor.addItem("Green");
chBackgroundColor.addItem("White");

Список класса List добавляется к окну аплета методом add:

add(chBackgroundColor);

Кратко остановимся на нескольких методах класса List.

Если вы разрешили пользователю выбирать из списка одновременно несколько элементов, то для получения ссылки на массив выбранных элементов вам пригодятся методы getSelectedItems и getSelectedIndexes:

public String[] getSelectedItems();	
public int[] getSelectedIndexes();

С помощью метода setMultipleSelections вы можете динамически включать или выключать режим одновременного выбора нескольких элементов.

В некоторых случаях вам может пригодиться метод clear, удаляющий все элементы из списка:

public void clear();

Методика использования других методов очевидна из краткого описания класса List, приведенного в этом разделе.

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

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

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

Приложение ListBox

В окне приложения ListBox мы создали два списка класса List, первый из которых предназначен для выбора цвета фона, а второй - для выбора цвета изображения. Размер первого списка достаточен для отображения всех добавленных в него элементов. Размер второго списка специально сделан меньше, поэтому справа от него появилась полоса просмотра (рис. 5.10).

Рис. 5.10. Окно приложения ListBox

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

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

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

Файл исходных текстов приложения ListBox приведен в листинге 5.7.

Листинг 5.7. Файл ListBox\ListBox.java

// =========================================================
// Списки типа List Box
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class ListBox extends Applet
{
  // Создаем ссылки на объекты класса List
  List chBackgroundColor;
  List chForegroundColor;

  // Строки для хранения названий выбираемого цвета
  String sSelBackground = new String("Yellow");
  String sSelForeground = new String("Black");
  
  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: ListBox\r\n" +
      "Author: Alexandr Frolov\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Создаем списки для выбора цвета фона и
    // цвета изображения
    chBackgroundColor = new List(6, false);
    chForegroundColor = new List(4, false);

    // Добавляем списки в окно аплета
    add(chBackgroundColor);
    add(chForegroundColor);

    // Заполняем список цвета фона
    chBackgroundColor.addItem("Yellow");
    chBackgroundColor.addItem("Green");
    chBackgroundColor.addItem("White");
    chBackgroundColor.addItem("Black");
    chBackgroundColor.addItem("Red");
    chBackgroundColor.addItem("Blue");

    // Заполняем список цвета изображения
    chForegroundColor.addItem("Black");
    chForegroundColor.addItem("Red");
    chForegroundColor.addItem("Blue");
    chForegroundColor.addItem("Yellow");
    chForegroundColor.addItem("Green");
    chForegroundColor.addItem("White");

    // Устанавливаем цвет фона
    setBackground(Color.yellow);

    // Устанавливаем цвет изображения
    setForeground(Color.black);
  }

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Переменная для хранения ссылки на список,
    // вызвавший событие
    List ch;

    // Получаем ссылку на список
    ch = (List)evt.target;

    // Проверяем, что событие вызвано списком, а не
    // другим компонентом
    if(evt.target instanceof List)
    {
      // Выполняем ветвление по спискам
      
      // Список цвета фона
      if(evt.target.equals(chBackgroundColor))
      {
        // Получаем номер текущего элемента списка
        // и устанавливаем соответствующий
        // цвет фона
        if(ch.getSelectedIndex() == 0)
          setBackground(Color.yellow);
        
        else if(ch.getSelectedIndex() == 1)
          setBackground(Color.green);

        else if(ch.getSelectedIndex() == 2)
          setBackground(Color.white);

        else if(ch.getSelectedIndex() == 3)
          setBackground(Color.black);
        
        else if(ch.getSelectedIndex() == 4)
          setBackground(Color.red);
        
        else if(ch.getSelectedIndex() == 5)
          setBackground(Color.blue);
      }

      // Список цвета изображения
      else if(evt.target.equals(chForegroundColor))
      {
        // Получаем номер текущего элемента списка
        // и устанавливаем соответствующий
        // цвет изображения
        if(ch.getSelectedIndex() == 0)
          setForeground(Color.black);
        
        else if(ch.getSelectedIndex() == 1)
          setForeground(Color.red);

        else if(ch.getSelectedIndex() == 2)
          setForeground(Color.blue);
      
        else if(ch.getSelectedIndex() == 3)
          setForeground(Color.yellow);

        else if(ch.getSelectedIndex() == 4)
          setForeground(Color.green);
      
        else if(ch.getSelectedIndex() == 5)
          setForeground(Color.white);
      }

      // Если событие возникло от неизвестного списка,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Перерисовываем окно аплета
      repaint();

      // возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }

  // -------------------------------------------------------
  // handleEvent
  // Обработка событий
  // -------------------------------------------------------
  public boolean handleEvent(Event evt)
  {
    // Переменная для хранения ссылки на список
    List ls;
  
    // Нас интересуют события, возникающие
    // только при выделении нового элемена списка
    if(evt.id == Event.LIST_SELECT)
    {
      // Получаем ссылку на список
      ls = (List)evt.target;
      
      // Получаем текущий выделенный цвет фона
      if(evt.target.equals(chBackgroundColor))
        sSelBackground = ls.getSelectedItem();

      // Получаем текущий выделенный цвет изображения
      else if(evt.target.equals(chForegroundColor))
        sSelForeground = ls.getSelectedItem();

      // Пишем цвет фона и изображения в строке
      // состояния навигатора
      showStatus("(" + sSelBackground 
        + ", " + sSelForeground + ")");
      
      // Перерисовываем окно
      repaint();

      // Возвращаем признак того, что мы обработали
      // событие самостоятельно
      return true;
    }
    
    // Для тех событий, которые мы не обрабатываем,
    // вызываем метод handleEvent из базового класа
    else
      return super.handleEvent(evt);
  }
  
  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Рисуем строку
    g.drawString("Смотри на цвет фона и текста!", 10, 120);

    // Отображаем текущий выделенный цвет фона
    // и изображения
    g.drawString("Background:  " + sSelBackground, 10, 160);
    g.drawString("Foreground:  " + sSelForeground, 10, 190);
  }
}

Исходный текст документа HTML, в который встроен аплет ListBox, представлен в листинге 5.8.

Листинг 5.8. Файл ListBox\ListBox.html

<html>
<head>
<title>ListBox</title>
</head>
<body>
<hr>
<applet
    code=ListBox.class
    id=ListBox
    width=320
    height=240 >
</applet>
<hr>
<a href="ListBox.java">The source.</a>
</body>
</html>

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

В классе ListBox мы добавили четыре поля и переопределили несколько методов.

Поля класса ListBox

В нашем классе мы определили два поля для хранения ссылок на списки цвета фона и цвета изображения, а также две строки для хранения названий выбираемых цветов:

List chBackgroundColor;
List chForegroundColor;
String sSelBackground = new String("Yellow");
String sSelForeground = new String("Black");

Содержимое строк sSelBackground и sSelForeground изменяется в процессе выделения пользователем различных строк списков.

Метод getAppletInfo

Метод getAppletInfo возвращает информацию об аплете ListBox.

Метод init

В методе init мы создаем два списка как объекты класса List:

chBackgroundColor = new List(6, false);
chForegroundColor = new List(4, false);

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

Созданные списки добавляются в окно аплета методом add:

add(chBackgroundColor);
add(chForegroundColor);

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

chBackgroundColor.addItem("Yellow");
chBackgroundColor.addItem("Green");
chBackgroundColor.addItem("White");
chBackgroundColor.addItem("Black");
chBackgroundColor.addItem("Red");
chBackgroundColor.addItem("Blue");

chForegroundColor.addItem("Black");
chForegroundColor.addItem("Red");
chForegroundColor.addItem("Blue");
chForegroundColor.addItem("Yellow");
chForegroundColor.addItem("Green");
chForegroundColor.addItem("White");

Затем метод выбирает для фона желтый цвет, а для изображения - черный:

setBackground(Color.yellow);
setForeground(Color.black);

Метод action

Метод action обрабатывает событие, вызванное списками, - выбор элемента из списка.

Прежде всего, метод action сохраняет ссылку на список, в котором произошел выбор, в переменной ch:

List ch;
ch = (List)evt.target;

Далее выполняется проверка факта, что событие вызванно именно списоком класса List, а затем обрабатываются события, созданные списками:

if(evt.target.equals(chBackgroundColor))
{
  if(ch.getSelectedIndex() == 0)
    setBackground(Color.yellow);
  else if(ch.getSelectedIndex() == 1)
    setBackground(Color.green);
  else if(ch.getSelectedIndex() == 2)
    setBackground(Color.white);
  else if(ch.getSelectedIndex() == 3)
    setBackground(Color.black);
  else if(ch.getSelectedIndex() == 4)
    setBackground(Color.red);
  else if(ch.getSelectedIndex() == 5)
    setBackground(Color.blue);
}

else if(evt.target.equals(chForegroundColor))
{
  if(ch.getSelectedIndex() == 0)
    setForeground(Color.black);
  else if(ch.getSelectedIndex() == 1)
    setForeground(Color.red);
  else if(ch.getSelectedIndex() == 2)
    setForeground(Color.blue);
  else if(ch.getSelectedIndex() == 3)
    setForeground(Color.yellow);
  else if(ch.getSelectedIndex() == 4)
    setForeground(Color.green);
  else if(ch.getSelectedIndex() == 5)
    setForeground(Color.white);
}
else
  return false;

С помощью метода getSelectedIndex метод action определяет номер выбранного элемента списка, устанавливая соответствующим образом цвет фона или изображения. Затем метод перерисовывает окно аплета, вызывая метод repaint.

Метод handleEvent

Для того чтобы отследить выделение элементов списка, наш аплет переопределил метод handleEvent, обеспечив обработку события с идентификатором Event.LIST_SELECT.

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

Наш метод handleEvent прежде всего проверяет код события, обрабатывая только события Event.LIST_SELECT, которые создаются при выделении пользователем элементов списка:

if(evt.id == Event.LIST_SELECT)
{
  . . .
}
else
  return super.handleEvent(evt);

Если событие подлежит обработке, наш метод handleEvent получает ссылку на объект, вызвавший событие, и сохраняет ее в переменной ls типа List:

List ls;
ls = (List)evt.target;

Затем метод определяет, какой сисок создал событие, проверяя поле evt.target, а затем получает и записывает выделенную строку в переменную sSelBackground (для списка цветов фона) или sSelForeground (для списка цветов изображения):

if(evt.target.equals(chBackgroundColor))
  sSelBackground = ls.getSelectedItem();
else if(evt.target.equals(chForegroundColor))
  sSelForeground = ls.getSelectedItem();

После этого цвет фона и изображения записывается в строку состояния навигатора в формате (<цвет фона>, <цвет изображения>):

showStatus("(" + sSelBackground + ",
  " + sSelForeground + ")");

После этого метод выполняет перерисовку окна и возвращает значение true - признак того, что он обработал событие:

repaint();
return true;

Метод paint

Обработчик метода paint рисует рамку вокруг окна аплета и текстовую строку в средней части этого окна.

В нижней части окна аплета метод paint отображает выделенные в списках цвета фона и изображения:

g.drawString("Background:  " + sSelBackground, 10, 160);
g.drawString("Foreground:  " + sSelForeground, 10, 190);

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

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

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

public class java.awt.Label
  extends java.awt.Component
{
  // -----------------------------------------------------
  // Поля
  // -----------------------------------------------------

  // Способ выравнивания текстового поля
  public final static int CENTER; // центрирование
  public final static int LEFT;   // по левой границе
  public final static int RIGHT;  // по правой границе

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

  // Создание текстового поля без текста
  public Label();

  // Создание текстового поля с заданным текстом
  public Label(String label);

  // Создание текстового поля с заданным текстом
  // и заданным выравниванием
  public Label(String label, int alignment);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Вызов метода createLabel
  public void addNotify();

  // Определение текущего выравнивания текстового поля
  public int getAlignment();

  // Получение текста из поля
  public String getText();

  // Получение строки параметров
  protected String paramString();

  // Установка выравнивания текстового поля
  public void setAlignment(int alignment);

  // Запись текста в поле
  public void setText(String label);
}

Текстовое поле класса Label создается вызовом соответствующего конструктора. Например, ниже мы создали текстовое поле, указав строку, которую надо в него записать:

Label lbTextLabel;
lbTextLabel = new Label("Выберите выравнивание");

С помощью метода add вы можете добавить текстовое поле в окно аплета:

add(lbTextLabel);

Метод setAlignment позволяет при необходимости изменить выравнивание текста. Способ выравнивания необходимо указать через единственный параметр метода:

lbTextLabel.setAlignment(Label.LEFT);

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

Приложение TextLabel

В окне приложения TextLabel, демонстрирующего способы работы с полями класса Label, мы разместили одно такое поле и три кнопки, позволяющие изменять выравнивание текста в поле (рис. 5.11).

Рис. 5.11. Окно приложения TextLabel

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

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

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

Листинг 5.9. Файл TextLabel\TextLabel.java

// =========================================================
// Работа с компонентами Label
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class TextLabel extends Applet
{
  // Создаем ссылку на объекты типа Label
  Label lbTextLabel;

  // Создаем три ссылки на объекты типа Button
  Button btnLeft;
  Button btnCenter;
  Button btnRight;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: TextLabel\r\n" +
      "Author: Alexandr Frolov\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Создаем компоненту Label
    lbTextLabel = new Label("Выберите выравнивание");

    // Создаем три кнопки
    btnLeft   = new Button("Влево");
    btnCenter = new Button("Центровка");
    btnRight  = new Button("Вправо");

    // Добавляем три кнопки
    add(btnLeft);
    add(btnCenter);
    add(btnRight);

    // Добавляем компоненту Label
    add(lbTextLabel);

    // Устанавливаем цвет фона
    setBackground(Color.yellow);
}

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Ссылка на кнопку, от которой пришло сообщение
    Button btn;

    // Проверяем, что событие вызвано кнопкой, а не
    // другим компонентом
    if(evt.target instanceof Button)
    {
      // Получам ссылку на кнопку, вызвавшую событие
      btn = (Button)evt.target;

      // Выполняем ветвление по кнопкам
      if(evt.target.equals(btnLeft))
      {
        // Выравниваем текст компоненты Label 
        // по левой границе
        lbTextLabel.setAlignment(Label.LEFT);
      }

      else if(evt.target.equals(btnCenter))
      {
        // Центруем текст компоненты Label 
        lbTextLabel.setAlignment(Label.CENTER);
      }

      else if(evt.target.equals(btnRight))
      {
        // Выравниваем текст компоненты Label 
        // по правой границе
        lbTextLabel.setAlignment(Label.RIGHT);
      }
      
      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }
      
  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);
  }
}

Исходный текст документа HTML, созданного для размещения аплета, представлен в листинге 5.10.

Листинг 5.10. Файл TextLabel\TextLabel.html

<html>
<head>
<title>TextLabel</title>
</head>
<body>
<hr>
<applet
    code=TextLabel.class
    id=TextLabel
    width=320
    height=240 >
</applet>
<hr>
<a href="TextLabel.java">The source.</a>
</body>
</html>

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

В классе TextLabel мы определили четыре поля и несколько методов.

Поля класса TextLabel

Мы определили четыре поля - lbTextLabel, btnLeft, btnCenter и btnRight:

Label lbTextLabel;
Button btnLeft;
Button btnCenter;
Button btnRight;

Первое из них предназначено для хранения ссылки на объект класса Label (однострочное текстовое поле), остальные три - для хранения ссылок на кнопки, определяющие выравнивание.

Метод getAppletInfo

Метод getAppletInfo возвращает информацию о нашем аплете.

Метод init

Метод init создает одно текстовое поле, вызывая конструктор с одним параметром - текстовой строкой:

lbTextLabel = new Label("Выберите выравнивание");

Далее этот метод создает три кнопки, с помощью которых вы будете изменять выравнивание текста в поле класса Label:

btnLeft   = new Button("Влево");
btnCenter = new Button("Центровка");
btnRight  = new Button("Вправо");

Затем созданные кнопки и поле добавляются в окно аплета при помощи метода add:

add(btnLeft);
add(btnCenter);
add(btnRight);
add(lbTextLabel);

Последнее, что делает метод init перед возвращением управления, это изменение цвета фона:

setBackground(Color.yellow);

Метод action

Наш метод action обрабатывает только те события, которые вызваны кнопками. Проверка источника события выполняется так же, как и раньше, поэтому мы не будем на этом останавливаться.

Что же касается установки выравнивания, то она выполняется при помощи метода setAlignment:

if(evt.target.equals(btnLeft))
  lbTextLabel.setAlignment(Label.LEFT);
else if(evt.target.equals(btnCenter))
  lbTextLabel.setAlignment(Label.CENTER);
else if(evt.target.equals(btnRight))
  lbTextLabel.setAlignment(Label.RIGHT);
else
  return false;

Метод paint

Единственное, что делает метод paint, - это рисование рамки черного цвета вокруг окна аплета.

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

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

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

public class java.awt.TextField
  extends java.awt.TextComponent
{
  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------

  // Создание поля без текста
  public TextField();

  // Создание поля без текста с заданной шириной
  public TextField(int cols);

  // Создание поля и инициализация его текстом
  public TextField(String text);

  // Создание поля заданной ширины 
  // и инициализация его текстом
  public TextField(String text, int cols);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Вызов метода createTextField
  public void addNotify();

  // Проверка, установлен ли для поля эхо-символ
  public boolean echoCharIsSet();

  // Определение размера поля
  public int getColumns();

  // Получение текущего эхо-символа
  public char getEchoChar();

  // Определение минимальных размеров области
  // для отображения поля
  public Dimension minimumSize();

  // Определение минимальных размеров области
  // для отображения поля заданной ширины
  public Dimension minimumSize(int cols);

  // Получение строки параметров
  protected String paramString();

  // Определение оптимальных размеров области
  // для отображения поля
  public Dimension preferredSize();

  // Определение оптимальных размеров области
  // для отображения поля заданной ширины
  public Dimension preferredSize(int cols);

  // Установка эхо-символа для отображения в поле
  public void setEchoCharacter(char c);
}

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

Вот фрагмент кода, в котором создается поле с текстом, имеющее ширину, достаточную для размещения 35 символов:

TextField txt;
txt = new TextField("Введите строку текста", 35);

Созданное поле добавляется в окно аплета методом add.

Большинство самых полезнных методов, необходимых для работы с полем класса TextField, определено в классе TextComponent, краткое описание которого мы привели ниже:

public class java.awt.TextComponent
  extends java.awt.Component
{
  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Получение текста, выделенного пользователем
  // в окне поля
  public String getSelectedText();

  // Получение позиции конца выделенной области 
  public int getSelectionEnd();

  // Получение позиции начала выделенной области 
  public int getSelectionStart();

  // Получение полного текста из поля
  public String getText();

  // Проверка, возможно ли редактирование 
  // текста в поле
  public boolean isEditable();

  // Получение строки параметров
  protected String paramString();

  // Удаление извещения
  public void removeNotify();

  // Выделение заданной области текста
  public void select(int selStart, int selEnd);

  // Выделение всего текста
  public void selectAll();

  // Включение или выключение возможности
  // редактирования текста
  public void setEditable(boolean t);

  // Установка текста в поле
  public void setText(String t);
}

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

Приложение может выделить любой фрагмент текста или весь текст при помощи методов select и selectAll, соответственно.

Для записи текста в поле приложение может воспользоваться методом setText.

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

Приложение TxtField

В приложении TxtField мы создали однострочное поле редактирования на базе класса TextField и кнопку, с помощью которой можно извлечь текст из поля для отображения (рис. 5.12).

Рис. 5.12. Окно аплета TxtField

Изменив текст в поле редактирования, нажмите кнопку “Получить строку”. В нижней части окна аплета вы увидите измененный вами текст.

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

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

Листинг 5.11. Файл TxtField\TxtField.java

// =========================================================
// Однострочное текстовое поле класса TextField
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class TxtField extends Applet
{
  // Создаем ссылку на объекты типа TextField
  TextField txt;

  // Создаем ссылку на объекты типа Button
  Button btnGetText;

  // Строка для хранения введенных данных
  String str;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: TxtField\r\n" +
      "Author: Alexandr Frolov\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Создаем редактируемое однострочное текстовое поле
    txt = new TextField("Введите строку текста", 35);

    // Создаем кнопку, с помощью которой можно получить
    // содержимое текстового поля
    btnGetText = new Button("Получить строку");

    // Добавляем текстовое поле в окно аплете
    add(txt);
    
    // Добавляем кнопку в окно аплете
    add(btnGetText);

    // Получаем и сохраняем текущий текст,
    // установленный в поле
    str = txt.getText();

    // Устанавливаем цвет фона
    setBackground(Color.yellow);
  }

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Ссылка на кнопку, от которой пришло сообщение
    Button btn;

    // Проверяем, что событие вызвано кнопкой, а не
    // другим компонентом
    if(evt.target instanceof Button)
    {
      // Получам ссылку на кнопку, вызвавшую событие
      btn = (Button)evt.target;

      // Проверяем ссылку на кнопку
      if(evt.target.equals(btnGetText))
      {
        // Получаем и сохраняем текущий текст,
        // установленный в поле
        str = txt.getText();

        // Перерисовываем окно аплета
        repaint();
      }

      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }
      
  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Рисуем строку, полученную из текстового поля
    g.drawString("> " + str, 10, 100);
  }
}

Документ HTML, созданный для нашего аплета, представлен в листинге 5.12.

Листинг 5.12. Файл TxtField\TxtField.html

<html>
<head>
<title>TxtField</title>
</head>
<body>
<hr>
<applet
    code=TxtField.class
    id=TxtField
    width=320
    height=240 >
</applet>
<hr>
<a href="TxtField.java">The source.</a>
</body>
</html>

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

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

Поля класса TxtField

В поле txt хранится ссылка на объект класса TextField - наше однострочное поле редактирования:

TextField txt;

В полях btnGetText и str хрянятся, соответственно, ссылки на кнопку и текстовую строку, в которую записывается текущее содержимое поля редактирования:

Button btnGetText;
String str;

Метод getAppletInfo

Метод getAppletInfo возвращает информацию о нашем аплете.

Метод init

Метод init создает одно текстовое поле редактирования, вызывая конструктор с параметром в виде текстовой строки:

txt = new TextField("Введите строку текста", 35);

Далее этот метод создает кнопку, с помощью которой можно получить текущее содержимое поля редактирования:

btnGetText = new Button("Получить строку");

Затем созданные поле и кнопка добавляются в окно аплета при помощи метода add:

add(txt);
add(btnGetText);

После этого метод init получает текущее содержимое поля редактирования и записывает его в строку str:

str = txt.getText();

В завершении метод init изменяет цвет фона:

setBackground(Color.yellow);

Метод action

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

Обработка заключается в извлечении текста из поля редактирования и записи его в строку str:

str = txt.getText();
repaint();

Метод paint

После рисования рамки черного цвета вокруг окна аплета метод paint отобаржает текущее содержимое строки str в нижней части окна:

g.drawString("> " + str, 10, 100);

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

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

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

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

public class java.awt.TextArea
  extends java.awt.TextComponent
{
  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------
  
  // Создание поля без текста и без указания размеров
  public TextArea();

  // Создание поля без текста с указанием размеров
  public TextArea(int rows, int cols);

  // Создание поля с текстом без указания размеров
  public TextArea(String text);

  // Создание поля с текстом и с указанием размеров
  public TextArea(String text, int rows, int cols);

  // -----------------------------------------------------
  // Методы
  // -----------------------------------------------------

  // Вызов метода createTextArea
  public void addNotify();

  // Добавление текста в поле редактирования
  public void appendText(String str);

  // Определение количества столбцов поля
  public int getColumns();

  // Определение количества строк поля
  public int getRows();

  // Добавление текста в поле редактирования
  // начиная с заданной позиции
  public void insertText(String str, int pos);

  // Определение минимальных размеров области
  // для размещения многострочного текстового поля
  public Dimension minimumSize();

  // Определение минимальных размеров области
  // для размещения многострочного текстового поля
  // с заданным количеством строк и столбцов
  public Dimension minimumSize(int rows, int cols);

  // Получение строки параметров
  protected String paramString();

  // Определение предпочтительных размеров области
  // для размещения многострочного текстового поля
  public Dimension preferredSize();

  // Определение предпочтительных размеров области
  // для размещения многострочного текстового поля
  // с заданным количеством строк и столбцов
  public Dimension preferredSize(int rows, int cols);

  // Замещение блока текста, начиная с первой позиции
  // и до второй позиции
  public void replaceText(String str, int start, int end);
}

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

TextArea txt;
txt = new TextArea("Введите строку текста", 5, 35);

Созданное поле добавляется в окно аплета методом add.

Отметим, что в классе TextArea есть методы для работы с блоками текста (вставка и замена), а также методы, с помощью которых можно определить количество строк и столбцов в поле редактирования.

Приложение TextEdit

Приложение TextEdit (рис. 5.13) демонстрирует некоторые приемы работы с многострочным полем редактирования текста, созданным на базе класса TextArea.

Рис. 5.13. Окно приложения TextEdit

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

Если же нажать кнопку “Получить выделенное”, в нижней части появится только выделенный фрагмент текста (как это показано на рис. 5.13).

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

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

Листинг 5.13. Файл TextEdit\TextEdit.java

// =========================================================
// Многострочное текстовое поле класса TextArea
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.applet.*;
import java.awt.*;

public class TextEdit extends Applet
{
  // Создаем ссылку на объект типа TextArea
  TextArea txt;

  // Создаем ссылку на объекты типа Button
  Button btnGetText;
  Button btnGetSelectedText;

  String str;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: TextEdit\r\n" +
      "Author: Alexandr Frolov\r\n" +
      "E-mail: frolov@glas.apc.org" +
      "WWW:    http://www.glasnet.ru/~frolov" +
      "Created with Microsoft Visual J++ Version 1.0";
  }

  // -------------------------------------------------------
  // init
  // Метод, получающий управление при инициализации аплета
  // -------------------------------------------------------
  public void init()
  {
    // Создаем редактируемое многострочное текстовое поле
    txt = new TextArea("Введите строку текста", 5, 35);

    // Создаем кнопку, с помощью которой можно получить
    // полное содержимое текстового поля
    btnGetText = new Button("Получить все");

    // Создаем кнопку, с помощью которой можно получить
    // содержимое выделенной области текстового поля
    btnGetSelectedText = new Button("Получить выделенное");

    // Добавляем текстовое поле в окно аплете
    add(txt);
    
    // Добавляем кнопки в окно аплете
    add(btnGetText);
    add(btnGetSelectedText);

    // Получаем и сохраняем текущий текст,
    // установленный в поле
    str = txt.getText();

    // Устанавливаем цвет фона
    setBackground(Color.yellow);
  }

  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Ссылка на кнопку, от которой пришло сообщение
    Button btn;

    // Проверяем, что событие вызвано кнопкой, а не
    // другим компонентом
    if(evt.target instanceof Button)
    {
      // Получам ссылку на кнопку, вызвавшую событие
      btn = (Button)evt.target;

      // Проверяем ссылку на кнопку
      if(evt.target.equals(btnGetText))
      {
        // Получаем и сохраняем текущий текст,
        // установленный в поле
        str = txt.getText();

        // Перерисовываем окно аплета
        repaint();
      }

      else if(evt.target.equals(btnGetSelectedText))
      {
        // Получаем и сохраняем выделенную область
        str = txt.getSelectedText();

        // Перерисовываем окно аплета
        repaint();
      }
      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
      {
        return false;
      }

      // Возвращаем признак того, что мы обработали событие
      return true;
    }

    // Если событие вызвано не кнопкой, 
    // мы его не обрабатываем
    return false;
  }
      
  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Определяем текущие размеры окна аплета
    Dimension dimAppWndDimension = size();
    
    // Выбираем в контекст отображения черный цвет
    g.setColor(Color.black);

    // Рисуем рамку вокруг окна аплета
    g.drawRect(0, 0, 
      dimAppWndDimension.width  - 1, 
      dimAppWndDimension.height - 1);

    // Рисуем строку, полученную из текстового поля
    g.drawString("> " + str, 10, 150);
  }
}

Исходный текст документа HTML, созданного для аплета, приведен в листинге 5.14.

Листинг 5.14. Файл TextEdit\TextEdit.html

<html>
<head>
<title>TextEdit</title>
</head>
<body>
<hr>
<applet
    code=TextEdit.class
    id=TextEdit
    width=320
    height=240 >
</applet>
<hr>
<a href="TextEdit.java">The source.</a>
</body>
</html>

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

В классе TextEdit мы определили четыре поля и несколько методов.

Поля класса TxtField

В поле txt хранится ссылка на объект класса TextArea - многострочное поле редактирования:

TextArea txt;

В полях btnGetText, btnGetSelectedText и str хрянятся, соответственно, ссылки на кнопки и текстовую строку, в которую записывается текущее содержимое поля редактирования:

Button btnGetText;
Button btnGetSelectedText;
String str;

Метод getAppletInfo

Метод getAppletInfo возвращает информацию о нашем аплете.

Метод init

Метод init создает одно текстовое поле редактирования, вызывая конструктор следующего вида:

txt = new TextArea("Введите строку текста", 5, 35);

Здесь создается поле из 5 строк и 35 столбцов.

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

btnGetText = new Button("Получить все");
btnGetSelectedText = new Button("Получить выделенное");

Затем созданные поле и кнопки добавляются в окно аплета при помощи метода add:

add(txt);
add(btnGetText);
add(btnGetSelectedText);

После этого метод init получает текущее содержимое поля редактирования и записывает его в строку str, а затем изменяет цвет фона:

str = txt.getText();
setBackground(Color.yellow);

Метод action

Наш метод action обрабатывает только те события, которые вызваны кнопками.

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

if(evt.target.equals(btnGetText))
{
  str = txt.getText();
  repaint();
}
else if(evt.target.equals(btnGetSelectedText))
{
  str = txt.getSelectedText();
  repaint();
}
else
  return false;

Для извлечения всего текста мы вызываем метод getText, а для извлечения выделенного фрагмента - метод getSelectedText.

После записи извлеченного текста метод action перерисовывает окно аплета, вызывая метод repaint.

Метод paint

После рисования рамки черного цвета вокруг окна аплета метод paint отобаржает текущее содержимое строки str в нижней части окна:

g.drawString("> " + str, 10, 100);