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

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

В составе библиотеки классов AWT имеется несколько классов, предназначенных для работы с окнами. Это класс Window, который произошел от класса Container, и его дочерние классы - Frame, Dialog и FileDialog (рис. 8.1).

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

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

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

Класс FileDialog предназначен для создания диалоговых панелей, с помощью которых можно выбирать файлы на локальных дисках компьютера. Так как аплеты не могут работать с файлами, в этой книге мы не будем рассматривать класс FileDialog. Информацию о том, как работать с файлами в приложениях Java, а также сведения об этом классе мы планируем включить в следующий том “Библиотеки системного программиста”, посвященный системе разработки Microsoft Visual J++.

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

Окна класса Frame

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

public class java.awt.Frame
  extends java.awt.Window 
  implements java.awt.MenuContainer
{
  // -----------------------------------------------------
  // Поля
  // -----------------------------------------------------

  // Различные типы курсоров
  public final static int CROSSHAIR_CURSOR;
  public final static int DEFAULT_CURSOR;
  public final static int E_RESIZE_CURSOR;
  public final static int HAND_CURSOR;
  public final static int MOVE_CURSOR;
  public final static int N_RESIZE_CURSOR;
  public final static int NE_RESIZE_CURSOR;
  public final static int NW_RESIZE_CURSOR;
  public final static int S_RESIZE_CURSOR;
  public final static int SE_RESIZE_CURSOR;
  public final static int SW_RESIZE_CURSOR;
  public final static int TEXT_CURSOR;
  public final static int W_RESIZE_CURSOR;
  public final static int WAIT_CURSOR;

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

  // Создание окна без заголовка
  public Frame();

  // Создание окна с заголовоком
  public Frame(String title);

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

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

  // Удаление окна и освобождение связанных с ним ресурсов
  public void dispose();	

  // Определение типа курсора
  public int getCursorType();

  // Получение пиктограммы, установленной для окна
  public Image getIconImage();

  // Получение ссылки на главное меню
  public MenuBar getMenuBar();

  // Получение заголовка окна
  public String getTitle();

  // Определение возможности изменения 
  // размеров окна пользователем
  public boolean isResizable();

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

  // Удаление компоненты меню
  public void remove(MenuComponent m);

  // Установка типа курсора
  public void setCursor(int cursorType);

  // Установка пиктограммы
  public void setIconImage(Image image);

  // Установка главного меню
  public void setMenuBar(MenuBar mb);

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

  // Установка заголовка окна
  public void setTitle(String title);
}

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

class MainFrameWnd extends Frame
{
  . . .
  public MainFrameWnd(String sTitle)
  {
    super(sTitle);
     . . .
    resize(400, 200);
  }
  . . .
}

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

Обратите также внимание на вызов метода resize. Этот вызов необходим для задания размеров окна.

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

При создании окна классов Frame и Dialog для них устанавливается режим размещения BorderLayout. Если вам нужен другой режим размещения, необходимо установить его явным образом.

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

Убрать окно с экрана вы можете методом hide. Этот метод прячет окно, но оставляет в памяти все связанные с ним ресурсы, поэтому вы сможете вновь отобразить спрятанное окно, вызвав метод show.

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

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

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

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

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

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

public class java.awt.MenuBar
  extends java.awt.MenuComponent
  implements java.awt.MenuContainer
{
  // -----------------------------------------------------
  // Конструктор
  // -----------------------------------------------------
  public MenuBar();

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

  // Добавление меню в главное меню окна
  public Menu add(Menu m);

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

  // Определение количества меню, добавленных
  // в главное меню
  public int countMenus();

  // Получение ссылки на меню Help
  public Menu getHelpMenu();

  // Получение ссылки на меню с заданным номером
  public Menu getMenu(int i);

  // Удаление меню с заданным номером из главного меню
  public void remove(int index);

  // Удаление компоненты меню
  public void remove(MenuComponent m);

  // Извещение об удалении меню
  public void removeNotify();

  // Установка меню Help
  public void setHelpMenu(Menu m);
}

