7. Комбинированные приложения Java

Наши предыдущие приложения были либо аплетами, либо автономными приложениями с консольным окном. Основной класс аплетов был унаследован от класса Applet, а в классе консольных приложений был определен метод main.

В этой главе мы расскажем о том, как создавать комбинированные приложения, двоичный файл .class которых способен работать и как аплет, встроенный в документ HTML, и как автономное приложение. Система автоматизированного проектирования приложений Java Applet Wizard, встроенная в Microsoft Visual J++, позволяет автоматически создавать исходные тексты шаблонов таких комбинированных приложений.

Структура комбинированных приложений

Рассмотрим структуру комбинированного приложения Combi, полные исходные тексты которого мы привели ниже в этой главе.

Главный класс комбинированного приложения

Класс Combi создан на базе класса Applet, что необходимо для обеспечения работы этого приложения под управлением навигатора Internet:

public class Combi extends Applet
{
  . . .
  public static void main(String args[])
  {
    . . .
  }
  public String getAppletInfo()
  {
    . . .
  }
  public void init()
  {
    . . .
  }
  public void paint(Graphics g)
  {
    . . .
  }
}

Обратите внимание, что наряду с методами, которые обычно определяются аплетами, такими как getAppletInfo, init и paint, в классе комбинированного приложения определен метод main. Если приложение запускается как аплет, метод main не получает управления. Если же приложение запущено автономно, этот метод первым получает управление и выполняет все необходимые инициализирующие действия.

Главное из этих действий - создание окна на базе класса Frame для размещения в нем аплета, создание аплета и вызов функций инициализации аплета. Ниже мы привели исходный текст метода main приложения Combi, созданный для нас системой Java Applet Wizard:

public static void main(String args[])
{
  CombiFrame frame = new CombiFrame("Combi");
  frame.show();

  frame.hide();
  frame.resize(
    frame.insets().left + frame.insets().right  + 320,
    frame.insets().top  + frame.insets().bottom + 240);

  Combi applet_Combi = new Combi();
  frame.add("Center", applet_Combi);
  . . .
  applet_Combi.init();
  applet_Combi.start();
  frame.show();
}

Прежде всего, метод main создает объект frame класса CombiFrame, определенного в нашем приложении на базе класса Frame (окно фрейма). Напомним, что класс Frame, который был нами описан в 30 томе “Библиотеки системного программиста”, позволяет приложениям Java создавать окна, напоминающие окна обычных приложений Windows.

Метод show отображает окно фрейма.

Далее в методе main выполняется изменение размеров окна фрейма, перед чем окно скрывается методом hide. Для изменения размеров окна применяется метод resize, которому через первый и второй параметры передаются новые значения, соответственно, ширины и высоты окна.

Размеры окна устанавливаются с учетом размеров внешней рамки и заголовка окна, для чего применяется метод insets. Поля left и right объекта класса Insets, ссылку на который возвращает метод insets, содержат ширину, соответственно, левой и правой части рамки окна. Поле top содержит высоту верхней части рамки окна с учетом заголовка, а поле bottom - высоту нижней части рамки окна.

Далее метод main делает нечто интересное - он создает аплет класса Combi:

Combi applet_Combi = new Combi();

Когда приложение Java встроено в документ HTML как аплет, объект аплета создается автоматически навигатором при просмотре этого документа и добавляется в окно навигатора. В случае автономного приложения мы сами должны создать аплет и добавить его в окно фрейма.

Добавление аплета в окно фрейма выполняется методом add:

frame.add("Center", applet_Combi);

В 30 томе “Библиотеки системного программиста” мы использовали этот метод для добавления компонент в окно контейнера, которым, в частности, является окно фрейма.

Создав аплет, мы должны вызвать методы init и start, как это происходит при инициализации аплета, встроенного в документ HTML:

applet_Combi.init();
applet_Combi.start();

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

frame.show();

Класс фрейма для комбинированного приложения

Теперь о классе CombiFrame.

Определение этого класса выглядит достаточно просто:

class CombiFrame extends Frame
{
  public CombiFrame(String str)
  {
    super (str);
  }
  public boolean handleEvent(Event evt)
  {
    switch (evt.id)
    {
      case Event.WINDOW_DESTROY:
      {
        dispose();
        System.exit(0);
        return true;
      }
      default:
        return super.handleEvent(evt);
    }       
  }
}

Класс CombiFrame создан на базе класса Frame и предназначен для создания окна фрейма, в которое будет добавлен аплет. В этом классе определен конструктор и метод handleEvent.

