В. Время, вперёд!

ИЮЛ | МАР | апр
| 13 |
2012 | 2013 | 2014

16 captures 12 окт 07 - 13 мар 13 |

Close Help

В. Время, вперёд!

Приступим к рассмотрению последнего примера. Это приложение будет взаимодействовать с человеком не через командную строку, а через обычные экранные кнопки. Нажатие на эти кнопки можно осуществлять как при помощи мышки, так и при помощи клавиатуры сочетание клавиши "Alt" и выделенной буквы кнопки или клавиши "пробел" и "ввод", если кнопка уже выбрана). Данное приложение можно выполнять и без консольной оболочки, т.к. оно заканчивает свою работу не сразу после запуска, а только по команде пользователя.

Наше приложение является секундомером. Вот так оно будет выглядеть в работе:

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

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

    ОТДЕЛ Секундомер+;

    ИСПОЛЬЗУЕТ
      ОС       ИЗ "...\Отделы\Обмен\",
      Окно     ИЗ "...\Отделы\Обмен\",
      Ввод     ИЗ "...\Отделы\Обмен\",
      Поле     ИЗ "...\Отделы\Поле\",
      Подложка ИЗ "...\Отделы\Поле\",
      Записка  ИЗ "...\Отделы\Поле\",
      Кнопка   ИЗ "...\Отделы\Поле\",
      Черта    ИЗ "...\Отделы\Поле\";

Объявляем постоянные, соответствующие номерам действий, которые вырабатываются при нажатии экранных кнопок:

    ПОСТ
      дПуск =1;
      дСтоп =2;
      дСброс=3;
      дВыход=4;

Заводим: логическую переменную, которая будет принимать значение ВКЛ, если секундомер в данный момент ведёт измерения -

    ПЕР
      идётИзмерение:КЛЮЧ;

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

      измеренноеВремя:ЦЕЛ;

переменную для хранения момента времени, в который произошло последнее обновление показаний секундомера -

      моментОбновления:ЦЕЛ;

и переменную для вывода показаний -

      зВремя:Записка.Доступ;

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

    ЗАДАЧА Приём(поле:Поле.Доступ; посылка+:Ввод.Посылка);
    УКАЗ

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

      ДЛЯ посылка ВИДА
      | Кнопка.Посылка:

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

          ВЫБРАТЬ посылка.кнопка.действие ИЗ
          | дПуск:  идётИзмерение:=ВКЛ
          | дСтоп:  идётИзмерение:=ОТКЛ
          | дСброс: измеренноеВремя:=0
          | дВыход: поле.состояние:=Поле.сДалее
          КОН

Учитывая, что в наборе данных вида "Ввод.ОтКлавиш" есть переменные "код", "упрКнопки", мы сможем выполнить следующее указание: при нажатии на клавишу "Esc" или клавишу "Alt" совместно с "X" сообщим через состояние поля, что требуется выход из приложения.

      | Ввод.ОтКлавиш:
          ЕСЛИ (Ввод.лАльт В посылка.упрКнопки) И (посылка.код = 58H) (* Alt+'X' *)
           ИЛИ (посылка.код = 1BH) ТО                                 (* Esc     *)
            поле.состояние:=Поле.сДалее
          КОН

Так как нам не нужно, чтобы приложение аварийно завершало свою работу при получении посылки вида, отличного от "Кнопка.Посылка" и "Ввод.ОтКлавиш", то отработаем это условие как пустую последовательность указаний:

      ИНАЧЕ
      КОН

Заканчиваем эту задачу и начинаем главную задачу. Определяем в ней переменные для поля, наделов и часов:

    КОН Получить;

    ЗАДАЧА Главная;
    ПЕР
      поле:Поле.Доступ;                            (* рабочее поле экрана   *)
      подложка:Подложка.Доступ;                    (* подложка поля         *)
      кнСтоп,кнПуск,кнСброс,кнВыход:Кнопка.Доступ; (* управляющие кнопки    *)
      черта1,черта2:Черта.Доступ;                  (* разделительные черты  *)
      часы:ЦЕЛ;

В задаче "Главная" объявляем подзадачу "СоздатьПоле". В начале этой задачи создаём переменную "поле". Верхний левый угол поля будет расположен в верхнем левом углу экрана (0,0). Высота поля будет 8 строк, а ширина 17 колонок. Поле распологается на чистом экране (ПУСТО), и его не надо помещать в середину (ОТКЛ). Ввод от пользователя будет направлен в задачу "Приём". Номер справки для нашего поля определять не будем (0).

      ЗАДАЧА СоздатьПоле;
      УКАЗ
        поле:=Поле.Создать(0,0,8,17,ПУСТО,ОТКЛ,Приём,0);