Для формирования главного меню окна вы должны создать объект класса MenuBar с помощью конструктора, а затем добавить в него отдельные меню.

Объект главного меню создается следующим образом:

MenuBar mbMainMenuBar;
mbMainMenuBar = new MenuBar();

Отдельные меню создаются на базе класса Menu, например:

Menu mnFile;
Menu mnHelp;
mnFile = new Menu("File");
mnHelp = new Menu("Help"); 

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

mnFile.add("New");       
mnFile.add("-");         
mnFile.add("Exit");      
  
mnHelp.add("Content");   
mnHelp.add("-");         
mnHelp.add("About");    

Далее сформированные меню добавляются в главное меню:

mbMainMenuBar.add(mnFile);
mbMainMenuBar.add(mnHelp);

И, наконец, теперь можно устанавливать главное меню в окне класса, созданного на базе класса Frame:

setMenuBar(mbMainMenuBar);

Классы Menu и MenuItem

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

public class java.awt.Menu
  extends java.awt.MenuItem 
  implements java.awt.MenuContainer 
{
  // -----------------------------------------------------
  // Конструкторы
  // -----------------------------------------------------

  // Создание меню с заданным названием
  public Menu(String label);

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

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

  // Добавление элемента меню
  public MenuItem add(MenuItem mi);

  // Добавление строки в меню
  public void add(String label);

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

  // Добавление разделителя в меню
  public void addSeparator();

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

  // Получение ссылки на элемент меню с заданным номером
  public MenuItem getItem(int index);

  // Проверка, остается ли меню на экране после того как
  // пользователь отпустил клавишу мыши
  public boolean isTearOff();

  // Удаление заданного элемента меню
  public void remove(int index);

  // Удаление заданной компоненты меню
  public void remove(MenuComponent item);

  // Извещение об удалении меню
  public void removeNotify();
}

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

mnHelp.add("-");         

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

Класс MenuItem определяет поведение отдельных элементов меню:

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

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

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

  // Блокирование элемента меню
  public void disable();

  // Разблокирование элемента меню
  public void enable();

  // Блокирование или разблокирование элемента меню
  public void enable(boolean cond);

  // Получение текстовой строки меню
  public String getLabel();

  // Проверка, является ли элемент меню заблокированным
  public boolean isEnabled();

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

  // Установка текстовой строки для элемента меню
  public void setLabel(String label);
}

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

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

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

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

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

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

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

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

  // Получение строки заголовка диалоговой панели
  public String getTitle();

  // Определение, является ли диалоговая панель модальной
  public boolean isModal();

  // Определение возможности изменения размеров окна
  // диалоговой панели
  public boolean isResizable();

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

  // Включение или выключение возможности изменения
  // размеров окна диалоговой панели
  public void setResizable(boolean resizable);

  // Установка заголовка диалоговой панели
  public void setTitle(String title);
}

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

class MessageBox extends Dialog
{
  . . .
  public MessageBox(String sMsg, 
    Frame  parent, String  sTitle, boolean  modal)
  {
   super(parent, sTitle, modal);
   . . .
   resize(200, 100);
   . . .
  }
}

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

Для окон класса Dialog устанавливается режим размещения BorderLayout. Если нужен другой режим размещения, необходимо установить его явным образом методом setLayout.

Для отображения окна диалоговой панели необходимо вызвать метод show. Чтобы спрятать диалоговой окно, применяйте метод hide. Метод dispose удаляет окно диалоговой панели окончательно и освобождает все связанные с ним ресурсы.

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

Приложение FrameWnd

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

В окне аплета FrameWnd расположены две кнопки с названиями Show Frame Window и Hide Frame Window. Первая из них предназначена для отображения окна Main Frame Window, а вторая - для его временного удаления (скрытия).

