Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Microsoft Visual J++. Создание приложений и аплетов на языке Java. Часть 2

© Александр Фролов, Григорий Фролов
Том 32, М.: Диалог-МИФИ, 1997, 288 стр.

[Назад] [Содеожание] [Дальше]

Приложение MultiTask

Система автоматизированной разработки аплетов Microsoft Visual J++ позволяет указать, что создаваемый аплет будет мультизадачным. Для этого на третьем шаге в поле Would you like your applet to be multi-threaded следует включить переключатель Yes (рис. 1.1).

Рис. 1.1. Добавление мультизадачности в создаваемый аплет

Включив указанный переключатель, выключите пока переключатель Would you like support for animation - анимацией мы займемся немного позже.

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

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

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

Листинг 1.1. Файл MultiTask\MultiTask.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 MultiTask extends Applet implements Runnable
{
  // Задача, которая будет обновлять окно аплета
  Thread m_MultiTask = null;

  // -------------------------------------------------------
  // MultiTask
  // Конструктор класса MultiTask. Не используется
  // -------------------------------------------------------
  public MultiTask()
  {
  }

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

  // -------------------------------------------------------
  // destroy
  // Метод, получающий управление при 
  // завершении работы аплета
  // -------------------------------------------------------
  public void destroy()
  {
  }

  // -------------------------------------------------------
  // paint
  // Метод paint, выполняющий рисование в окне аплета
  // -------------------------------------------------------
  public void paint(Graphics g)
  {
    // Отображения строки со случайным числом
    g.drawString("Running: " + Math.random(), 10, 20);
  }

  // -------------------------------------------------------
  // start
  // Метод вызывается при первом отображении окна аплета
  // -------------------------------------------------------
  public void start()
  {
    // Если задача еще не была создана, аплет создает
    // новую задачу как объект класса Thread, 
    // а затем запускает ее
    if (m_MultiTask == null)
    {
      // Создание задачи
      m_MultiTask = new Thread(this);

      // Запуск задачи
      m_MultiTask.start();
    }
  }
	
  // -------------------------------------------------------
  // stop
  // Метод вызывается, когда страница с аплетом 
  // исчезает с экрана
  // -------------------------------------------------------
  public void stop()
  {
    // Когда пользователь покидает страницу с аплетом, 
    // метод stop останавливает задачу.
    // Остановка выполняется только в том случае,
    // если задача была создана
    if (m_MultiTask != null)
    {
      // Остановка задачи
      m_MultiTask.stop();

      // Сброс ссылки на задачу
      m_MultiTask = null;
    }
  }

  // -------------------------------------------------------
  // run
  // Метод, который работает в рамках отдельной задачи
  // Он вызывает периодическое обновление содержимого
  // окна аплета
  // -------------------------------------------------------
  public void run()
  {
    // Выполняем обновление окна в бесконечном цикле
    while (true)
    {
      try
      {
        // Вызываем функцию обновления окна
        repaint();

        // Выполняем небольшую задержку
        Thread.sleep(50);
      }
      catch (InterruptedException e)
      {
        // Если при выполнении задержки произошло
        // исключение, останавливаем работу задачи
        stop();
      }
    }
  }
}

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

Листинг 1.2. Файл MultiTask\MultiTask.html


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

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

Для того чтобы аплет стал мультизадачным, его класс, который наследуется от класса Applet, дополнительно реализует интерфейс Runnable, как это показано ниже:


public class MultiTask extends Applet implements Runnable
{
  . . .
}

Внутри класса определяется поле с именем m_MultiTask типа Thread, которое предназначено для хранения ссылки на объект класса Thread, то есть на задачу:


Thread m_MultiTask = null;

Поле инициализируется значением null. Реальная ссылка на задачу будет сюда записана только после создания задачи.

Рассмотрим теперь методы класса.

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

В нашем аплете конструктор не используется.

Метод getAppletInfo

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

Метод init

Метод init вызывается один раз при инициализации аплета. Наше приложение его не использует.

Метод destroy

При завершении работы аплета управление передается методу destroy. Мы его не используем.

Метод paint

Метод paint рисует в окне аплета текстовую строку и случайное число, полученное при помощи статического метода random класса Math:


public void paint(Graphics g)
{
  g.drawString("Running: " + Math.random(), 10, 20);
}

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

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

Метод start

Метод start вызывается, когда пользователь отображает документ HTML, содержащий аплет. Наша реализация этого метода проверяет, создана ли задача перерисовки окна, и, если эта задача не запущена, создает и запускает ее:


public void start()
{
  if(m_MultiTask == null)
  {
    m_MultiTask = new Thread(this);
    m_MultiTask.start();
  }
}

Первоначально в поле m_MultiTask находится значение null, поэтому при первом вызове метода start всегда создается задача как объекта класса Thread. При этом конструктору с помощью ключевого слова this передается ссылка на наш аплет, поэтому при запуске задачи управление будет передано методу run, определенному в аплете.

Созданная задача не запускается автоматически. Для запуска необходимо вызвать метод start.

Метод stop

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


public void stop()
{
  if(m_MultiTask != null)
  {
    m_MultiTask.stop();
    m_MultiTask = null;
  }
}

После остановки мы записываем в поле m_MultiTask значение null.

Метод run

Метод run получает управление при запуске задачи методом start. Если этот метод возвращает управление, соответствующая задача завершает свою работу.

Наша реализация метода run состоит из бесконечного цикла, в котором периодически с задержкой 50 миллисекунд вызывается метод repaint:


public void run()
{
  while(true)
  {
    try
    {
      repaint();
      Thread.sleep(50);
    }
    catch(InterruptedException e)
    {
      stop();
    }
  }
}

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

Для выполнения задержки метод run вызывает метод sleep из класса Thread. Так как метод sleep может вызывать исключение InterruptedException, мы его обрабатываем с помощью операторов try и catch. Если произошло исключение, мы завершаем задачу, вызывая метод stop.

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

[Назад] [Содеожание] [Дальше]