Конструктор выполняет простую задачу - создание окна фрейма. Для этого он вызывает конструктор базового класса Frame, передавая ему через параметр строку заголовка окна.

Задача метода handleEvent - удаление окна фрейма, когда пользователь пытается его закрыть, сделав, например, щелчок мышью по правой кнопке в заголовке окна. В случае такой попытки методу handleEvent передается извещение с кодом Event.WINDOW_DESTROY.

В процессе обработки этого извещения метод handleEvent удаляет окно фрейма, вызывая метод dispose, а затем завершает работу приложения, вызывая статический метод exit из класса System.

Все прочие извещения передаются методу handleEvent, определенному в базовом классе.

Приложение Combi

Приложение Combi имеет описанную выше структуру и потому способно работать как автономно, так и под управлением навигатора Internet.

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

На рис. 7.1 показан внешний вид окна этого приложения, когда оно работает автономно.

Рис. 7.1. Окно автономно работающего приложения Combi

Приложение определяет платформу, на которой оно работает, название и версию операционной системы, каталог, в котором находится двоичный модуль приложения, и каталог, в котором расположены классы Java. Кроме того, сразу после запуска автономное приложение Combi, если оно выполняется в среде операционной системы Windows 95 или Windows NT, запускает программу калькулятора calc.exe, входящую в комплект этой операционной системы.

Когда приложение Combi работает как аплет, встроенный в документ HTML, его окно имеет вид, показанный на рис. 7.2.

Рис. 7.2. Окно приложения Combi, встроенного в документ HTML

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

Кроме того, будучи загруженным с сервера Web, приложение не сможет запустить программу калькулятора, так как эта возможность для аплетов заблокирована. Однако при работе аплета в среде Microsoft Visual J++ запуск приложений (а также другие действия) разрешается, поэтому на экране появится окно клаькулятора.

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

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

Листинг 7.1. Файл Combi\Combi.java

// =========================================================
// Приложение, способное работать как аплет, включенный
// в документ HTML, а также как автономное приложение 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.*;

// Импортируем класс CombiFrame
import CombiFrame;

// =========================================================
// Combi 
// Основной класс приложения
// =========================================================
public class Combi extends Applet
{
  // Режим работы приложения. Если это поле содержит 
  // значение true, приложение работает автономно, если 
  // false - в составе документа HTML под управлением 
  // навигатора
  boolean m_fStandAlone = false;

  // -------------------------------------------------------
  // main
  // Метод main получает управление, когда приложение
  // работает автономно
  // -------------------------------------------------------
  public static void main(String args[])
  {
    // Создаем окно класса CombiFrame, унаследованного от
    // класса Frame (окно фрейма)
    CombiFrame frame = new CombiFrame("Combi");

    // Отображаем окно фрейма
    frame.show();

    // Выполняем изменение размеров окна
    
    // Скрываем окно фрейма
    frame.hide();

    // Изменяем размеры окна фрейма
    frame.resize(
      frame.insets().left + frame.insets().right  + 320,
      frame.insets().top  + frame.insets().bottom + 240);

    // Создаем аплет класса Combi
    Combi applet_Combi = new Combi();

    // Добавляем окно этого аплета в окно фрейма
    frame.add("Center", applet_Combi);

    // Устанавливаем признак работы в режиме
    // автономного прилождения Java
    applet_Combi.m_fStandAlone = true;

    // Вызываем методы init и start аплета класса Combi
    applet_Combi.init();
    applet_Combi.start();

    // Отображаем окно фрейма
    frame.show();
  }

  // -------------------------------------------------------
  // getAppletInfo
  // Метод, возвращающей строку информации об аплете
  // -------------------------------------------------------
  public String getAppletInfo()
  {
    return "Name: Combi\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()
  {
    // Устанавливаем размеры окна аплета
    resize(320, 240);

    // Определяем имя операционной системы
    String str = System.getProperty("os.name");
    
    // Если это Windows, запускаем калькулятор
    if(str.indexOf("Windows") != -1)
    {
      // Получаем указатель на класс Runtime 
      Runtime rt = Runtime.getRuntime();
      
      // Выполняем попытку запуска клькулятора
      try
      {
        rt.exec("calc.exe");
      }
      catch(Exception ioe)
      {
        System.out.println(ioe.toString());
      }
    }
  }

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

    // Рабочая строка
    String str;

    // Проверяем, в каком режиме работает приложение
    // и рисуем соответствующее сообщение в его окне
    if(m_fStandAlone)
    {
      g.drawString("Приложение работает" +
        " автономно", 10, 20);

      // Отображаем системные свойства, доступные
      // аплетам и автономным приложениям
      str = 
        "System: " + System.getProperty("os.arch") +
        ", OS: "   + System.getProperty("os.name")    +
        ", ver. "  + System.getProperty("os.version");

      g.drawString(str, 10, 50);

      str = 
        "User dir: "    + System.getProperty("user.dir")  +
        ", User home: " + System.getProperty("user.home");
      
      g.drawString(str, 10, 65);
    }

    // Приложение работает под управлением навигатора
    else
    {
      g.drawString("Приложение работает" +
      " в документе HTML", 10, 20);

      // Отображаем системные свойства, доступные
      // аплетам
      str = 
        "System: " + System.getProperty("os.arch") +
        ", OS: "   + System.getProperty("os.name")    +
        ", ver. "  + System.getProperty("os.version");

      g.drawString(str, 10, 50);
    }
  }
}

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