В окне Main Frame Window мы создали главное меню, содержащее меню File и Help. При выборе любой строки из этого меню, кроме строки Exit меню File, на экране появляется окно диалоговой панели Dialog from Frame с названием выбранной строки меню (рис. 8.2).

Рис. 8.2. Окно и диалоговая панель, создаваемая аплетом FrameWnd

Помимо меню, в окне Main Frame Window находится кнопка OK, нажатие на которую вызывает удаление окна. Кроме того, в нижней части окна отображается строка “Окно класса Frame”.

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

Обратите также внимание на то, что в самой нижней части окно Main Frame Window и Dialog from Frame находится предупреждающее сообщение “Warning: Applet Window”. Это предупреждение пользователю, что данное окно или диалоговая панель выведена не локальным приложением, запущенным на компьютере пользователя, а аплетом, загруженным из сети. Пользователь должен понимать, что данные, введенные им в окнах, созданных аплетами, передаются по сети и могут оказаться доступной кому угодно. Поэтому он не должен вводить конфиденциальную информацию, например, номера своих кредитных карточек.

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

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

Листинг 8.1. Файл FrameWnd\FrameWnd.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.*;

// =========================================================
// Класс FrameWnd
// Это наш аплет
// =========================================================
public class FrameWnd extends Applet
{
  // Окно, которое будет возникать из аплета
  MainFrameWnd fMainFrame;
  
  // Кнопка для отображения окна fMainFrame
  Button btnShowFrame;

  // Кнопка для удаления окна fMainFrame
  Button btnHideFrame;

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: FrameWnd\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()
  {
    // Создаем новое окно на базе класса MainFrameWnd
    fMainFrame = new MainFrameWnd("Main Frame Window");

    // Создаем кнопку для отображения этого окна
    btnShowFrame = new Button("Show Frame Window");
    
    // Добавляем кнопку в окно аплета
    add(btnShowFrame);
    
    // Создаем кнопку для удаления окна fMainFrame 
    btnHideFrame = new Button("Hide Frame Window");

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

  // -------------------------------------------------------
  // destroy
  // Метод, получающий управление при завершении
  // работы аплета
  // -------------------------------------------------------
  public void destroy()
  {
    // Удаляем окно fMainFrame и освобождаем все связанные
    // с ним ресурсы
    fMainFrame.dispose();
  }

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

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

      // Если нажата кнопка отображения окна fMainFrame,
      // показываем его с помощью метода show
      if(evt.target.equals(btnShowFrame))
      {
        fMainFrame.show();
      }

      // Если нажата кнопка удаления окна fMainFrame,
      // удаляем его с помощью метода hide
      else if(evt.target.equals(btnHideFrame))
      {
        fMainFrame.hide();
      }
      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
        return false;

      return true;
    }

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

// =========================================================
// Класс MainFrameWnd
// На базе этого класса создается окно с меню
// =========================================================
class MainFrameWnd extends Frame
{
  // Кнопка, с помощью которой можно закрыть окно
  Button btnOK;

  // Главное меню окна
  MenuBar mbMainMenuBar;
  
  // Меню File
  Menu mnFile;

  // Меню Help
  Menu mnHelp;

  // -------------------------------------------------------
  // MainFrameWnd
  // Конструктор класса
  // -------------------------------------------------------
  public MainFrameWnd(String sTitle)
  {
    // Создаем окно, вызывая конструктор из базового класса
    super(sTitle);
    
    // Устанавливаем размеры окна
    resize(400, 200);

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

    // Устанавливаем режим добавления компонент FlowLayout
    setLayout(new FlowLayout());
    
    // Создаем и добавляем в окно кнопку OK
    btnOK = new Button("OK");
    add(btnOK);

    // Создаем главное меню
    mbMainMenuBar = new MenuBar();
    
    // Создаем меню File
    mnFile = new Menu("File");
    
    // Заполняем меню File
    mnFile.add("New");       // строка New
    mnFile.add("-");         // разделитель
    mnFile.add("Exit");      // строка Exit
  
    // Создаем меню Help
    mnHelp = new Menu("Help"); 

    // Заполняем меню Help
    mnHelp.add("Content");   // строка Content
    mnHelp.add("-");         // разделитель
    mnHelp.add("About");     // строка About

    // Добавляем меню File и Help в главное 
    // меню нашего окна
    mbMainMenuBar.add(mnFile);
    mbMainMenuBar.add(mnHelp);
    
    // Устанавливаем для окна главное меню
    setMenuBar(mbMainMenuBar);
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование 
  // в созданном нами окне 
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Устанавливаем шрифт
    g.setFont(new Font("Helvetica", Font.PLAIN, 12));

    // Рисуем строку
    g.drawString("Окно класса Frame", 10, 50);

    // Вызываем метод paint родительского класса
    super.paint(g);
  }