Далее создаём наделы. См. задание размеров и положения наделов и полей.

        подложка:=Подложка.Создать(0,0,0,0,"");
        зВремя  :=Записка.Создать(1,3,1,11,"00:00:00.00");
        черта1:=Черта.Создать(2,0,1,0);
        кнПуск :=Кнопка.Создать(3,2,"[~Пуск]",дПуск,ВКЛ);
        кнСтоп :=Кнопка.Создать(3,9,"[~Стоп]",дСтоп,ВКЛ);
        кнСброс:=Кнопка.Создать(4,4,"[ С~брос ]",дСброс,ВКЛ);
        черта2:=Черта.Создать(5,0,1,0);
        кнВыход:=Кнопка.Создать(6,4,"[ ~Выход ]",дВыход,ВКЛ);

Знак "~" в надписи, передаваемой наделу, предваряет букву, по которой человек сможет перейти к данному наделу, нажимая сочетание из клавиш "Alt" и заданной буквы. В данном примере все наши экранные кнопки - выбираемые (ВКЛ).

В конце подзадачи добавляем наделы в порядке получения ввода. Этот порядок определяет очерёдность обхода наделов при нажатии пользователем клавиши "Tab". В начале работы приложения первому наделу, который является выбираемым (в нашем случае это кнопка Пуск), будет предоставлена возможность получать ввод от человека.

        Поле.ДобавитьНадел(поле,подложка);
        Поле.ДобавитьНадел(поле,зВремя);
        Поле.ДобавитьНадел(поле,черта1);
        Поле.ДобавитьНадел(поле,кнПуск);
        Поле.ДобавитьНадел(поле,кнСтоп);
        Поле.ДобавитьНадел(поле,кнСброс);
        Поле.ДобавитьНадел(поле,черта2);
        Поле.ДобавитьНадел(поле,кнВыход)
      КОН СоздатьПоле;

Далее начинается последовательность указаний задачи "Главная". Настраиваем окно вывода, вызываем подзадачу для создания поля, подгоняем размер окна приложения под размер нашего поля, рисуем поле со всеми наделами и создаём часы №1 с временем срабатывания в 100 мс:

    УКАЗ
      Окно.Графическое("Секундомер","Lucida Console",30,ОбновитьПоказания);
    (*
      Окно.Текстовое(ОбновитьПоказания);
    *)
      СоздатьПоле;
      Поле.ОкноНаВсёПоле(поле);
      Поле.Рисовать(поле);
      часы:=Окно.СоздатьЧасы(1,100);
      Окно.Показать;

И, наконец, повтор указаний, который будет выполняться всё основное время работы приложения (пока состояние поля будет рабочим):

      ПОКА поле.состояние = Поле.сРабота ВЫП

Вызываем задачу поля - "Проверить", в которой проверяется и обрабатывается ввод от пользователя:

        Поле.Проверить(поле)

Заканчиваем повтор указаний, прекращаем вызывать по часам задачу "ОбновитьПоказания", завершаем объявление задачи:

      КОН;
      Окно.УдалитьЧасы(часы)
    КОН Главная;

Следующая задача выводит через записку "зВремя" обновлённые показания времени в привычном для человека виде:

      ЗАДАЧА ОбновитьПоказания(номерЧасов:ЦЕЛ);
      ПЕР
        сотые,секунды,минуты,часы:ЦЕЛ;
        сейчас:ЦЕЛ;
        прошлоВремени:ЦЕЛ;
      УКАЗ
        сейчас:=ОС.Время();
        прошлоВремени:=сейчас-моментОбновления;
        моментОбновления:=сейчас;
        ЕСЛИ идётИзмерение ТО
          УВЕЛИЧИТЬ(измеренноеВремя,прошлоВремени)
        КОН;
        сотые:=измеренноеВремя ДЕЛИТЬ 10;
        секунды:=сотые ДЕЛИТЬ 100;
        минуты:=секунды ДЕЛИТЬ 60;
        часы:=минуты ДЕЛИТЬ 60;
        Записка.ИзЧЦел(зВремя,"%.2d:%.2d:%.2d.%.2d",
          часы,минуты ОСТАТОК 60,секунды ОСТАТОК 60,сотые ОСТАТОК 100)
      КОН ОбновитьПоказания;

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

    УКАЗ
      измеренноеВремя:=0;
      идётИзмерение:=ОТКЛ;
      Главная
    КОН Секундомер.

Полный текст данного приложения расположен в папке \Глагол\Приложения\Иное\.

Отметим, что в примерах игр (папка \Глагол\Приложения\Игры\) взаимодействие приложения с человеком организовано точно таким же образом, как и в разобранном выше примере.

Сделано в России