Листинг 7.2. Файл CombiFrame\CombiFrame.java

// =========================================================
// Исходный текст класса CombiFrame для прилдожения Combi
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =========================================================
import java.awt.*;

// =========================================================
// CombiFrame 
// Класс для окна фрейма
// =========================================================
class CombiFrame extends Frame
{
  // -------------------------------------------------------
  // Конструктор класса CombiFrame
  // -------------------------------------------------------
  public CombiFrame(String str)
  {
    // Вызываем конструктор базового класса
    super (str);
  }

  // -------------------------------------------------------
  // handleEvent
  // Метод handleEvent обрабатывает извещение WINDOW_DESTROY
  // -------------------------------------------------------
  public boolean handleEvent(Event evt)
  {
    switch (evt.id)
    {
      // Когда пользователь закрывает окно фрейма, 
      // метод handleEvent завершает работу автономного
      // приложения
      case Event.WINDOW_DESTROY:
      {
        // Удаление окна фрейма
        dispose();

        // Завершение работы приложения
        System.exit(0);

        return true;
      }

      default:
        // Для обработки других извещений вызываем
        // метод handleEvent из базового класса
        return super.handleEvent(evt);
    }       
  }
}

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

Листинг 7.3. Файл Combi\Combi.html

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

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

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

Так как определение класса CombiFrame расположено в отдельном файле, мы должны импортировать описание этого класса в исходных текстах класса Combi:

import CombiFrame;

Поля класса Combi

В классе Combi определено поле с именем m_fStandAlone:

boolean m_fStandAlone = false;

Если приложение работает автономно, в это поле записывается значение true, если как аплет в составе документа HTML - false. По умолчанию это поле инициализируется значением false, однако если приложение запускается автономно, метод main записывает в него значение true:

applet_Combi.m_fStandAlone = true;

Метод init

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

После изменения размеров окна аплета методом resize метод init определяет некоторые параметры среды выполнения приложения. Для этого используется метод getProperty, определенный в классе System. Подробное описание этого метода выходит за рамки нашей книги. Однако мы отметим, что передавая этому методу в виде текстовой строки названия параметров среды выполнения, можно получить в текстовом виде значения этих параметров.

Наш метод init использует метод getProperty для определения названия операционной системы, под управлением которой работает приложение, передавая ему строку "os.name":

String str = System.getProperty("os.name");

Далее метод init проверяет, есть ли в строке названия операционной системы слово Windows, и если есть, пытается запустить программу калькулятора:

if(str.indexOf("Windows") != -1)
{
  Runtime rt = Runtime.getRuntime();
  try
  {
    rt.exec("calc.exe");
  }
  catch(Exception ioe)
  {
    System.out.println(ioe.toString());
  }
}

Калькулятор запускается с помощью класса Runtime, который предоставляет системно-зависимые методы (именно поэтому перед его использованием мы проверили название операционной системы).

Ссылка на объект класса Runtime должна быть получена с помощью статического метода getRuntime. Получив такую ссылку, мы запускаем программу калькулятора с помощью метода exec, который определен в реализации класса Runtime для операционных систем Microsoft Windows 95 и Microsoft Windows NT.

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

Метод paint

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

Если приложение работает автономно, метод отображает в окне приложения соответствующее сообщение:

g.drawString("Приложение работает автономно", 10, 20);

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

str = 
  "System: " + System.getProperty("os.arch") +
  ", OS: "   + System.getProperty("os.name")    +
  ", ver. "  + System.getProperty("os.version");
g.drawString(str, 10, 50);

Строкой ниже отображается путь к каталогу, в котором находится двоичный модуль приложения и путь к каталогу, где находится библиотка классов Java:

str = 
  "User dir: "    + System.getProperty("user.dir")  +
  ", User home: " + System.getProperty("user.home");
g.drawString(str, 10, 65);

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