  // -------------------------------------------------------
  // handleEvent
  // Обработка событий для окна
  // -------------------------------------------------------
  public boolean handleEvent(Event evt)
  {
    // Если пользователь закрывает окно,
    // скрываем его с помощью метода hide
    if(evt.id == Event.WINDOW_DESTROY)
    {
      hide();
      return true;
    }
      
    else
      return super.handleEvent(evt);
  }
  
  // -------------------------------------------------------
  // action
  // Метод вызывается, когда пользователь выполняет
  // действие над компонентами в нашем окне
  // -------------------------------------------------------
  public boolean action(Event evt, Object obj)
  {
    // Ссылка на кнопку, от которой пришло сообщение
    Button btn;
  
    // Ссылка на элемент меню
    MenuItem mnItem;

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

      // Если пользователь нажал кнопку OK, скрываем окно
      if(evt.target.equals(btnOK))
      {
        hide();
      }
      // Если событие возникло от неизвестной кнопки,
      // мы его не обрабатываем
      else
        return false;

      return true;
    }

    // Обработка событий от меню
    else if(evt.target instanceof MenuItem)
    {
      // Получам ссылку на элемент меню
      mnItem = (MenuItem)evt.target;

      // Если из меню File выбрана строка Exit,
      // завершаем работу виртуальной машины Java
      if(obj.equals("Exit"))
      {
        System.exit(0);
      }

      // Если из меню File выбрана строка New,
      // отображаем название строки в диалоговой панели
      else if(obj.equals("New"))
      {
        // Ссылка на диалоговую панель
        MessageBox mbox;

        // Создаем новую диалоговую панель
        mbox = new MessageBox("Item New selected",
          this, "Dialog from Frame", true);
        
        // Отображаем диалоговую панель
        mbox.show();
      }

      // Если из меню File выбрана строка Content,
      // отображаем название строки в диалоговой панели
      else if(obj.equals("Content"))
      {
        MessageBox mbox;

        mbox = new MessageBox("Item Content selected",
          this, "Dialog from Frame", true);
        
        mbox.show();
      }
      
      // Если из меню File выбрана строка About,
      // отображаем название строки в диалоговой панели
      else if(obj.equals("About"))
      {
        MessageBox mbox;
        mbox = new MessageBox("Item About selected",
          this, "Dialog from Frame", true);
        
        mbox.show();
      }

      else
        return false;

      return true;
    }
    return false;
  }
}

// =========================================================
// Класс MessageBox
// На базе этого класса мы создаем диалоговые панели
// =========================================================
class MessageBox extends Dialog
{
  // Поле для отображения текста сообщения
  Label lbMsg;

  // Кнопка для удаления диалоговой панели
  Button btnOK;

  // -------------------------------------------------------
  // MessageBox
  // Конструктор класса
  // -------------------------------------------------------
  public MessageBox(String sMsg, 
    Frame  parent, String  sTitle, boolean  modal)
  {
    // Создаем диалогвоую панель, вызывая конструктор
    // базового класса Dialog
    super(parent, sTitle, modal);

    // Устанавливаем размеры окна диалоговой панели
    resize(200, 100);

    // Устанавливаем режим размещения компонент GridLayout
    setLayout(new GridLayout(2, 1));
    
    // Создаем и добавляем поле для отображения сообщения
    lbMsg = new Label(sMsg, Label.CENTER);
    add(lbMsg);

    // Создаем и добавляем кнопку для завершения работы
    // диалоговой панели
    btnOK = new Button("OK");
    add(btnOK);
  }

  // -------------------------------------------------------
  // handleEvent
  // Обработка событий для диалоговой панели
  // -------------------------------------------------------
  public boolean handleEvent(Event evt)
  {
    // Если пользователь закрывает окно диалоговой панели,
    // скрываем его с помощью метода hide
    if(evt.id == Event.WINDOW_DESTROY)
    {
      dispose();
      return true;
    }
      
    else
      return super.handleEvent(evt);
  }

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

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

      return true;
    }
    return false;
  }
}

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

Листинг 8.2. Файл FrameWnd\FrameWnd.html

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

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

Рассмотрим по очереди поля и методы классов, определенных в нашем приложении.

Поля класса FrameWnd

В поле fMainFrame класса MainFrameWnd хранится ссылка на окно, которое будет создано, если пользователь нажмет кнопку “Show Frame Window”, расположенную в окне аплета. Класс MainFrameWnd создан нами на базе класса Frame.

Поля с именами btnShowFrame и btnHideFrame предназначены, соответственно, для хранения ссылок на только что указанную кнопку и кнопку “Hide Frame Window”, с помощью которой можно скрыть окно.

Метод getAppletInfo класса FrameWnd

Этот метод возвращает информацию об аплете FrameWnd.

Метод init класса FrameWnd

В процессе инициализации аплета метод init создает объект класса MainFrameWnd - перекрывающееся окно с заголовком "Main Frame Window":

fMainFrame = new MainFrameWnd("Main Frame Window");

Для этого вызывается конструктор из класса MainFrameWnd, созданного нами на базе класса Frame.

После этого метод init создает две кнопки и добавляет их в окно аплета:

btnShowFrame = new Button("Show Frame Window");
add(btnShowFrame);
btnHideFrame = new Button("Hide Frame Window");
add(btnHideFrame);

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

Метод destroy класса FrameWnd

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

fMainFrame.dispose();

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

Назначение метода action класса FrameWnd - обработка событий, вызванных кнопками кнопку “Show Frame Window” и “Hide Frame Window”, созданных в окне аплета:

if(evt.target.equals(btnShowFrame))
  fMainFrame.show();
else if(evt.target.equals(btnHideFrame))
  fMainFrame.hide();

Если нажата кнопка “Show Frame Window”, для окна fMainFrame вызывается метод show, что приводит к появлению окна на экране. Если нажата кнопка “Hide Frame Window”, для этого окна вызывается метод hide, после чего окно исчезает с экрана. Исчезнувшее окно не уничтожается и вы можете снова отобразить его на экране, нажав кнопку “Show Frame Window”.

Класс MainFrameWnd

Класс MainFrameWnd предназначен для создания автономного перекрывающегося окна, которое существует вне окна навигатора. Этот класс был нами создан на базе класса Frame:

class MainFrameWnd extends Frame
{
  . . .
}

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

Поля класса MainFrameWnd

В поле btnOK хранится ссылка на кнопку, при нажатии которой окно удаляется.

Поле mbMainMenuBar класса MenuBar предназначено для хранения ссылки на главное меню окна. В него мы будем добавлять меню “File” и “Help”, идентификаторы которых хранятся в полях mnFile и mnHelp, соответственно.

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

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

super(sTitle);

Далее конструктор определяет размеры окна, вызывая для него метод resize:

resize(400, 200);

Затем мы устанавливаем для нашего окна желтый цвет фона и черный цвет изображения:

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

По умолчанию для окон класса Frame устанавливается режим добавления компонент BorderLayout. Мы изменяем этот режим на FlowLayout, вызывая метод setLayout:

setLayout(new FlowLayout());

Установив новый режим добавления компонент, мы располагаем в нашем окне кнопку, предварительно создав ее с помощью конструктора класса Button:

btnOK = new Button("OK");
add(btnOK);

Далее метод init приступает к формированию главного меню окна. Это меню создается как объект класса MenuBar:

mbMainMenuBar = new MenuBar();

Затем мы создаем и наполняем меню “File”:

mnFile = new Menu("File");
mnFile.add("New");       // строка New
mnFile.add("-");         // разделитель
mnFile.add("Exit");      // строка Exit

Это меню создается на базе класса Menu. Обратите внимание, что между строками New и File расположен разделитель.

Аналогичным образом мы добавляем в главное меню другое меню - “Help”:

mnHelp = new Menu("Help"); 
mnHelp.add("Content");   // строка Content
mnHelp.add("-");         // разделитель
mnHelp.add("About");     // строка About

После своего окончательного формирования меню “File” и “Help” добавляются в главное меню окна mbMainMenuBar:

mbMainMenuBar.add(mnFile);
mbMainMenuBar.add(mnHelp);

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

setMenuBar(mbMainMenuBar);

Метод paint класса MainFrameWnd

Метод paint получает в качестве параметра ссылку на контекст отображения, пригодный для рисования в нашем окне. Пользуясь этим контекстом, мы устанавливаем шрифт текста и рисуем текстовую строку. Затем мы вызываем метод paint из базового класса Frame, на основе которого создан наш класс MainFrameWnd:

g.setFont(new Font("Helvetica", Font.PLAIN, 12));
g.drawString("Окно класса Frame", 10, 50);
super.paint(g);

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

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

При получении кода события Event.WINDOW_DESTROY (удаление окна) мы просто скрываем окно, вызывая метод hide:

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

Все другие события передаются для обработки методу handleEvent из базового класса.

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

Этот метод обрабатывает события, связанные с кнопкой и меню.

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

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

Здесь для вас нет ничего нового.

Рассмотрим более подробно процедуру обработки событий от меню.

Вначале метод action проверяет, вызвано ли событие выбором строки из меню, сравнивая объект события с классом MenuItem:

else if(evt.target instanceof MenuItem)
{
. . .
}
else
  return false;

Если это так, в поле mnItem сохраняется ссылка на элемент меню, вызвавший событие:

mnItem = (MenuItem)evt.target;

Однако мы не используем этот элемент, так как для определения строки, выбранной пользователем, нам достаточно проанализировать второй параметр метода action:

if(obj.equals("Exit"))
  System.exit(0);
else if(obj.equals("New"))
{
  MessageBox mbox;
  mbox = new MessageBox("Item New selected",
    this, "Dialog from Frame", true);
  mbox.show();
}
else if(obj.equals("Content"))
{
 . . .
}
else if(obj.equals("About"))
{
. . .
}

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

Если пользователь выбрал из меню File строку Exit, мы вызываем метод System.exit, предназначенный для завершения работы виртуальной машины Java. Таким способом вы можете завершить работу аплета, когда он выполняется в среде Microsoft Visual J++ в процессе отладки. Если же аплет запущен автономно в навигаторе, то завершения работы навигатора не произойдет.

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

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

Класс MessageBox

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

class MessageBox extends Dialog
{
  . . .
}

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

Поля класса MessageBox

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

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

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

Наш конструктор создает диалоговую панель с заданным сообщением внутри нее. Ссылка на строку сообщения передается конструктору через первый параметр. Остальные параметры используются конструктором базового класса Dialog для создания диалоговой панели:

super(parent, sTitle, modal);

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

resize(200, 100);

Отменяя установленный по умолчанию режим размещения компонент BorderLayout, конструктор устанавливает режим GridLayout:

setLayout(new GridLayout(2, 1));

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

lbMsg = new Label(sMsg, Label.CENTER);
add(lbMsg);
btnOK = new Button("OK");
add(btnOK);

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

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

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

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

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

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

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