Компьютерное моделирование

Разработка имитационных моделей в виде приложений с интерфейсом

Разбить на страницы
Показывать лекцию целиком

8.1. Применение текстовых объектов и потоков данных

Модель представляет собой набор операторов, содержащихся в одном объекте "Модель" и в любом количестве необязательных текстовых объектов.

Текстовые объекты с наборами операторов модели подключаются к объекту "Модель" командой INCLUDE. Формат команды:

INCLUDE         A

Операнд А - спецификация файла (полный путь доступа к файлу). Допустимые значения - String. Например:

INCLUDE         "DanDon.txt"
INCLUDE          "D:\Primer\DanZad.txt"

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

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

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

Команда INCLUDE допускает пять уровней вложенности файлов модели. Нельзя помещать команду INCLUDE в Plus-процедуру.

Операторы INCLUDE можно также закреплять за функциональными клавишами. Это позволяет одним нажатием клавиши объекту "Процесс моделирования" передать набор команд и (или) Plus-операторов, содержащихся в текстовом файле.

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

Поток данных - это последовательность текстовых строк, используемых процессом моделирования. Существуют два типа потоков данных:

  • потоки ввода-вывода (I/O или "файловые" потоки) для доступа к файлам;
  • потоки в памяти для тестирования или прямого доступа к внутренним данным.
  • Основной элемент потока данных - текстовая строка, которая является строкой печатных символов, включая пробелы.

    Для обработки потоков данных существуют пять блоков GPSS World: OPEN, CLOSE, READ, WRITE, SEEK. Три из них - READ, WRITE, SEEK - выполняют операции только с одной отдельной строкой текста.

    Перейдем к рассмотрению блоков обработки потоков данных.

    8.1.1. Блок OPEN

    Блок OPEN предназначен для инициализации потока данных. Формат блока:

    OPEN   A,[B],[C]

    Операнд А - дескриптор потока данных. Операнд определяет тип потока данных. Он обрабатывается как строка. Если это нулевая строка, создается поток в памяти. Если это канальное имя, такое как "\pipe\mypipe", создается канальный поток. В противном случае создается поток ввода-вывода и предполагается, что операнд А является спецификацией файла.

    Операнд В - номер потока данных, произвольное положительное число, задаваемое пользователем. Нумерация потоков введена с целью использования одновременно в одном процессе моделирования нескольких потоков данных. По умолчанию номер потока данных равен 1.

    Операнд С - метка блока, в который направляется транзакт в случае ошибки инициализации потока данных. Коды ошибок:

  • 0 - нет ошибки;
  • 10 - длинное имя файла;
  • 11 - ошибка чтения внешнего файла;
  • 12 - во время попытки открыть файл был запрещен доступ к памяти.
  • OPEN   ("Plan.txt"),3,Kon1
    OPEN   ("G\Model\NorPogr.txt")
    OPEN   ("")

    В первом примере открывается поток ввода-вывода, потоку присваивается номер 3 и в случае ошибки открытия активный транзакт направляется к блоку с меткой Kon1. Операндом А указан неполный путь доступа к файлу, поэтому подразумевается, что используется папка объекта "Процесс моделирования". Если файл с указанным именем не найден, то предполагается, что файл создается, и ошибка не возникает.

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

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

    Замечание.Если указанный операндом А файл найден, во время обработки блока OPEN он полностью загружается в виртуальную память. Все находившиеся в файле данные хранятся как часть объекта "Процесс моделирования" до тех пор, пока поток данных не будет закрыт. Все изменения данных отражаются в файловой системе только после того, как поток данных закрывается блоком CLOSE или библиотечной Plus-процедурой Close().

    8.1.2. Блок CLOSE

    Блок CLOSE предназначен для закрытия потока данных. Формат блока:

    CLOSE             A,[B],[C]

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

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

    Операнд С - метка блока, в который направляется транзакт в случае ошибки закрытия потока данных. Коды ошибок:

  • 0 - нет ошибки;
  • 41 - запись файла на диск не произведена из-за ошибки ввода-вывода;
  • 42 - файл не был открыт.
  • Например:

    CLOSE             Parm_Error,(P1+1)

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

    Блок CLOSE для потоков ввода-вывода записывает данные из виртуальной памяти в дисковый файл.

    8.1.3. Блок READ

    Блок READ предназначен для считывания из потока данных текстовой строки. Формат блока:

    READ   A,[B],[C]

    Операнд А - номер или имя параметра транзакта, в который записывается считанная из потока ввода или потока в памяти строка, находящаяся на позиции текущей строки. После считывания позиция текущей строки увеличивается на единицу. Если такой параметр активного транзакта не существует, он создается.

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

    Операнд С - метка блока, в который направляется транзакт в случае ошибки считывания. Если операнд С не используется, код ошибки все равно сохраняется. Для его получения нужно использовать блок CLOSE. Коды ошибок:

  • 21 - во время попытки выполнить чтение был запрещен доступ к памяти;
  • 22 - файл не был открыт.
  • Например:

    READ   Stroka_Text,4,Kon5

    В примере блок READ считывает текстовую строку из потока данных номер 4 и записывает в параметр транзакта с именем Stro-ka_Text. Если текстовая строка считывается без ошибки, а параметр активного транзакта не существует, он создается. В случае ошибки строка не считывается и активный транзакт направляется к блоку с меткой Kon5.

    8.1.4. Блок WRITE

    Блок WRITE предназначен для передачи текстовой строки потоку данных. Формат блока:

    WRITE             A,[B],[C],[D]

    Операнд А - текстовая строка, которая должна быть передана потоку данных.

    Операнд В - номер потока данных, по умолчанию равен 1.

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

  • 0 - нет ошибки;
  • 31 - во время попытки выполнить запись был запрещен доступ к памяти;
  • 32 - файл не был открыт.
  • Операнд D - задает режим работы блока WRITE. Если операнд D не используется (по умолчанию) или равен ON, блок WRITE работает в режиме вставки. Если операнд D равен OFF - в режиме замены.

    Режим вставки:

  • все текстовые строки, находящиеся на или за позицией текущей строки, сдвигаются на одну позицию;
  • если позиция текущей строки находится далеко за последней текстовой строкой, она устанавливается сразу после последней строки потока данных;
  • копия новой текстовой строки помещается на позицию текущей строки;
  • позиция текущей строки увеличивается на единицу. Режим замены:
  • если позиция текущей строки находится далеко за последней текстовой строкой, все промежуточные позиции заполняются нулевыми текстовыми строками;
  • текстовая строка, находящаяся на позиции текущей строки, удаляется;
  • копия новой текстовой строки помещается на позицию текущей строки;
  • позиция текущей строки увеличивается на единицу. Пример:
  • WRITE     "INITIAL    MX$TDon(1,1),420",5,Met3

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

    Замечание 1.Если операнды С блоков OPEN, CLOSE, READ и WRITE не используются, ошибка игнорируется. Обычно эти операнды используются для того, чтобы направить активный транзакт на блок CLOSE, который код ошибки помещает в параметр транзакта. Из параметра можно записать код ошибки в сохраняемую ячейку и завершить моделирование. Значение ячейки будет выведено в стандартном отчете. Замечание 2.При построчном считывании данных из файла может оказаться, что на позиции текущей строки нет строки данных. Это происходит тогда, когда из файла считаны все текстовые строки. В данном случае активный транзакт входит в блок READ и далее направляется к блоку, метка которого указана операндом С. Код ошибки при этом не сохраняется.

    8.1.5. Блок SEEK

    Блок SEEK устанавливает позицию текущей строки потока данных. Формат блока:

    SEEK               A,[B]

    Операнд А - новая позиция текущей строки.

    Операнд В - номер потока данных, по умолчанию равен 1.

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

    31 - код ошибки: файл не был открыт.

    Пример:

    SEEK    (Stroka+P1),(Potok+3)

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

    8.2. Разработка модели в GPSS World

    8.2.1. Постановка задачи

    На склад, имеющий 10 пунктов выгрузки, прибывают транспорта с материальными средствами (МС). В транспорте могут быть автомобили различной грузоподъемности. Всего количество типов автомобилей, отличающихся грузоподъемностью, которое может быть в транспорте, распределено по нормальному закону с математическим ожиданием 6 автомобилей и стандартным отклонением 1 автомобиль. Количество автомобилей одного типа в транспорте также распределено по нормальному закону с математическим ожиданием 11 автомобилей и стандартным отклонением 2 автомобиля. Интервалы времени прибытия транспортов распределены по экспоненциальному закону со средним значением 9 часов. Время разгрузки автомобиля зависит от его типа и подчиняется экспоненциальному закону. Среднее время выгрузки МС приведено в табл. 8.1. После выгрузки из тех же автомобилей вновь формируется транспорт.

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

    Среднее время выгрузки МС из автомобилей различных типов
    Характеристики Тип автомобиля
    1 2 3 4 5 6 7 8 9 10
    Среднее время выгрузки, мин 8 10 12 7 6 9 11 5 13 10

    Для имитации транспорта в целом и одного автомобиля следует использовать транзакты. Пункты выгрузки в модели будут представлять ОКУ.

    8.2.2. Программа модели

    ; Модель разгрузки транспортов
    ; Задание исходных данных
    IntTp	EQU		720	; Средний интервал поступления транспортов
    MOTip	EQU		6	; Матожидание типов автомобилей в транспорте
    SOTip	EQU		1	; Стандартное отклонение типов автомобилей
    MatA	EQU		11	; Матожидание автомобилей одного типа
    SOtkA	EQU		2	; Стандартное отклонение автомобилей одного типа
    KolPun	EQU		10	; Количество пунктов выгрузки
    VrMod	EQU		1440	; Время моделирования
    ;	Определение функций и булевых переменных
    SrVrA	FUNCTION	P3,D10	; Среднее время выгрузки
    1,8/2,10/3,12/4,7/5,6/6,9/7,11/8,5/9,13/10,10
    TipAvt	FUNCTION	RN64,C2	; Число типов автомобилей
    0,1/1,7
    ; Сегмент имитации поступления и обработки сообщений
    	GENERATE	(Exponential(33,0,IntTp)) ; Источник транспортов
    	SAVEVALUE	1,0	; Обнуление счетчика
    	ASSIGN		5,AC1	; Абсолютное модельное время входа транспорта
    	ASSIGN		2,(INT(Normal(77,MOTip,SOTip)-1))	;Число типов
    	SPLIT		*2	; Транзактов - по числу типов автомобилей
    	ASSIGN		2+,1	; Запомнить число типов автомобилей
    	ASSIGN		4,(INT(Normal(55,MatA,SOtkA)-1));Автомобили
    	SPLIT		*4	; Транзактов - по числу автомобилей
    	ASSIGN		4+,1	; Запомнить число автомобилей одного типа
    	TEST L		X1,KolPun,Met1 ; Есть свободные пункты выгрузки?
    	SAVEVALUE	1+,1
    Met2	SELECT MIN	3,1,KolPun,,FR	; Выбор пункта с min загрузкой
    	TEST NE		P3,0,Met1	; Есть пункты с min загрузкой?
    	QUEUE		P3	; Встать в очередь
    	SEIZE		P3	; Занять пункт выгрузки
    	DEPART		P3	; Покинуть очередь
    	ADVANCE		(Exponential(73,0,FN$SrVrA))	; Выгрузка
    	RELEASE		P3	; Освободить АРМ
    	UNLINK		PunSb,Met2,1	; Автомобиль на выгрузку
    	ASSEMBLE	*4	; Собрать автомобили одного типа
    	ASSEMBLE	*2	; Собрать автомобили всех типов
    	ASSIGN		6,AC1	; Время выхода транспорта
    	SAVEVALUE	VrVigS+,(P6-P5) ; Суммарное время выгрузки
    VigTr	TERMINATE	; Выгруженные транспорта
    Met1	LINK	PunSb,FIFO	; Автомобили, ожидающие выгрузки
    ; Сегмент задания времени моделирования
    	GENERATE	VrMod TEST	NE	N$VigTr,0,Met3
    	SAVEVALUE	VrVig,(X$VrVigS/N$VigTr)	; Среднее время выгрузки
    Met3	TERMINATE	1

    Замысел построения модели заключается в следующем. Блок GENERATE имитирует поступление транзактов. Один транзакт - один транспорт. Затем случайным образом определяется количество типов автомобилей в транспорте и заносится в параметр 2 транзакта. Исходный (порождающий) транзакт - транспорт копируется блоком SPLIT и результат копирования - число автомобилей различных типов в прибывшем транспорте копируется вторым блоком SPLIT. Результат копирования - число транзактов, равное числу автомобилей в транспорте. Число автомобилей одного типа заносится в параметр 4 всех транзактов, имитирующих автомобили данного типа.

    Далее первые десять транзактов-автомобилей (по числу пунктов выгрузки) поступают на блок SELECT, остальные - в список пользователя с именем PunSb. По мере освобождения пунктов выгрузки из списка пользователя выводятся транзакты и направляются на блок SELECT с меткой Met2. Результат работы блока SELECT - номер пункта выгрузки с минимальным коэффициентом загрузки заносится в параметр 3 вошедшего транзакта. Если результатом поиска блока SELECT является P3=0, т. е. номер нужного блока не найден, то транзакт блоком TEST снова отправляется в список пользователя. При успешном поиске транзакт занимает соответствующий пункт выгрузки.

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

    При входе транзакта-транспорта в модель и выходе из нее в параметры 5 и 6 записывается соответствующее модельное время. Оно используется для расчета времени разгрузки транспорта. Суммарное время разгрузки всех транспортов накапливается в ячейке VrVigS.

    Для работы с GPSS-моделью можно создать в какой-либо другой системе программирования, например, Delphi, интерфейс, который должен позволять осуществлять ввод исходных данных и вывод результатов моделирования. Например, в приведенной программе модели разгрузки транспортов вводить посредством интерфейса характеристики, для ввода которых используется команда EQU, а также среднее время выгрузки из одного автомобиля. При этом, естественно, необходимо разработать процедуры, формирующие в Delphi соответствующие строки программы GPSS-модели. Сама GPSS-программа также потребует модификации, для проведения которой нужно будет использовать команду INCLUDE и рассмотренные в п. 8.1 блоки OPEN, CLOSE, READ, WRITE для работы с текстовыми объектами и потоками данных.

    8.3. Создание стартовой формы приложения - имитационной модели

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

    При запуске Delphi автоматически создаётся новый проект. Вид экрана после запуска Delphi показан на рис. 8.1. Можно использовать этот проект для создания нового приложения. По умолчанию этот проект имеет название Project1.

    Стартовая форма создается путем изменения свойств формы .Свойства формы определяют ее внешний вид: размер, положение на экране, текст заголовка, вид рамки. Свойства перечислены на вкладке Properties (свойства) окна Object Inspector.В левой колонке находятся имена свойств, а в правой - их значения.

    Сначала надо изменить значение свойства Caption ( Заголовок ) - заменить Forml на Модель разгрузки транспортов. Для этого щелкнуть мышью в поле Caption.В результате этого в правой колонке, где находится текущее значение свойства - текст Forml, появляется курсор (рис. 8.2.).

    Используя клавишу <Backspase>, надо удалить Forml и ввести Модель разгрузки транспортов.

    Аналогичным образом можно установить значения свойств Height и Width, которые определяют высоту и ширину формы. Этим свойствам надо присвоить значения 530 и 715. Размер формы и элементов управления, а также положение формы на экране и элементов управления на поверхности формы задаются в пикселях, точках экрана.

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

    При разработке формы Form1 имитационной модели оставим свойство Color неизменным.

    (рис 8.1) Вид экрана после запуска Delphi(рис 8.2) Установка значения свойства Caption посредством ввода(рис 8.3) Установка значения свойства выбором из списка

    В поле значения свойства Font расположена командная кнопка с тремя точками, при нажатии на которую появляется стандартное диалоговое окно Windows выбора шрифта и его свойств (рис. 8.4). Для рассматриваемого примера выбран шрифт Times New Roman размером 10.

    Большинство свойств определяют внешний вид формы. Свойство Name определяет имя формы, которое используется в программе для управления формой.

    Ниже в табл. 8.2 приведены измененные свойства формы разрабатываемой имитационной модели. Остальные свойства формы оставлены без изменения и в таблице не приведены.

    (рис 8.4) Пример раскрытого списка уточняющих свойств свойства Font(рис 8.2) Пример раскрытого списка уточняющих свойств свойства Font
    Изменённые свойства формы имитационной модели
    Свойство Обозначение Значение
    Имя формы Name Form1
    Заголовок Caption Модель разгрузки транспортов
    Высота Height 530
    Ширина Width 715
    Шрифт Font. Name Times New Roman
    Размер шрифта Font. Size 10

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

    Создайте папки D:\ModRTr\Интерфей с и в последней сохраните проект. Чтобы сохранить проект, надо выполнить команду File/ Save Project As. Откроется окно Save Unit As. Выберите в нем и раскройте созданную ранее папку Интерфейс. В поле Имя файла введите имя программного модуля, например, Rasgruska, и щелкните кнопку Сохранить.

    После этого щелчка в диалоговом окне Save Unit As появится диалоговое окно Save Project As. В поле имя файла введите, например, Rasgr_transporta и щелкните кнопку Сохранить.

    (рис 8.5) Вид формы имитационной модели после установки значений свойств

    8.3 Добавление компонент в стартовую форму имитационной модели

    8.3.1. Добавление полей редактирования

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

    IntTp - средние значения интервалов поступления транспортов;

    MOТip, SOTip - математическое ожидание MOТip и стандартное отклонение SOTip количества типов автомобилей в транспорте;

    MatA, SOtkA - математическое ожидание MatA и стандартное отклонение SOtkA количества автомобилей одного типа в транспорте;

    KolPun - количество пунктов выгрузки;

    VrMod - время моделирования.

    В Windows данные с клавиатуры вводятся в поля редактирования. Поэтому в данную форму надо добавить компоненты - семь полей редактирования.

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

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

    (рис 8.6) Пиктограммы стандартной палитры компонентов

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

    Добавьте в форму, перейдя на вкладку Standard (см. рис. 8.6), семь компонентов редактирования Edit. У компонента Edit пиктограмма .

    Компонент формы, окруженный восемью маленькими квадратиками (см. на рис. 8.7 поле Edit1 ), называется выделенным (маркированным).Свойства маркированного компонента отображаются в окне Object Inspector.Ниже, в табл. 8.3, перечислены основные свойства компонента, называемого полем редактирования.

    На рис. 8.7 представлен вид формы после добавления к ней семи полей редактирования Edit1 Edit7.

    (рис 8.7) Форма имитационной модели с семью полями редактирования

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

    Основные свойства компонента поля редактирования
    Свойство Обозначение
    Имя поля. Используется в программе для доступа к содержимому (тексту) поля Name
    Текст, находящийся в поле ввода-редактирования Text
    Расстояние от левой границы поля до левой границы формы Left
    Расстояние от верхней границы поля до верхней границы формы Top
    Высота поля Height
    Ширина поля Width
    Шрифт, используемый для отображения вводимого текста Font
    Признак наследования свойств шрифта родительской формы ParentFont

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

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

    (рис 8.8) Окно Object Inspector с свойствами поля редактирования Edit1

    В табл. 8.4 приведены свойства полей редактирования, предназначенных для ввода IntTp, MOТip, SOTip, MatA, SOtkA, KolPun, VrMod.

    Свойства полей редактирования формы имитационной модели
    Name Edit1 Edit2 Edit3 Edit4 Edit5 Edit6 Edit7
    Text
    Top 30 60 90 30 60 90 120
    Left 16 16 16 350 350 350 16
    Height 21 21 21 21 21 21 21
    Width 50 50 50 50 50 50 50

    8.3.2. Добавление меток

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

    Текст, находящийся в форме, называется меткой. Добавляется метка к форме точно так же, как и поле редактирования. Пиктограмма метки (большая буква А) находится в палитре компонентов перед пиктограммой поля редактирования (см. рис. 8.6). После того как метка добавлена, можно, используя окно Object Inspector,изменить ее свойства.

    К форме разрабатываемого приложения надо добавить восемь меток. Все метки будут представлять собой информационные сообщения. Добавьте метки и установите значения их свойств согласно табл. 8.5. Форма разрабатываемого приложения будет иметь вид, представленный на рис. 8.9.

    Свойства меток формы имитационной модели
    Name Labell Label2 Label3 Label4 Label5 Label6 Label7 Label8
    Caption
    AutoSize false true true true true true true true
    Top 0 30 60 90 30 60 90 120
    Left 140 70 70 70 410 410 410 70
    Wordwrap true true true true true true True true
    ParentFont false true true true true true true true
    (рис 8.9) Вид формы имитационной модели после добавления меток

    Как видно по рис. 8.9, из полей редактирования необходимо удалить их имена Edit1…Edit7. На этом же рисунке указано свойство Caption для каждой метки - информационное сообщение. Например, для Labell: Введите исходные данные и нажмите кнопку ВВОД. Для Labell: Средний интервал поступления транспортов.

    Свойство ParentFont метки Labell имеет значение false, поэтому свойство Font этой метки не наследует значения свойства Font "родителя", в данном случае основной формы. Это дает возможность установить свойства шрифта метки иные, чем у формы. У меток Label2…Label8 значение свойства ParentFont оставлено без изменения. Значит, они наследуют свойства Font "родителя".

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

    У меток Label2…Label8 свойству AutoSize установлено значение true, а у метки Label1 - false.

    8.3.3. Добавление компонент для ввода и вывода данных, представленных в виде таблиц

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

    Значок компонента StringGrid находится на дополнительной ( Additional ) странице палитры компонентов. В разрабатываемую форму имитационной модели необходимо добавить два компонента. Один компонент для ввода табл. 8.1. В данной модели результаты моделирования целесообразно вывести таблицей. Поэтому нужен второй компонент StringGrid. Добавьте два компонента. Добавляются они также, как и другие компоненты.

    Добавленные компоненты StringGrid имеют стандартные свойства. Delphi предоставляет разработчику возможность изменить эти свойства после добавления компонентов в форму.

    В табл. 8.6 перечислены основные свойства компонента StringGrid.

    Основные свойства компонента StringGrid
    Свойство Описание
    Name Имя компонента. Используется в программе для доступа к свойствам компонента
    ColCount Количество колонок таблицы
    RowCount Количество строк таблицы
    Cells Соответствующий таблице двумерный строковый массив. Если строки и столбцы нумеровать с нуля, то ячейке Cells соответствует Cells (i,j)
    FixedCols Количество зафиксированных слева столбцов таблицы. Они выделяются цветом и при горизонтальной прокрутке таблицы остаются на месте
    FixedRows Количество зафиксированных сверху строк таблицы. Они выделяются цветом и при вертикальной прокрутке таблицы остаются на месте
    Options Свойство используется для задания других атрибутов таблицы (табл. 8.7)
    DefaultColWidth Ширина столбцов таблицы
    DefaultRowHeight Высота строк таблицы
    GridLineWidth Ширина линий, ограничивающих ячейки таблицы
    Left Расстояние от левой границы поля таблицы до левой границы формы
    Top Расстояние от верхней границы поля таблицы до верхней границы формы
    Height Высота поля таблицы
    Width Ширина поля таблицы
    Font Шрифт, используемый для отображения содержимого ячеек таблицы
    ParentFont Признак наследования характеристик шрифта формы

    Из всех свойств следует обратить внимание на свойство Options. Свойство Options используется для задания многих атрибутов таблицы (компонента StringGrid ), которые описаны в табл. 8.7. На вкладке, показанной на рис. 8.10, перед свойством Options стоит знак " + ". При двойном нажатии на него появляется вкладка с вложенными свойствами свойства Options (рис. 8.10).

    Атрибуты таблицы, задаваемые свойством Options
    Атрибут Описание (для значения True )
    goFixedHorzLine Горизонтальные линии фиксированы
    goFixedVertLine Вертикальные линии фиксированы
    goHorzLine Горизонтальные разделительные линии отображаются
    goVertLine Вертикальные разделительные линии отображаются
    goRangeSelect Можно выбирать несколько ячеек
    goDrawFocusSelected Текущая ячейка помечается цветом
    goRowSizing Возможно изменение размеров строк
    goColSizing Возможно изменение размеров столбцов
    goRowMoving Возможно перемещение строк
    goColMoving Возможно перемещение столбцов
    goEditing Возможно редактирование содержимого ячеек
    goTabs Возможно перемещение по ячейкам клавишами Tab и Shift-Tab
    goThumbTracking Содержимое таблицы скроллируется с помощью полос прокрутки

    Свойства, перечисленные в табл. 8.6 и табл. 8.7, после выделения (маркирования) соответствующей таблицы устанавливаются либо заданием какого - то числового значения, либо выбором True или False (рис. 8.10).

    Для ввода данных табл. 8.1 необходимо изменить некоторые из свойств StringGrid. Например, для того, чтобы была возможность редактировать содержимое ячеек таблиц, нужно установить свойство goEditing True, а для перемещения курсора с помощью клавиш Tab и стрелок - свойство goTabs также установить True.

    В табл. 8.8 приведены значения свойств обеих компонентов StringGrid, используемых моделью для ввода и вывода данных. Установите эти значения. Форма должна иметь вид, показанный на рис. 8.11. Введите также метки Label9 и Label10 (см. рис. 8.11).

    (рис 8.10) Вкладка свойства Options (рис 8.8) Вкладка свойства Options
    Значения свойств компонента StringGrid1
    СвойствоКомпоненты
    12
    Name Tabl1 Tabl2
    ColCount 11 11
    RowCount 2 5
    FixedCols 1 1
    FixedRows 1 1
    Options.goEditing True True
    Options.goTabs True True
    DefaultColWidth 70 125
    DefaultRowHeight 24 24
    GridLineWidth 1 1
    goRowSizing True True
    (рис 8.11) Вид формы после добавления компонентов StringGrid

    Первая строка и первый столбец таблиц зафиксированы (см. рис. 8.11). Они используются в качестве заголовков таблиц. В рассматриваемом примере в первой строке первой таблицы это тип автомобиля (номера 1 … 10), во второй таблице - пункты выгрузки (также номера 1 … 10). Следует отметить, что можно было бы ввести в эти ячейки и наименования вместо порядковых номеров. Как это делается, покажем на примере ввода поясняющего текста в строки таблиц. Во вторую строку первой таблицы - Cells(0, 1) - введем: Время, мин. Во вторую таблицу: Cells(0, 1) - Коэф. загр.; Cells(0, 2) - Ср. время ; Cells(0, 3) - Макс. очер. Во время создания формы имитационной модели установить значения элементов Cells таблицы нельзя, так как элементы таблицы доступны только во время работы программы. Поэтому значения элементов Cells таблицы, соответствующие первой строке и первому столбцу обеих таблиц устанавливают процедуры FormActivate1 и FormActivate2 (текст их приведен ниже) во время активизации формы. В какой процедуре обработки события производится вызов указанных процедур, укажем позже.

    procedure TForm1.FormActivate1(Sender: TObject);
    var  n1:integer;
    begin
      for n1:=1 to Tabl1.ColCount do
        Tabl1.Cells[n1,0]:=IntToStr(n1);
      Tabl1.Cells[0,1]:='Время, мин';
    end;
    procedure TForm1.FormActivate2(Sender: TObject);
    var  n1:integer;
    begin
      for n1:=1 to Tabl2.ColCount do
        Tabl2.Cells[n1,0]:=IntToStr(n1);
      Tabl2.Cells[0,1]:='Коэф.исп.пункт. разгр.';
      Tabl2.Cells[0,2]:='Ср.вр.разгр.авт.,мин';
      Tabl2.Cells[0,3]:='Макс.очер.на пун.разгр.';
      Tabl2.Cells[0,4]:='Ср.вр.разгр.тран.,час';
    end;

    8.3.4. Добавление командных кнопок

    Для управления работой имитационной модели к форме надо добавить шесть командных кнопок (рис. 8.12).

    В модели предусмотрен пример. При нажатии кнопки ПРИМЕР автоматически вводятся исходные данные, курсор устанавливается на кнопке МОДЕЛИРОВАНИЕ. Нажатием этой кнопки переходят к процессу моделирования.

    (рис 8.12) Стартовая форма имитационной модели

    По окончании моделирования для вывода результатов нужно нажать кнопку ВЫВОД. Результаты моделирования появятся в нижней таблице.

    Если производилось моделирование примера, а потом нужно выполнить моделирование с другими исходными данными, нажатием кнопки СБРОС можно удалить данные примера и ввести новые. Использование кнопки СБРОС удобно в том случае, если очередной ввод исходных данных требует большого количества изменений. После этого нажать кнопку ВВОД и нажатием кнопки МОДЕЛИРОВАНИЕ перейти к процессу моделирования, по завершении которого нажать кнопку ВЫВОД.

    Нажатие на кнопку ВЫХОД ИЗ МОДЕЛИ приводит к завершению работы программы имитационной модели. Закрывается открытая форма приложения.

    Кнопки добавляются в форму точно так же, как и другие компоненты. Пиктограмма командной кнопки _2U,находится на палитре стандартных компонентов (см. рис. 8.6). После добавления кнопок с помощью диалогового окна Object Inspector надо установить требуемые значения их свойств (табл. 8.9).

    Свойства кнопок стартовой формы имитационной модели
    Name Button1 Button2 Button3 Button4 Button5 Button6
    Caption Ввод Сброс Моделирование Выход из модели Пример Вывод
    Top 470 470 470 470 470 470
    Left 176 96 256 528 16 424
    Height 25 25 25 25 25 25
    Width 75 75 161 169 75 75

    После запуска программы курсор сразу автоматически устанавливается в поле редактирования Edit1 для ввода переменной Средний интервал поступления транспортов. Поэтому в форме указано, что надо сначала ввести данные, потом нажать кнопку ВВОД и только потом кнопку МОДЕЛИРОВАНИЕ.

    8.4. События и процедуры обработки событий

    8.4.1. События

    Вид созданной формы подсказывает, как работает приложение. Очевидно, что пользователь должен ввести значения в поля редактирования, нажать ВВОД и потом щелкнуть кнопку МОДЕЛИРОВАНИЕ. Щелчок на изображении командной кнопки - это пример того, что в Windows называется событием.

    Событие - это то, что происходит во время работы приложения. В Delphi у каждого события есть имя, например, щелчок кнопкой мыши это событие OnClick, двойной щелчок - событие onDblClick.

    В табл. 8.10 приведены некоторые события Windows.

    Реакцией на событие должно быть какое-либо действие. Например, реакцией на событие OnClick, произошедшее на кнопке МОДЕЛИРОВАНИЕ,должен быть переход к запуску имитационной модели. В Delphi реакция на событие реализуется как процедура обработки события.Таким образом, задача программиста состоит в написании необходимых процедур обработки событий.

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

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

    Перечень некоторых событий Windows
    Событие Содержание
    OnClick Происходит при щелчке кнопкой мыши
    OnDblClick Происходит при двойном щелчке кнопкой мыши
    OnEnter Происходит перед тем, как элемент управления действительно получает фокус
    OnError Происходит, когда элемент контроля обнаруживает ошибку и не может вернуть информацию об ошибке вызывающей программе
    OnExit Происходит непосредственно перед тем, как элемент управления теряет фокус
    OnKeyDown Происходит при нажатии на клавишу. События OnKeyDown и OnKeyPress - это чередующиеся, повторяющиеся события, которые происходят до тех пор, пока не будет отпущена удерживаемая клавиша (в этот момент происходит событие OnKeyUp )
    OnKeyPress Происходит, когда пользователь нажимает клавишу, которая генерирует печатаемый символ. Может происходить также при нажатии клавиши печатаемого символа с <Ctrl>. He происходит при нажатии клавиш <Tab>, <Enter>, клавиш перемещения курсора
    OnKeyUp Происходит при отпускании нажатой клавиши
    OnMouseDown Происходит при нажатии кнопки мыши
    OnMouseMove Происходит при перемещении мыши
    OnMouseUp Происходит при отпускании кнопки мыши

    8.4.2. Разработка процедур обработки событий для кнопок

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

    Затем нужно выбрать вкладку Events (события) окна Object Inspector.В результате этих действий в окне Object Inspector появится вкладка со списком событий, которые способен воспринимать маркированный компонент, в данном случае - командная кнопка (рис. 8.13).

    В левой колонке вкладки перечислены имена событий, на которые может реагировать маркированный объект. Если для события определена процедура обработки события, то в правой колонке, рядом с именем события выводится ее имя.

    Чтобы создать процедуру обработки события, надо сделать двойной щелчок в поле имени процедуры обработки события. В результате открывается окно редактора кода (в Delphi кодом называется текст программы) с макетом процедуры обработки события (рис. 8.14).

    (рис 8.13) Вкладка Events командной кнопки ВВОД (Button1)(рис 8.14) Окно редактора кода с макетом процедуры обработки события, происходящего на кнопке Button1 (ВВОД)

    Delphi автоматически присваивает процедуре обработки события имя. Имя процедуры обработки события состоит из двух частей. Первая часть идентифицирует форму, которой принадлежит объект, для которого создается процедура обработки события. Вторая часть имени идентифицирует сам объект и событие. В нашем случае имя формы - Form1, Button1 - имя командной кнопки ВВОДимя события - Click.

    В окне редактора кода (см. рис. 8.14) между begin и end можно печатать инструкции Object Pascal, реализующие процедуру обработки события. Введите следующий программный код:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ProvVvod1;
      begin
        MOTip:=StrToFloat(Edit2.text);
        SOTip:=StrToFloat(Edit3.text);
        MatA:=StrToFloat(Edit4.text);
        SOtkA:=StrToFloat(Edit5.text);
      end;
      if (SOTip*5)>MOTip then begin
        MessageDlg('Стандартное отклонение SOTip'+#13
          +'должно быть более чем в 5 раз меньше'+#13
          +'математического ожидания MOTip',
          mtWarning,[mbOk],0);
        Edit3.SetFocus;
      end
      else if (SOtkA*)>MatA then begin
        MessageDlg('Стандартное отклонение SOtkA'+#13
          +'должно быть более чем в 5 раз меньше'+#13
          +'математического ожидания MatA',
          mtWarning,[mbOk],0);
        Edit5.SetFocus;
      end;
      ProvVvod2; Tabl1.SetFocus;
    end;

    В тексте процедуры выделено то, что сформировано Delphi. Остальное вводится разработчиком.

    Обработка события при щелчке кнопки ВВОД происходит так. Вначале процедурой ProvVvod1 проверяется, все ли данные введены в поля редактирования. Если все данные введены, производится их перевод в вещественный тип.

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

    Далее процедурой ProvVvod2 проверяется полнота ввода данных в первую таблицу StrinGrid. Создайте процедуры ProvVvod1, ProvVvod2 в разделе implementation программного модуля (.pas ).

    procedure TForm1.ProvVvod1;
    begin
      begin
        if (Edit1.text='') or (Edit2.text='')
        or (Edit3.text='') or (Edit4.text='')
        or (Edit5.text='') or (Edit6.text='')
        or (Edit7.text='') then
          MessageDlg('Необходимо задать все'+#13
            +'исходные данные'+#13
            + 'в полях редактирования',
            mtWarning,[mbOk],0);
      end;
      begin
        if Edit1.text='' then Edit1.SetFocus;
        if Edit2.text='' then Edit2.SetFocus;
        if Edit3.text='' then Edit3.SetFocus;
        if Edit4.text='' then Edit4.SetFocus;
        if Edit5.text='' then Edit5.SetFocus;
        if Edit6.text='' then Edit6.SetFocus;
        if Edit7.text='' then Edit7.SetFocus;
      end;
    end;
    
    procedure TForm1.ProvVvod2;
    begin
      begin
        if (Tabl1.Cells[1,1]='') or (Tabl1.Cells[2,1]='') or (Tabl1.Cells[3,1]='')
        or (Tabl1.Cells[4,1]='') or (Tabl1.Cells[5,1]='') or (Tabl1.Cells[6,1]='')
        or (Tabl1.Cells[7,1]='') or (Tabl1.Cells[8,1]='') or (Tabl1.Cells[9,1]='')
        or (Tabl1.Cells[10,1]='')
        then
          MessageDlg('Необходимо задать все'+#13
            +'исходные данные в таблице',
            mtWarning,[mbOk],0);
      end;
      Tabl1.SetFocus;
    end;

    Объявите в интерфейсной части эти процедуры.

    type TForm1 = class(TForm)
        Edit1: TEdit;
        …
        procedure ProvVvod1;
        procedure ProvVvod2;
      private

    При нажатии кнопки СБРОС все поля редактирования и ячейки Tabl1 очищаются. Создайте обработчик этого события, программный код которого приведен ниже.

    procedure TForm1.Button2Click(Sender: TObject);
    var n1,n2:integer;
    begin
      Edit1.text:='';
      Edit2.text:='';
      Edit3.text:='';
      Edit4.text:='';
      Edit5.text:='';
      Edit6.text:='';
      Edit7.text:='';
      for n1:=1 to 10 do
        Tabl1.Cells[n1,1]:='';
      for n2:=1 to 3 do
        for n1:=1 to 10 do
          Tabl2.Cells[n1,n2]:=''; Edit1.SetFocus;
    end;

    Нажатием кнопки МОДЕЛИРОВАНИЕ производится переход к процессу моделирования. Создайте обработчик этого события согласно следующему программному коду.

    procedure TForm1.Button3Click(Sender: TObject); begin
    VivProgr;
    WinExec('d:\ModRTr\GPSSW.exe',SW_RESTORE);
    Button6.SetFocus;
    end;

    При обработке этого события вначале выполняется процедура VivProgr, состоящая в свою очередь из четырех процедур VivProgr1, VivProgr2, VivProgr3 и VivProgr4. Они формирует следующие тестовые файлы с фрагментами программы GPSS:

  • Progr1.txt для ввода данных командой EQU и посредством функции SrVrA (процедура VivProgr1 );
  • Progr2.txt для ввода времени моделирования из поля редактирования Edit7 (процедура VivProgr2 );
  • Progr3.txt - для вывода результатов моделирования в текстовый файл DanTabl211.txt (процедура VivProgr3 );
  • Progr4.txt - для вывода результатов моделирования в текстовый файл DanTabl212.txt (процедура VivProgr4 );
  • Progr5.txt - для вывода результатов моделирования в текстовый файл DanTabl213.txt (процедура VivProgr5 );
  • Создайте в разделе implementation программного модуля ( .pas ) программные коды шести процедур.

    procedure TForm1.VivProgr;
      begin
        VivProgr1;
        VivProgr2;
        VivProgr3;
        VivProgr4;
        VivProgr5;
      end;
    
    procedure TForm1.VivProgr1;
    var
      f:TextFile;
    begin
      AssignFile(f,'d:\ModRTr\Progr1.txt');
      Rewrite(f);
      writeln(f,'IntTp EQU ',Edit1.text);
      writeln(f,'MOTip EQU ',Edit2.text);
      writeln(f,'SOTip EQU ',Edit3.text);
      writeln(f,'MatA EQU ',Edit4.text);
      writeln(f,'SOtkA EQU ',Edit5.text);
      writeln(f,'KolPun EQU ',Edit6.text);
      writeln(f,'VrMod EQU ',Edit7.text);
      writeln(f,'SrVrA FUNCTION P3,D',(Tabl1.ColCount-1));
      writeln(f,'1,',Tabl1.Cells[1,1],'/2,',Tabl1.Cells[2,1],'/3,',Tabl1.Cells[3,1],
        '/4,',Tabl1.Cells[4,1],'/5,',Tabl1.Cells[5,1],'/6,',Tabl1.Cells[6,1],
        '/7,',Tabl1.Cells[7,1],'/8,',Tabl1.Cells[8,1],'/9,',Tabl1.Cells[9,1],
        '/10,',Tabl1.Cells[10,1]);
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr2;
    var
      f:TextFile;
    begin
      AssignFile(f,'d:\ModRTr\Progr2.txt');
      Rewrite(f);
      writeln(f,'GENERATE ', StrToFloat(Edit7.text);
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr3;
    var
      f:TextFile;
      n1:integer;
    begin
      AssignFile(f,'d:\ModRTr\Progr3.txt');
      Rewrite(f);
      writeln(f,'OPEN ("DanTabl21.txt"),1,Kon1');
      for n1:=1 to StrToInt(Edit6.text) do
        writeln(f,'WRITE FR',n1,',,,OFF');
      writeln(f,'Kon1 CLOSE Err1,1');
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr4;
    var
      f:TextFile;
      n1:integer;
    begin
      AssignFile(f,'d:\ModRTr\Progr4.txt');
      Rewrite(f);
      writeln(f,'OPEN ("DanTabl22.txt"),1,Kon2');
      for n1:=1 to StrToInt(Edit6.text) do
        writeln(f,'WRITE FT',n1,',,,OFF');
      writeln(f,'Kon2 CLOSE Err1,1');
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr5;
    var
      f:TextFile;
      n1:integer;
    begin
      AssignFile(f,'d:\ModRTr\Progr5.txt');
      Rewrite(f);
      writeln(f,'OPEN ("DanTabl23.txt"),1,Kon3');
      for n1:=1 to StrToInt(Edit6.text) do
        writeln(f,'WRITE QM',n1,',,,OFF');
      writeln(f,'WRITE X$VrVig',',,,OFF')
      writeln(f,'Kon3 CLOSE Err1,1');
      CloseFile(f);
    end;

    Объявите в интерфейсной части программного модуля эти шесть процедур.

    type TForm1 = class(TForm)
        Edit1: TEdit;
        …
        procedure VivProgr;
        procedure VivProgr1;
        procedure VivProgr2;
        procedure VivProgr3;
        procedure VivProgr4;
        procedure VivProgr5;
    private

    После выполнения процедуры VivProgr командой

    WinExec('d:\ModRTr\GPSSW.exe',SW_RESTORE);

    запускается GPSS.exe. И далее пользователем - приложение Модель разгрузки транспортов. Курсор устанавливается на кнопке ВЫВОД.

    Для обработки события - щелчка кнопки ВЫВОД - используйте следующий программный код:

    procedure TForm1.Button6Click(Sender: TObject);
      begin
        FormActivate2(Sender);
        VivRes1;
        VivRes2;
        VivRes3;
      end;

    Обработка события начинается с выполнения процедуры FormActivate2(Sender). В результате этого вводятся заголовки в первую строку и в первый столбец второй таблицы. Затем последовательно выполняются процедуры VivRes1, VivRes2 и VivRes3, которые считывают результаты моделирования из файлов DanTabl211.txt, DanTabl212.txt и DanTabl213.txt соответственно и выводят их построчно во вторую таблицу.

    Создайте обработчик события - щелчка кнопки ВЫВОД и в разделе implementation программного модуля ( .pas ) создайте процедуры FormActivate2(Sender) (см. п. 8.3.3), VivRes1, VivRes2 и VivRes3.

    procedure TForm1.VivRes1;
    var
      f:TextFile;
      n1:integer;
      a:real;
      begin
        AssignFile(f, 'd:\ModRTr\DanTabl21.txt');
        Reset(f);
        for n1:=1 to (Tabl2.ColCount-1) do begin
          read(f,a);
          a:=Trunc(a);
          a:=a/1000;
          Tabl2.Cells[n1,1]:=FloatToStr(a);
        end;
      end;
    
    procedure TForm1.VivRes2;
    var
      f:TextFile;
      n1:integer;
      a:real;
      begin
        AssignFile(f, 'd:\ModRTr\DanTabl22.txt');
        Reset(f);
        for n1:=1 to (Tabl2.ColCount-1) do begin
          read(f,a);
          a:=a*1000;
          a:=Trunc(a);
          a:=a/1000;
          Tabl2.Cells[n1,2]:=FloatToStr(a);
        end;
      end;
    
    procedure TForm1.VivRes3;
    var
      f:TextFile;
      n1:integer;
      a:real;
      begin
        AssignFile(f, 'd:\ModRTr\DanTabl23.txt');
        Reset(f);
        for n1:=1 to (Tabl2.ColCount-1) do
        begin
          read(f,a);
          Tabl2.Cells[n1,3]:=FloatToStr(a);
        end;
      end;

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

    type TForm1 = class(TForm)
        Edit1: TEdit;
        …
        procedure FormActivate2(Sender: TObject);
        procedure VivRes1;
        procedure VivRes2;
        procedure VivRes3;
      private

    Завершение работы с программой модели происходит при нажатии кнопки ВЫХОД ИЗ МОДЕЛИ. Результатом является закрытие формы приложения. Создайте обработчик этого события.

    procedure TForm1.Button4Click(Sender: TObject);
      begin
        Form1.close;
      end;

    8.4.3. Разработка процедур обработки событий для полей редактирования

    В соответствии с видом формы имитационной модели сформулируем следующие требования к программе:

  • в поля исходных данных модели допускается вводить только положительные числа, а ввод других символов программа должна блокировать;
  • числа, вводимые в поля Edit3 и Edit5, не должны быть равны или больше чисел, вводимых в поля соответственно Edit2 и Edit4 (стандартное отклонение должно быть в пять раз и более меньше математического ожидания);
  • во время ввода данных модели при нажатии на клавишу Enter курсор автоматически должен перемещаться в поле ввода следующего числа. Если клавиша Enter нажата во время ввода в поле Edit7, программа должна перейти к вводу в первую таблицу;
  • при обнаружении ошибок при вводе в поля Edit3 или Edit5 курсор должен быть соответственно в одном из них;
  • если в какое - то поле не введена хотя бы одна цифра (поле пустое) и нажата клавиша Enter, то возникает ошибка, о чем выдается сообщение, и ввод нужно повторить.
  • Чтобы программа удовлетворяла вышеприведенным требованиям, надо для каждого поля редактирования написать процедуру обработки события OnKeyPress, которая в зависимости от того, какую клавишу нажал пользователь, будет выполнять нужное действие.

    Заготовка процедуры OnKeyPress для Edit1, генерируемая Delphi, выглядит следующим образом:

    Procedure Tform1.Edit1KeyPress(Sender:Tobject; var Key:Char);
      begin
      end;

    Заголовок процедуры Edit1KeyPress показывает, что процедура в качестве параметра получает символьную переменную Key. Эта переменная содержит символ, соответствующий нажатой клавише. Следует обратить внимание на то, что параметр принимается по ссылке (перед именем переменной стоит слово var ), поэтому процедура может изменить значение переменной. Символ, соответствующий нажатой клавише, появляется в поле редактирования после выполнения процедуры обработки события OnKeyPress, поэтому процедура обработки может заменить введенный символ или присвоением переменной Key значения Chr(0) запретить его появление в поле редактирования.

    Ниже приведен программный код процедуры обработки события OnKeyPress в поле редактирования.

    рrocedure TForm1.Edit1KeyPress(Sender:Tobject; var Key:Char);
      begin
        case Key of
          '0'..'9',Chr(8):;
          '-':Key:=Chr(0);
          ',':if pos(',',Edit1.text)<> then Key:=Chr(0);
          Chr(13):Edit2.SetFocus
          '.': begin
              MessageDlg('Для отделения дробной части' +'числа'+#13
                +'от целой используйте запятую', mtInformation, [mbOk],0);
              Key:=Chr(0);
            end;
          else Key:=Chr(0);
        end;
      end;

    Процедура TForm1.Edit1KeyPress проверяет, какая клавиша нажата при вводе исходных данных в поле редактирования Edit1. Если нажата клавиша BackSprace, то процедура завершает свою работу и символ появляется в поле редактирования или стирается последний введённый символ. Если нажата запятая, то процедура проверяет, есть ли уже запятая в поле редактирования. Если есть, то ввод второй запятой блокируется. Если нажата клавиша "-", то ввод её тоже блокируется. Если нажата клавиша Enter, то применением метода SetFocus к полю редактирования Edit2 курсор перемещается в это поле.

    Процедуры обработки события OnKeyPress полей редактирования отличаются только способом обработки нажатия клавиши Enter (в поле Edit1 Edit2.SetFocus, в поле Edit2 Edit3.SetFocus и т.д., а в поле Edit7

    then
      begin
        FormActivate1(Sender);
        Tabl1.SetFocus;
      end;

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

    Создайте в разделе implementation программный код процедур EditKeyPress и FormActivate1 (см. п. 8.3.3).

    procedure TForm1.EditKeyPress(Sender: TObject; var Key: Char);
    var
      nak:string[20];
      begin
      if Sender=Edit1 then
        nak:=Edit1.text
      else if Sender=Edit2 then
        nak:=Edit2.text
      else if Sender=Edit3 then
        nak:=Edit3.text
      else if Sender=Edit4 then
        nak:=Edit4.text
      else if Sender=Edit5 then
        nak:=Edit5.text
      else if Sender=Edit6 then
        nak:=Edit6.text
      else nak:=Edit7.text;
      case Key of
        '0'..'9',Chr(8):;
        '-':Key:=Chr(0);
        ',':if pos(',',nak) <>0 then Key:=Chr(0);
        Chr(13):if Sender=Edit1
            then Edit2.SetFocus
            else if Sender=Edit2
            then Edit3.SetFocus
            else if Sender=Edit3
            then Edit4.SetFocus
            else if Sender=Edit4
            then Edit5.SetFocus
            else if Sender=Edit5
            then Edit6.SetFocus
            else if Sender=Edit6
            then Edit7.SetFocus
            else if Sender=Edit7
            then
              begin
                FormActivate1(Sender);
                Tabl1.SetFocus;
              end;
        '.':begin
            MessageDlg('Для отделения дробной'
              +'части от целой'+#13
              +'используйте запятую',
              mtInformation,[mbOk],0);
            Key:=Chr(0);
          end;
        else Key:=Chr(0)
      end;
    end;

    Объявите в интерфейсной части:

    type TForm1 = class(TForm)
      Edit1: TEdit;
      …
      procedure FormActivate1(Sender: TObject);
    private

    Теперь выделите компонент Edit2 и на вкладке Events раскройте список. Из списка для onKeyPress щелчком установите EditKeyPress. Проделайте тоже для компонентов Edit3 … Edit7.

    8.4.4. Модификация программы имитационной модели

    Интерфейс приложения разработан. Согласно интерфейсу внесем изменения в исходную GPSS-модель (см. п. 8.2.2). Заменим строки программы с командой EQU и строки

    SrVrA	FUNCTION	P3,D10	; Среднее время выгрузки
    1,26/2,20/3,30/4,25/5,15/6,18/7,28/8,32/9,23/10,30

    командой

    INCLUDE          "Progr1.txt"        ; Подключение файла

    Модифицируем также сегмент задания времени моделирования.

    ;Сегмент задания времени моделирования
    	INCLUDE		"Progr2.txt" ; Подключение файла
    	TEST E		TG1,1,Met3 ; При TG1=1 - расчет результатов моделирования
    ;	TEST NE		N$VigTr,0,Met3
    	SAVEVALUE	VrVig,((X$VrVigS/N$VigTr)/60) ; Среднее время выгрузки, час
    	INCLUDE		"Progr3.txt" ; Подключение файла
    	INCLUDE		"Progr4.txt" ; Подключение файла
    	INCLUDE		"Progr5.txt" ; Подключение файла
    Met3	TERMINATE     1

    Разработка имитационной модели в виде приложения с интерфейсом завершена.

    Отладьте приложение и перейдите к работе с ним.

    8.5. Работа с приложением

    Поместите в папку D:\ModRTr файл GPSS.exe и GPSS-модель ModRasgTr.gps. Нахождение файла Rasg_transporta.exe в этой же папке необязательно. Запустите Rasg_transporta.exe.

    Нажмите кнопку ПРИМЕР. Автоматически будут введены данные, показанные на рис. 8.15.

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

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

    Нажмите OK. Повторите ввод числа с отделением его целой части от дробной части запятой в это же поле редактирования. Нажмите кнопку ВВОД. Появится предупреждение о другой ошибке (рис. 8.17). Нажмите OK и исправьте ошибку.

    (рис 8.15) Форма приложения с данными примера(рис 8.16) Сообщение об ошибке при вводе числа(рис 8.17) Сообщение об ошибке при вводе стандартного отклонения

    Далее удалите, например, количество пунктов разгрузки из поля редактирования и щелкните ВВОД. Появится предупреждение о том, что необходимо задать все исходные данные в полях редактирования (рис. 8.18). Щелкните OK и исправьте ошибку.

    Теперь удалите, например, среднее время разгрузки автомобиля второго типа из первой таблицы и щелкните ВВОД. Появится предупреждение о том, что необходимо задать все исходные данные в полях редактирования (рис. 8.19). Щелкните OK, исправьте ошибку и нажмите ВВОД.

    (рис 8.18) Предупреждение о необходимости ввода всех данных в поля редактирования(рис 8.19) Предупреждение о необходимости ввода всех данных в первую таблицу

    Теперь ошибок ввода исходных данных нет. Щелкните кнопку МОДЕЛИРОВАНИЕ.

    Выполните необходимые действия с GPSS-моделью. Закройте GPSS-exe и нажмите активную кнопку ВЫВОД. Во второй таблице появятся результаты моделирования (рис. 8.20):

  • среднее время разгрузки автомобилей различных типов;
  • коэффициенты использования пунктов разгрузки;
  • максимальные очереди на пункты разгрузки;
  • среднее время разгрузки одного транспорта.
  • (рис 8.20) Форма приложения с данными и результатами моделирования

    Вопросы для самоконтроля

  • Какова цель предназначения текстовых объектов и потоков данных?
  • Какой командой подключаются текстовые объекты к объе-ту GPSS World "Модель"? Формат этой команды.
  • Назначение и формат блока OPEN.
  • Назначение и формат блока CLOSE.
  • Назначение и формат блока READ.
  • Назначение и формат блока WRITE.
  • Назовите режимы работы блока WRITE и дайте им характеристику.
  • Назначение и формат блока SEEK.
  • Назначение и формат блока SELECT.
  • Страницы:

    8.1. Применение текстовых объектов и потоков данных

    Модель представляет собой набор операторов, содержащихся в одном объекте "Модель" и в любом количестве необязательных текстовых объектов.

    Текстовые объекты с наборами операторов модели подключаются к объекту "Модель" командой INCLUDE. Формат команды:

    INCLUDE         A

    Операнд А - спецификация файла (полный путь доступа к файлу). Допустимые значения - String. Например:

    INCLUDE         "DanDon.txt"
    INCLUDE          "D:\Primer\DanZad.txt"

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

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

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

    Команда INCLUDE допускает пять уровней вложенности файлов модели. Нельзя помещать команду INCLUDE в Plus-процедуру.

    Операторы INCLUDE можно также закреплять за функциональными клавишами. Это позволяет одним нажатием клавиши объекту "Процесс моделирования" передать набор команд и (или) Plus-операторов, содержащихся в текстовом файле.

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

    Поток данных - это последовательность текстовых строк, используемых процессом моделирования. Существуют два типа потоков данных:

  • потоки ввода-вывода (I/O или "файловые" потоки) для доступа к файлам;
  • потоки в памяти для тестирования или прямого доступа к внутренним данным.
  • Основной элемент потока данных - текстовая строка, которая является строкой печатных символов, включая пробелы.

    Для обработки потоков данных существуют пять блоков GPSS World: OPEN, CLOSE, READ, WRITE, SEEK. Три из них - READ, WRITE, SEEK - выполняют операции только с одной отдельной строкой текста.

    Перейдем к рассмотрению блоков обработки потоков данных.

    8.1.1. Блок OPEN

    Блок OPEN предназначен для инициализации потока данных. Формат блока:

    OPEN   A,[B],[C]

    Операнд А - дескриптор потока данных. Операнд определяет тип потока данных. Он обрабатывается как строка. Если это нулевая строка, создается поток в памяти. Если это канальное имя, такое как "\pipe\mypipe", создается канальный поток. В противном случае создается поток ввода-вывода и предполагается, что операнд А является спецификацией файла.

    Операнд В - номер потока данных, произвольное положительное число, задаваемое пользователем. Нумерация потоков введена с целью использования одновременно в одном процессе моделирования нескольких потоков данных. По умолчанию номер потока данных равен 1.

    Операнд С - метка блока, в который направляется транзакт в случае ошибки инициализации потока данных. Коды ошибок:

  • 0 - нет ошибки;
  • 10 - длинное имя файла;
  • 11 - ошибка чтения внешнего файла;
  • 12 - во время попытки открыть файл был запрещен доступ к памяти.
  • OPEN   ("Plan.txt"),3,Kon1
    OPEN   ("G\Model\NorPogr.txt")
    OPEN   ("")

    В первом примере открывается поток ввода-вывода, потоку присваивается номер 3 и в случае ошибки открытия активный транзакт направляется к блоку с меткой Kon1. Операндом А указан неполный путь доступа к файлу, поэтому подразумевается, что используется папка объекта "Процесс моделирования". Если файл с указанным именем не найден, то предполагается, что файл создается, и ошибка не возникает.

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

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

    Замечание.Если указанный операндом А файл найден, во время обработки блока OPEN он полностью загружается в виртуальную память. Все находившиеся в файле данные хранятся как часть объекта "Процесс моделирования" до тех пор, пока поток данных не будет закрыт. Все изменения данных отражаются в файловой системе только после того, как поток данных закрывается блоком CLOSE или библиотечной Plus-процедурой Close().

    8.1.2. Блок CLOSE

    Блок CLOSE предназначен для закрытия потока данных. Формат блока:

    CLOSE             A,[B],[C]

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

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

    Операнд С - метка блока, в который направляется транзакт в случае ошибки закрытия потока данных. Коды ошибок:

  • 0 - нет ошибки;
  • 41 - запись файла на диск не произведена из-за ошибки ввода-вывода;
  • 42 - файл не был открыт.
  • Например:

    CLOSE             Parm_Error,(P1+1)

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

    Блок CLOSE для потоков ввода-вывода записывает данные из виртуальной памяти в дисковый файл.

    8.1.3. Блок READ

    Блок READ предназначен для считывания из потока данных текстовой строки. Формат блока:

    READ   A,[B],[C]

    Операнд А - номер или имя параметра транзакта, в который записывается считанная из потока ввода или потока в памяти строка, находящаяся на позиции текущей строки. После считывания позиция текущей строки увеличивается на единицу. Если такой параметр активного транзакта не существует, он создается.

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

    Операнд С - метка блока, в который направляется транзакт в случае ошибки считывания. Если операнд С не используется, код ошибки все равно сохраняется. Для его получения нужно использовать блок CLOSE. Коды ошибок:

  • 21 - во время попытки выполнить чтение был запрещен доступ к памяти;
  • 22 - файл не был открыт.
  • Например:

    READ   Stroka_Text,4,Kon5

    В примере блок READ считывает текстовую строку из потока данных номер 4 и записывает в параметр транзакта с именем Stro-ka_Text. Если текстовая строка считывается без ошибки, а параметр активного транзакта не существует, он создается. В случае ошибки строка не считывается и активный транзакт направляется к блоку с меткой Kon5.

    8.1.4. Блок WRITE

    Блок WRITE предназначен для передачи текстовой строки потоку данных. Формат блока:

    WRITE             A,[B],[C],[D]

    Операнд А - текстовая строка, которая должна быть передана потоку данных.

    Операнд В - номер потока данных, по умолчанию равен 1.

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

  • 0 - нет ошибки;
  • 31 - во время попытки выполнить запись был запрещен доступ к памяти;
  • 32 - файл не был открыт.
  • Операнд D - задает режим работы блока WRITE. Если операнд D не используется (по умолчанию) или равен ON, блок WRITE работает в режиме вставки. Если операнд D равен OFF - в режиме замены.

    Режим вставки:

  • все текстовые строки, находящиеся на или за позицией текущей строки, сдвигаются на одну позицию;
  • если позиция текущей строки находится далеко за последней текстовой строкой, она устанавливается сразу после последней строки потока данных;
  • копия новой текстовой строки помещается на позицию текущей строки;
  • позиция текущей строки увеличивается на единицу. Режим замены:
  • если позиция текущей строки находится далеко за последней текстовой строкой, все промежуточные позиции заполняются нулевыми текстовыми строками;
  • текстовая строка, находящаяся на позиции текущей строки, удаляется;
  • копия новой текстовой строки помещается на позицию текущей строки;
  • позиция текущей строки увеличивается на единицу. Пример:
  • WRITE     "INITIAL    MX$TDon(1,1),420",5,Met3

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

    Замечание 1.Если операнды С блоков OPEN, CLOSE, READ и WRITE не используются, ошибка игнорируется. Обычно эти операнды используются для того, чтобы направить активный транзакт на блок CLOSE, который код ошибки помещает в параметр транзакта. Из параметра можно записать код ошибки в сохраняемую ячейку и завершить моделирование. Значение ячейки будет выведено в стандартном отчете. Замечание 2.При построчном считывании данных из файла может оказаться, что на позиции текущей строки нет строки данных. Это происходит тогда, когда из файла считаны все текстовые строки. В данном случае активный транзакт входит в блок READ и далее направляется к блоку, метка которого указана операндом С. Код ошибки при этом не сохраняется.

    8.1.5. Блок SEEK

    Блок SEEK устанавливает позицию текущей строки потока данных. Формат блока:

    SEEK               A,[B]

    Операнд А - новая позиция текущей строки.

    Операнд В - номер потока данных, по умолчанию равен 1.

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

    31 - код ошибки: файл не был открыт.

    Пример:

    SEEK    (Stroka+P1),(Potok+3)

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

    8.2. Разработка модели в GPSS World

    8.2.1. Постановка задачи

    На склад, имеющий 10 пунктов выгрузки, прибывают транспорта с материальными средствами (МС). В транспорте могут быть автомобили различной грузоподъемности. Всего количество типов автомобилей, отличающихся грузоподъемностью, которое может быть в транспорте, распределено по нормальному закону с математическим ожиданием 6 автомобилей и стандартным отклонением 1 автомобиль. Количество автомобилей одного типа в транспорте также распределено по нормальному закону с математическим ожиданием 11 автомобилей и стандартным отклонением 2 автомобиля. Интервалы времени прибытия транспортов распределены по экспоненциальному закону со средним значением 9 часов. Время разгрузки автомобиля зависит от его типа и подчиняется экспоненциальному закону. Среднее время выгрузки МС приведено в табл. 8.1. После выгрузки из тех же автомобилей вновь формируется транспорт.

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

    Среднее время выгрузки МС из автомобилей различных типов
    Характеристики Тип автомобиля
    1 2 3 4 5 6 7 8 9 10
    Среднее время выгрузки, мин 8 10 12 7 6 9 11 5 13 10

    Для имитации транспорта в целом и одного автомобиля следует использовать транзакты. Пункты выгрузки в модели будут представлять ОКУ.

    8.2.2. Программа модели

    ; Модель разгрузки транспортов
    ; Задание исходных данных
    IntTp	EQU		720	; Средний интервал поступления транспортов
    MOTip	EQU		6	; Матожидание типов автомобилей в транспорте
    SOTip	EQU		1	; Стандартное отклонение типов автомобилей
    MatA	EQU		11	; Матожидание автомобилей одного типа
    SOtkA	EQU		2	; Стандартное отклонение автомобилей одного типа
    KolPun	EQU		10	; Количество пунктов выгрузки
    VrMod	EQU		1440	; Время моделирования
    ;	Определение функций и булевых переменных
    SrVrA	FUNCTION	P3,D10	; Среднее время выгрузки
    1,8/2,10/3,12/4,7/5,6/6,9/7,11/8,5/9,13/10,10
    TipAvt	FUNCTION	RN64,C2	; Число типов автомобилей
    0,1/1,7
    ; Сегмент имитации поступления и обработки сообщений
    	GENERATE	(Exponential(33,0,IntTp)) ; Источник транспортов
    	SAVEVALUE	1,0	; Обнуление счетчика
    	ASSIGN		5,AC1	; Абсолютное модельное время входа транспорта
    	ASSIGN		2,(INT(Normal(77,MOTip,SOTip)-1))	;Число типов
    	SPLIT		*2	; Транзактов - по числу типов автомобилей
    	ASSIGN		2+,1	; Запомнить число типов автомобилей
    	ASSIGN		4,(INT(Normal(55,MatA,SOtkA)-1));Автомобили
    	SPLIT		*4	; Транзактов - по числу автомобилей
    	ASSIGN		4+,1	; Запомнить число автомобилей одного типа
    	TEST L		X1,KolPun,Met1 ; Есть свободные пункты выгрузки?
    	SAVEVALUE	1+,1
    Met2	SELECT MIN	3,1,KolPun,,FR	; Выбор пункта с min загрузкой
    	TEST NE		P3,0,Met1	; Есть пункты с min загрузкой?
    	QUEUE		P3	; Встать в очередь
    	SEIZE		P3	; Занять пункт выгрузки
    	DEPART		P3	; Покинуть очередь
    	ADVANCE		(Exponential(73,0,FN$SrVrA))	; Выгрузка
    	RELEASE		P3	; Освободить АРМ
    	UNLINK		PunSb,Met2,1	; Автомобиль на выгрузку
    	ASSEMBLE	*4	; Собрать автомобили одного типа
    	ASSEMBLE	*2	; Собрать автомобили всех типов
    	ASSIGN		6,AC1	; Время выхода транспорта
    	SAVEVALUE	VrVigS+,(P6-P5) ; Суммарное время выгрузки
    VigTr	TERMINATE	; Выгруженные транспорта
    Met1	LINK	PunSb,FIFO	; Автомобили, ожидающие выгрузки
    ; Сегмент задания времени моделирования
    	GENERATE	VrMod TEST	NE	N$VigTr,0,Met3
    	SAVEVALUE	VrVig,(X$VrVigS/N$VigTr)	; Среднее время выгрузки
    Met3	TERMINATE	1

    Замысел построения модели заключается в следующем. Блок GENERATE имитирует поступление транзактов. Один транзакт - один транспорт. Затем случайным образом определяется количество типов автомобилей в транспорте и заносится в параметр 2 транзакта. Исходный (порождающий) транзакт - транспорт копируется блоком SPLIT и результат копирования - число автомобилей различных типов в прибывшем транспорте копируется вторым блоком SPLIT. Результат копирования - число транзактов, равное числу автомобилей в транспорте. Число автомобилей одного типа заносится в параметр 4 всех транзактов, имитирующих автомобили данного типа.

    Далее первые десять транзактов-автомобилей (по числу пунктов выгрузки) поступают на блок SELECT, остальные - в список пользователя с именем PunSb. По мере освобождения пунктов выгрузки из списка пользователя выводятся транзакты и направляются на блок SELECT с меткой Met2. Результат работы блока SELECT - номер пункта выгрузки с минимальным коэффициентом загрузки заносится в параметр 3 вошедшего транзакта. Если результатом поиска блока SELECT является P3=0, т. е. номер нужного блока не найден, то транзакт блоком TEST снова отправляется в список пользователя. При успешном поиске транзакт занимает соответствующий пункт выгрузки.

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

    При входе транзакта-транспорта в модель и выходе из нее в параметры 5 и 6 записывается соответствующее модельное время. Оно используется для расчета времени разгрузки транспорта. Суммарное время разгрузки всех транспортов накапливается в ячейке VrVigS.

    Для работы с GPSS-моделью можно создать в какой-либо другой системе программирования, например, Delphi, интерфейс, который должен позволять осуществлять ввод исходных данных и вывод результатов моделирования. Например, в приведенной программе модели разгрузки транспортов вводить посредством интерфейса характеристики, для ввода которых используется команда EQU, а также среднее время выгрузки из одного автомобиля. При этом, естественно, необходимо разработать процедуры, формирующие в Delphi соответствующие строки программы GPSS-модели. Сама GPSS-программа также потребует модификации, для проведения которой нужно будет использовать команду INCLUDE и рассмотренные в п. 8.1 блоки OPEN, CLOSE, READ, WRITE для работы с текстовыми объектами и потоками данных.

    8.3. Создание стартовой формы приложения - имитационной модели

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

    При запуске Delphi автоматически создаётся новый проект. Вид экрана после запуска Delphi показан на рис. 8.1. Можно использовать этот проект для создания нового приложения. По умолчанию этот проект имеет название Project1.

    Стартовая форма создается путем изменения свойств формы .Свойства формы определяют ее внешний вид: размер, положение на экране, текст заголовка, вид рамки. Свойства перечислены на вкладке Properties (свойства) окна Object Inspector.В левой колонке находятся имена свойств, а в правой - их значения.

    Сначала надо изменить значение свойства Caption ( Заголовок ) - заменить Forml на Модель разгрузки транспортов. Для этого щелкнуть мышью в поле Caption.В результате этого в правой колонке, где находится текущее значение свойства - текст Forml, появляется курсор (рис. 8.2.).

    Используя клавишу <Backspase>, надо удалить Forml и ввести Модель разгрузки транспортов.

    Аналогичным образом можно установить значения свойств Height и Width, которые определяют высоту и ширину формы. Этим свойствам надо присвоить значения 530 и 715. Размер формы и элементов управления, а также положение формы на экране и элементов управления на поверхности формы задаются в пикселях, точках экрана.

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

    При разработке формы Form1 имитационной модели оставим свойство Color неизменным.

    (рис 8.1) Вид экрана после запуска Delphi(рис 8.2) Установка значения свойства Caption посредством ввода(рис 8.3) Установка значения свойства выбором из списка

    В поле значения свойства Font расположена командная кнопка с тремя точками, при нажатии на которую появляется стандартное диалоговое окно Windows выбора шрифта и его свойств (рис. 8.4). Для рассматриваемого примера выбран шрифт Times New Roman размером 10.

    Большинство свойств определяют внешний вид формы. Свойство Name определяет имя формы, которое используется в программе для управления формой.

    Ниже в табл. 8.2 приведены измененные свойства формы разрабатываемой имитационной модели. Остальные свойства формы оставлены без изменения и в таблице не приведены.

    (рис 8.4) Пример раскрытого списка уточняющих свойств свойства Font(рис 8.2) Пример раскрытого списка уточняющих свойств свойства Font
    Изменённые свойства формы имитационной модели
    Свойство Обозначение Значение
    Имя формы Name Form1
    Заголовок Caption Модель разгрузки транспортов
    Высота Height 530
    Ширина Width 715
    Шрифт Font. Name Times New Roman
    Размер шрифта Font. Size 10

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

    Создайте папки D:\ModRTr\Интерфей с и в последней сохраните проект. Чтобы сохранить проект, надо выполнить команду File/ Save Project As. Откроется окно Save Unit As. Выберите в нем и раскройте созданную ранее папку Интерфейс. В поле Имя файла введите имя программного модуля, например, Rasgruska, и щелкните кнопку Сохранить.

    После этого щелчка в диалоговом окне Save Unit As появится диалоговое окно Save Project As. В поле имя файла введите, например, Rasgr_transporta и щелкните кнопку Сохранить.

    (рис 8.5) Вид формы имитационной модели после установки значений свойств

    8.3 Добавление компонент в стартовую форму имитационной модели

    8.3.1. Добавление полей редактирования

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

    IntTp - средние значения интервалов поступления транспортов;

    MOТip, SOTip - математическое ожидание MOТip и стандартное отклонение SOTip количества типов автомобилей в транспорте;

    MatA, SOtkA - математическое ожидание MatA и стандартное отклонение SOtkA количества автомобилей одного типа в транспорте;

    KolPun - количество пунктов выгрузки;

    VrMod - время моделирования.

    В Windows данные с клавиатуры вводятся в поля редактирования. Поэтому в данную форму надо добавить компоненты - семь полей редактирования.

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

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

    (рис 8.6) Пиктограммы стандартной палитры компонентов

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

    Добавьте в форму, перейдя на вкладку Standard (см. рис. 8.6), семь компонентов редактирования Edit. У компонента Edit пиктограмма .

    Компонент формы, окруженный восемью маленькими квадратиками (см. на рис. 8.7 поле Edit1 ), называется выделенным (маркированным).Свойства маркированного компонента отображаются в окне Object Inspector.Ниже, в табл. 8.3, перечислены основные свойства компонента, называемого полем редактирования.

    На рис. 8.7 представлен вид формы после добавления к ней семи полей редактирования Edit1 Edit7.

    (рис 8.7) Форма имитационной модели с семью полями редактирования

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

    Основные свойства компонента поля редактирования
    Свойство Обозначение
    Имя поля. Используется в программе для доступа к содержимому (тексту) поля Name
    Текст, находящийся в поле ввода-редактирования Text
    Расстояние от левой границы поля до левой границы формы Left
    Расстояние от верхней границы поля до верхней границы формы Top
    Высота поля Height
    Ширина поля Width
    Шрифт, используемый для отображения вводимого текста Font
    Признак наследования свойств шрифта родительской формы ParentFont

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

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

    (рис 8.8) Окно Object Inspector с свойствами поля редактирования Edit1

    В табл. 8.4 приведены свойства полей редактирования, предназначенных для ввода IntTp, MOТip, SOTip, MatA, SOtkA, KolPun, VrMod.

    Свойства полей редактирования формы имитационной модели
    Name Edit1 Edit2 Edit3 Edit4 Edit5 Edit6 Edit7
    Text
    Top 30 60 90 30 60 90 120
    Left 16 16 16 350 350 350 16
    Height 21 21 21 21 21 21 21
    Width 50 50 50 50 50 50 50

    8.3.2. Добавление меток

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

    Текст, находящийся в форме, называется меткой. Добавляется метка к форме точно так же, как и поле редактирования. Пиктограмма метки (большая буква А) находится в палитре компонентов перед пиктограммой поля редактирования (см. рис. 8.6). После того как метка добавлена, можно, используя окно Object Inspector,изменить ее свойства.

    К форме разрабатываемого приложения надо добавить восемь меток. Все метки будут представлять собой информационные сообщения. Добавьте метки и установите значения их свойств согласно табл. 8.5. Форма разрабатываемого приложения будет иметь вид, представленный на рис. 8.9.

    Свойства меток формы имитационной модели
    Name Labell Label2 Label3 Label4 Label5 Label6 Label7 Label8
    Caption
    AutoSize false true true true true true true true
    Top 0 30 60 90 30 60 90 120
    Left 140 70 70 70 410 410 410 70
    Wordwrap true true true true true true True true
    ParentFont false true true true true true true true
    (рис 8.9) Вид формы имитационной модели после добавления меток

    Как видно по рис. 8.9, из полей редактирования необходимо удалить их имена Edit1…Edit7. На этом же рисунке указано свойство Caption для каждой метки - информационное сообщение. Например, для Labell: Введите исходные данные и нажмите кнопку ВВОД. Для Labell: Средний интервал поступления транспортов.

    Свойство ParentFont метки Labell имеет значение false, поэтому свойство Font этой метки не наследует значения свойства Font "родителя", в данном случае основной формы. Это дает возможность установить свойства шрифта метки иные, чем у формы. У меток Label2…Label8 значение свойства ParentFont оставлено без изменения. Значит, они наследуют свойства Font "родителя".

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

    У меток Label2…Label8 свойству AutoSize установлено значение true, а у метки Label1 - false.

    8.3.3. Добавление компонент для ввода и вывода данных, представленных в виде таблиц

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

    Значок компонента StringGrid находится на дополнительной ( Additional ) странице палитры компонентов. В разрабатываемую форму имитационной модели необходимо добавить два компонента. Один компонент для ввода табл. 8.1. В данной модели результаты моделирования целесообразно вывести таблицей. Поэтому нужен второй компонент StringGrid. Добавьте два компонента. Добавляются они также, как и другие компоненты.

    Добавленные компоненты StringGrid имеют стандартные свойства. Delphi предоставляет разработчику возможность изменить эти свойства после добавления компонентов в форму.

    В табл. 8.6 перечислены основные свойства компонента StringGrid.

    Основные свойства компонента StringGrid
    Свойство Описание
    Name Имя компонента. Используется в программе для доступа к свойствам компонента
    ColCount Количество колонок таблицы
    RowCount Количество строк таблицы
    Cells Соответствующий таблице двумерный строковый массив. Если строки и столбцы нумеровать с нуля, то ячейке Cells соответствует Cells (i,j)
    FixedCols Количество зафиксированных слева столбцов таблицы. Они выделяются цветом и при горизонтальной прокрутке таблицы остаются на месте
    FixedRows Количество зафиксированных сверху строк таблицы. Они выделяются цветом и при вертикальной прокрутке таблицы остаются на месте
    Options Свойство используется для задания других атрибутов таблицы (табл. 8.7)
    DefaultColWidth Ширина столбцов таблицы
    DefaultRowHeight Высота строк таблицы
    GridLineWidth Ширина линий, ограничивающих ячейки таблицы
    Left Расстояние от левой границы поля таблицы до левой границы формы
    Top Расстояние от верхней границы поля таблицы до верхней границы формы
    Height Высота поля таблицы
    Width Ширина поля таблицы
    Font Шрифт, используемый для отображения содержимого ячеек таблицы
    ParentFont Признак наследования характеристик шрифта формы

    Из всех свойств следует обратить внимание на свойство Options. Свойство Options используется для задания многих атрибутов таблицы (компонента StringGrid ), которые описаны в табл. 8.7. На вкладке, показанной на рис. 8.10, перед свойством Options стоит знак " + ". При двойном нажатии на него появляется вкладка с вложенными свойствами свойства Options (рис. 8.10).

    Атрибуты таблицы, задаваемые свойством Options
    Атрибут Описание (для значения True )
    goFixedHorzLine Горизонтальные линии фиксированы
    goFixedVertLine Вертикальные линии фиксированы
    goHorzLine Горизонтальные разделительные линии отображаются
    goVertLine Вертикальные разделительные линии отображаются
    goRangeSelect Можно выбирать несколько ячеек
    goDrawFocusSelected Текущая ячейка помечается цветом
    goRowSizing Возможно изменение размеров строк
    goColSizing Возможно изменение размеров столбцов
    goRowMoving Возможно перемещение строк
    goColMoving Возможно перемещение столбцов
    goEditing Возможно редактирование содержимого ячеек
    goTabs Возможно перемещение по ячейкам клавишами Tab и Shift-Tab
    goThumbTracking Содержимое таблицы скроллируется с помощью полос прокрутки

    Свойства, перечисленные в табл. 8.6 и табл. 8.7, после выделения (маркирования) соответствующей таблицы устанавливаются либо заданием какого - то числового значения, либо выбором True или False (рис. 8.10).

    Для ввода данных табл. 8.1 необходимо изменить некоторые из свойств StringGrid. Например, для того, чтобы была возможность редактировать содержимое ячеек таблиц, нужно установить свойство goEditing True, а для перемещения курсора с помощью клавиш Tab и стрелок - свойство goTabs также установить True.

    В табл. 8.8 приведены значения свойств обеих компонентов StringGrid, используемых моделью для ввода и вывода данных. Установите эти значения. Форма должна иметь вид, показанный на рис. 8.11. Введите также метки Label9 и Label10 (см. рис. 8.11).

    (рис 8.10) Вкладка свойства Options (рис 8.8) Вкладка свойства Options
    Значения свойств компонента StringGrid1
    СвойствоКомпоненты
    12
    Name Tabl1 Tabl2
    ColCount 11 11
    RowCount 2 5
    FixedCols 1 1
    FixedRows 1 1
    Options.goEditing True True
    Options.goTabs True True
    DefaultColWidth 70 125
    DefaultRowHeight 24 24
    GridLineWidth 1 1
    goRowSizing True True
    (рис 8.11) Вид формы после добавления компонентов StringGrid

    Первая строка и первый столбец таблиц зафиксированы (см. рис. 8.11). Они используются в качестве заголовков таблиц. В рассматриваемом примере в первой строке первой таблицы это тип автомобиля (номера 1 … 10), во второй таблице - пункты выгрузки (также номера 1 … 10). Следует отметить, что можно было бы ввести в эти ячейки и наименования вместо порядковых номеров. Как это делается, покажем на примере ввода поясняющего текста в строки таблиц. Во вторую строку первой таблицы - Cells(0, 1) - введем: Время, мин. Во вторую таблицу: Cells(0, 1) - Коэф. загр.; Cells(0, 2) - Ср. время ; Cells(0, 3) - Макс. очер. Во время создания формы имитационной модели установить значения элементов Cells таблицы нельзя, так как элементы таблицы доступны только во время работы программы. Поэтому значения элементов Cells таблицы, соответствующие первой строке и первому столбцу обеих таблиц устанавливают процедуры FormActivate1 и FormActivate2 (текст их приведен ниже) во время активизации формы. В какой процедуре обработки события производится вызов указанных процедур, укажем позже.

    procedure TForm1.FormActivate1(Sender: TObject);
    var  n1:integer;
    begin
      for n1:=1 to Tabl1.ColCount do
        Tabl1.Cells[n1,0]:=IntToStr(n1);
      Tabl1.Cells[0,1]:='Время, мин';
    end;
    procedure TForm1.FormActivate2(Sender: TObject);
    var  n1:integer;
    begin
      for n1:=1 to Tabl2.ColCount do
        Tabl2.Cells[n1,0]:=IntToStr(n1);
      Tabl2.Cells[0,1]:='Коэф.исп.пункт. разгр.';
      Tabl2.Cells[0,2]:='Ср.вр.разгр.авт.,мин';
      Tabl2.Cells[0,3]:='Макс.очер.на пун.разгр.';
      Tabl2.Cells[0,4]:='Ср.вр.разгр.тран.,час';
    end;

    8.3.4. Добавление командных кнопок

    Для управления работой имитационной модели к форме надо добавить шесть командных кнопок (рис. 8.12).

    В модели предусмотрен пример. При нажатии кнопки ПРИМЕР автоматически вводятся исходные данные, курсор устанавливается на кнопке МОДЕЛИРОВАНИЕ. Нажатием этой кнопки переходят к процессу моделирования.

    (рис 8.12) Стартовая форма имитационной модели

    По окончании моделирования для вывода результатов нужно нажать кнопку ВЫВОД. Результаты моделирования появятся в нижней таблице.

    Если производилось моделирование примера, а потом нужно выполнить моделирование с другими исходными данными, нажатием кнопки СБРОС можно удалить данные примера и ввести новые. Использование кнопки СБРОС удобно в том случае, если очередной ввод исходных данных требует большого количества изменений. После этого нажать кнопку ВВОД и нажатием кнопки МОДЕЛИРОВАНИЕ перейти к процессу моделирования, по завершении которого нажать кнопку ВЫВОД.

    Нажатие на кнопку ВЫХОД ИЗ МОДЕЛИ приводит к завершению работы программы имитационной модели. Закрывается открытая форма приложения.

    Кнопки добавляются в форму точно так же, как и другие компоненты. Пиктограмма командной кнопки _2U,находится на палитре стандартных компонентов (см. рис. 8.6). После добавления кнопок с помощью диалогового окна Object Inspector надо установить требуемые значения их свойств (табл. 8.9).

    Свойства кнопок стартовой формы имитационной модели
    Name Button1 Button2 Button3 Button4 Button5 Button6
    Caption Ввод Сброс Моделирование Выход из модели Пример Вывод
    Top 470 470 470 470 470 470
    Left 176 96 256 528 16 424
    Height 25 25 25 25 25 25
    Width 75 75 161 169 75 75

    После запуска программы курсор сразу автоматически устанавливается в поле редактирования Edit1 для ввода переменной Средний интервал поступления транспортов. Поэтому в форме указано, что надо сначала ввести данные, потом нажать кнопку ВВОД и только потом кнопку МОДЕЛИРОВАНИЕ.

    8.4. События и процедуры обработки событий

    8.4.1. События

    Вид созданной формы подсказывает, как работает приложение. Очевидно, что пользователь должен ввести значения в поля редактирования, нажать ВВОД и потом щелкнуть кнопку МОДЕЛИРОВАНИЕ. Щелчок на изображении командной кнопки - это пример того, что в Windows называется событием.

    Событие - это то, что происходит во время работы приложения. В Delphi у каждого события есть имя, например, щелчок кнопкой мыши это событие OnClick, двойной щелчок - событие onDblClick.

    В табл. 8.10 приведены некоторые события Windows.

    Реакцией на событие должно быть какое-либо действие. Например, реакцией на событие OnClick, произошедшее на кнопке МОДЕЛИРОВАНИЕ,должен быть переход к запуску имитационной модели. В Delphi реакция на событие реализуется как процедура обработки события.Таким образом, задача программиста состоит в написании необходимых процедур обработки событий.

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

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

    Перечень некоторых событий Windows
    Событие Содержание
    OnClick Происходит при щелчке кнопкой мыши
    OnDblClick Происходит при двойном щелчке кнопкой мыши
    OnEnter Происходит перед тем, как элемент управления действительно получает фокус
    OnError Происходит, когда элемент контроля обнаруживает ошибку и не может вернуть информацию об ошибке вызывающей программе
    OnExit Происходит непосредственно перед тем, как элемент управления теряет фокус
    OnKeyDown Происходит при нажатии на клавишу. События OnKeyDown и OnKeyPress - это чередующиеся, повторяющиеся события, которые происходят до тех пор, пока не будет отпущена удерживаемая клавиша (в этот момент происходит событие OnKeyUp )
    OnKeyPress Происходит, когда пользователь нажимает клавишу, которая генерирует печатаемый символ. Может происходить также при нажатии клавиши печатаемого символа с <Ctrl>. He происходит при нажатии клавиш <Tab>, <Enter>, клавиш перемещения курсора
    OnKeyUp Происходит при отпускании нажатой клавиши
    OnMouseDown Происходит при нажатии кнопки мыши
    OnMouseMove Происходит при перемещении мыши
    OnMouseUp Происходит при отпускании кнопки мыши

    8.4.2. Разработка процедур обработки событий для кнопок

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

    Затем нужно выбрать вкладку Events (события) окна Object Inspector.В результате этих действий в окне Object Inspector появится вкладка со списком событий, которые способен воспринимать маркированный компонент, в данном случае - командная кнопка (рис. 8.13).

    В левой колонке вкладки перечислены имена событий, на которые может реагировать маркированный объект. Если для события определена процедура обработки события, то в правой колонке, рядом с именем события выводится ее имя.

    Чтобы создать процедуру обработки события, надо сделать двойной щелчок в поле имени процедуры обработки события. В результате открывается окно редактора кода (в Delphi кодом называется текст программы) с макетом процедуры обработки события (рис. 8.14).

    (рис 8.13) Вкладка Events командной кнопки ВВОД (Button1)(рис 8.14) Окно редактора кода с макетом процедуры обработки события, происходящего на кнопке Button1 (ВВОД)

    Delphi автоматически присваивает процедуре обработки события имя. Имя процедуры обработки события состоит из двух частей. Первая часть идентифицирует форму, которой принадлежит объект, для которого создается процедура обработки события. Вторая часть имени идентифицирует сам объект и событие. В нашем случае имя формы - Form1, Button1 - имя командной кнопки ВВОДимя события - Click.

    В окне редактора кода (см. рис. 8.14) между begin и end можно печатать инструкции Object Pascal, реализующие процедуру обработки события. Введите следующий программный код:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ProvVvod1;
      begin
        MOTip:=StrToFloat(Edit2.text);
        SOTip:=StrToFloat(Edit3.text);
        MatA:=StrToFloat(Edit4.text);
        SOtkA:=StrToFloat(Edit5.text);
      end;
      if (SOTip*5)>MOTip then begin
        MessageDlg('Стандартное отклонение SOTip'+#13
          +'должно быть более чем в 5 раз меньше'+#13
          +'математического ожидания MOTip',
          mtWarning,[mbOk],0);
        Edit3.SetFocus;
      end
      else if (SOtkA*)>MatA then begin
        MessageDlg('Стандартное отклонение SOtkA'+#13
          +'должно быть более чем в 5 раз меньше'+#13
          +'математического ожидания MatA',
          mtWarning,[mbOk],0);
        Edit5.SetFocus;
      end;
      ProvVvod2; Tabl1.SetFocus;
    end;

    В тексте процедуры выделено то, что сформировано Delphi. Остальное вводится разработчиком.

    Обработка события при щелчке кнопки ВВОД происходит так. Вначале процедурой ProvVvod1 проверяется, все ли данные введены в поля редактирования. Если все данные введены, производится их перевод в вещественный тип.

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

    Далее процедурой ProvVvod2 проверяется полнота ввода данных в первую таблицу StrinGrid. Создайте процедуры ProvVvod1, ProvVvod2 в разделе implementation программного модуля (.pas ).

    procedure TForm1.ProvVvod1;
    begin
      begin
        if (Edit1.text='') or (Edit2.text='')
        or (Edit3.text='') or (Edit4.text='')
        or (Edit5.text='') or (Edit6.text='')
        or (Edit7.text='') then
          MessageDlg('Необходимо задать все'+#13
            +'исходные данные'+#13
            + 'в полях редактирования',
            mtWarning,[mbOk],0);
      end;
      begin
        if Edit1.text='' then Edit1.SetFocus;
        if Edit2.text='' then Edit2.SetFocus;
        if Edit3.text='' then Edit3.SetFocus;
        if Edit4.text='' then Edit4.SetFocus;
        if Edit5.text='' then Edit5.SetFocus;
        if Edit6.text='' then Edit6.SetFocus;
        if Edit7.text='' then Edit7.SetFocus;
      end;
    end;
    
    procedure TForm1.ProvVvod2;
    begin
      begin
        if (Tabl1.Cells[1,1]='') or (Tabl1.Cells[2,1]='') or (Tabl1.Cells[3,1]='')
        or (Tabl1.Cells[4,1]='') or (Tabl1.Cells[5,1]='') or (Tabl1.Cells[6,1]='')
        or (Tabl1.Cells[7,1]='') or (Tabl1.Cells[8,1]='') or (Tabl1.Cells[9,1]='')
        or (Tabl1.Cells[10,1]='')
        then
          MessageDlg('Необходимо задать все'+#13
            +'исходные данные в таблице',
            mtWarning,[mbOk],0);
      end;
      Tabl1.SetFocus;
    end;

    Объявите в интерфейсной части эти процедуры.

    type TForm1 = class(TForm)
        Edit1: TEdit;
        …
        procedure ProvVvod1;
        procedure ProvVvod2;
      private

    При нажатии кнопки СБРОС все поля редактирования и ячейки Tabl1 очищаются. Создайте обработчик этого события, программный код которого приведен ниже.

    procedure TForm1.Button2Click(Sender: TObject);
    var n1,n2:integer;
    begin
      Edit1.text:='';
      Edit2.text:='';
      Edit3.text:='';
      Edit4.text:='';
      Edit5.text:='';
      Edit6.text:='';
      Edit7.text:='';
      for n1:=1 to 10 do
        Tabl1.Cells[n1,1]:='';
      for n2:=1 to 3 do
        for n1:=1 to 10 do
          Tabl2.Cells[n1,n2]:=''; Edit1.SetFocus;
    end;

    Нажатием кнопки МОДЕЛИРОВАНИЕ производится переход к процессу моделирования. Создайте обработчик этого события согласно следующему программному коду.

    procedure TForm1.Button3Click(Sender: TObject); begin
    VivProgr;
    WinExec('d:\ModRTr\GPSSW.exe',SW_RESTORE);
    Button6.SetFocus;
    end;

    При обработке этого события вначале выполняется процедура VivProgr, состоящая в свою очередь из четырех процедур VivProgr1, VivProgr2, VivProgr3 и VivProgr4. Они формирует следующие тестовые файлы с фрагментами программы GPSS:

  • Progr1.txt для ввода данных командой EQU и посредством функции SrVrA (процедура VivProgr1 );
  • Progr2.txt для ввода времени моделирования из поля редактирования Edit7 (процедура VivProgr2 );
  • Progr3.txt - для вывода результатов моделирования в текстовый файл DanTabl211.txt (процедура VivProgr3 );
  • Progr4.txt - для вывода результатов моделирования в текстовый файл DanTabl212.txt (процедура VivProgr4 );
  • Progr5.txt - для вывода результатов моделирования в текстовый файл DanTabl213.txt (процедура VivProgr5 );
  • Создайте в разделе implementation программного модуля ( .pas ) программные коды шести процедур.

    procedure TForm1.VivProgr;
      begin
        VivProgr1;
        VivProgr2;
        VivProgr3;
        VivProgr4;
        VivProgr5;
      end;
    
    procedure TForm1.VivProgr1;
    var
      f:TextFile;
    begin
      AssignFile(f,'d:\ModRTr\Progr1.txt');
      Rewrite(f);
      writeln(f,'IntTp EQU ',Edit1.text);
      writeln(f,'MOTip EQU ',Edit2.text);
      writeln(f,'SOTip EQU ',Edit3.text);
      writeln(f,'MatA EQU ',Edit4.text);
      writeln(f,'SOtkA EQU ',Edit5.text);
      writeln(f,'KolPun EQU ',Edit6.text);
      writeln(f,'VrMod EQU ',Edit7.text);
      writeln(f,'SrVrA FUNCTION P3,D',(Tabl1.ColCount-1));
      writeln(f,'1,',Tabl1.Cells[1,1],'/2,',Tabl1.Cells[2,1],'/3,',Tabl1.Cells[3,1],
        '/4,',Tabl1.Cells[4,1],'/5,',Tabl1.Cells[5,1],'/6,',Tabl1.Cells[6,1],
        '/7,',Tabl1.Cells[7,1],'/8,',Tabl1.Cells[8,1],'/9,',Tabl1.Cells[9,1],
        '/10,',Tabl1.Cells[10,1]);
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr2;
    var
      f:TextFile;
    begin
      AssignFile(f,'d:\ModRTr\Progr2.txt');
      Rewrite(f);
      writeln(f,'GENERATE ', StrToFloat(Edit7.text);
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr3;
    var
      f:TextFile;
      n1:integer;
    begin
      AssignFile(f,'d:\ModRTr\Progr3.txt');
      Rewrite(f);
      writeln(f,'OPEN ("DanTabl21.txt"),1,Kon1');
      for n1:=1 to StrToInt(Edit6.text) do
        writeln(f,'WRITE FR',n1,',,,OFF');
      writeln(f,'Kon1 CLOSE Err1,1');
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr4;
    var
      f:TextFile;
      n1:integer;
    begin
      AssignFile(f,'d:\ModRTr\Progr4.txt');
      Rewrite(f);
      writeln(f,'OPEN ("DanTabl22.txt"),1,Kon2');
      for n1:=1 to StrToInt(Edit6.text) do
        writeln(f,'WRITE FT',n1,',,,OFF');
      writeln(f,'Kon2 CLOSE Err1,1');
      CloseFile(f);
    end;
    
    procedure TForm1.VivProgr5;
    var
      f:TextFile;
      n1:integer;
    begin
      AssignFile(f,'d:\ModRTr\Progr5.txt');
      Rewrite(f);
      writeln(f,'OPEN ("DanTabl23.txt"),1,Kon3');
      for n1:=1 to StrToInt(Edit6.text) do
        writeln(f,'WRITE QM',n1,',,,OFF');
      writeln(f,'WRITE X$VrVig',',,,OFF')
      writeln(f,'Kon3 CLOSE Err1,1');
      CloseFile(f);
    end;

    Объявите в интерфейсной части программного модуля эти шесть процедур.

    type TForm1 = class(TForm)
        Edit1: TEdit;
        …
        procedure VivProgr;
        procedure VivProgr1;
        procedure VivProgr2;
        procedure VivProgr3;
        procedure VivProgr4;
        procedure VivProgr5;
    private

    После выполнения процедуры VivProgr командой

    WinExec('d:\ModRTr\GPSSW.exe',SW_RESTORE);

    запускается GPSS.exe. И далее пользователем - приложение Модель разгрузки транспортов. Курсор устанавливается на кнопке ВЫВОД.

    Для обработки события - щелчка кнопки ВЫВОД - используйте следующий программный код:

    procedure TForm1.Button6Click(Sender: TObject);
      begin
        FormActivate2(Sender);
        VivRes1;
        VivRes2;
        VivRes3;
      end;

    Обработка события начинается с выполнения процедуры FormActivate2(Sender). В результате этого вводятся заголовки в первую строку и в первый столбец второй таблицы. Затем последовательно выполняются процедуры VivRes1, VivRes2 и VivRes3, которые считывают результаты моделирования из файлов DanTabl211.txt, DanTabl212.txt и DanTabl213.txt соответственно и выводят их построчно во вторую таблицу.

    Создайте обработчик события - щелчка кнопки ВЫВОД и в разделе implementation программного модуля ( .pas ) создайте процедуры FormActivate2(Sender) (см. п. 8.3.3), VivRes1, VivRes2 и VivRes3.

    procedure TForm1.VivRes1;
    var
      f:TextFile;
      n1:integer;
      a:real;
      begin
        AssignFile(f, 'd:\ModRTr\DanTabl21.txt');
        Reset(f);
        for n1:=1 to (Tabl2.ColCount-1) do begin
          read(f,a);
          a:=Trunc(a);
          a:=a/1000;
          Tabl2.Cells[n1,1]:=FloatToStr(a);
        end;
      end;
    
    procedure TForm1.VivRes2;
    var
      f:TextFile;
      n1:integer;
      a:real;
      begin
        AssignFile(f, 'd:\ModRTr\DanTabl22.txt');
        Reset(f);
        for n1:=1 to (Tabl2.ColCount-1) do begin
          read(f,a);
          a:=a*1000;
          a:=Trunc(a);
          a:=a/1000;
          Tabl2.Cells[n1,2]:=FloatToStr(a);
        end;
      end;
    
    procedure TForm1.VivRes3;
    var
      f:TextFile;
      n1:integer;
      a:real;
      begin
        AssignFile(f, 'd:\ModRTr\DanTabl23.txt');
        Reset(f);
        for n1:=1 to (Tabl2.ColCount-1) do
        begin
          read(f,a);
          Tabl2.Cells[n1,3]:=FloatToStr(a);
        end;
      end;

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

    type TForm1 = class(TForm)
        Edit1: TEdit;
        …
        procedure FormActivate2(Sender: TObject);
        procedure VivRes1;
        procedure VivRes2;
        procedure VivRes3;
      private

    Завершение работы с программой модели происходит при нажатии кнопки ВЫХОД ИЗ МОДЕЛИ. Результатом является закрытие формы приложения. Создайте обработчик этого события.

    procedure TForm1.Button4Click(Sender: TObject);
      begin
        Form1.close;
      end;

    8.4.3. Разработка процедур обработки событий для полей редактирования

    В соответствии с видом формы имитационной модели сформулируем следующие требования к программе:

  • в поля исходных данных модели допускается вводить только положительные числа, а ввод других символов программа должна блокировать;
  • числа, вводимые в поля Edit3 и Edit5, не должны быть равны или больше чисел, вводимых в поля соответственно Edit2 и Edit4 (стандартное отклонение должно быть в пять раз и более меньше математического ожидания);
  • во время ввода данных модели при нажатии на клавишу Enter курсор автоматически должен перемещаться в поле ввода следующего числа. Если клавиша Enter нажата во время ввода в поле Edit7, программа должна перейти к вводу в первую таблицу;
  • при обнаружении ошибок при вводе в поля Edit3 или Edit5 курсор должен быть соответственно в одном из них;
  • если в какое - то поле не введена хотя бы одна цифра (поле пустое) и нажата клавиша Enter, то возникает ошибка, о чем выдается сообщение, и ввод нужно повторить.
  • Чтобы программа удовлетворяла вышеприведенным требованиям, надо для каждого поля редактирования написать процедуру обработки события OnKeyPress, которая в зависимости от того, какую клавишу нажал пользователь, будет выполнять нужное действие.

    Заготовка процедуры OnKeyPress для Edit1, генерируемая Delphi, выглядит следующим образом:

    Procedure Tform1.Edit1KeyPress(Sender:Tobject; var Key:Char);
      begin
      end;

    Заголовок процедуры Edit1KeyPress показывает, что процедура в качестве параметра получает символьную переменную Key. Эта переменная содержит символ, соответствующий нажатой клавише. Следует обратить внимание на то, что параметр принимается по ссылке (перед именем переменной стоит слово var ), поэтому процедура может изменить значение переменной. Символ, соответствующий нажатой клавише, появляется в поле редактирования после выполнения процедуры обработки события OnKeyPress, поэтому процедура обработки может заменить введенный символ или присвоением переменной Key значения Chr(0) запретить его появление в поле редактирования.

    Ниже приведен программный код процедуры обработки события OnKeyPress в поле редактирования.

    рrocedure TForm1.Edit1KeyPress(Sender:Tobject; var Key:Char);
      begin
        case Key of
          '0'..'9',Chr(8):;
          '-':Key:=Chr(0);
          ',':if pos(',',Edit1.text)<> then Key:=Chr(0);
          Chr(13):Edit2.SetFocus
          '.': begin
              MessageDlg('Для отделения дробной части' +'числа'+#13
                +'от целой используйте запятую', mtInformation, [mbOk],0);
              Key:=Chr(0);
            end;
          else Key:=Chr(0);
        end;
      end;

    Процедура TForm1.Edit1KeyPress проверяет, какая клавиша нажата при вводе исходных данных в поле редактирования Edit1. Если нажата клавиша BackSprace, то процедура завершает свою работу и символ появляется в поле редактирования или стирается последний введённый символ. Если нажата запятая, то процедура проверяет, есть ли уже запятая в поле редактирования. Если есть, то ввод второй запятой блокируется. Если нажата клавиша "-", то ввод её тоже блокируется. Если нажата клавиша Enter, то применением метода SetFocus к полю редактирования Edit2 курсор перемещается в это поле.

    Процедуры обработки события OnKeyPress полей редактирования отличаются только способом обработки нажатия клавиши Enter (в поле Edit1 Edit2.SetFocus, в поле Edit2 Edit3.SetFocus и т.д., а в поле Edit7

    then
      begin
        FormActivate1(Sender);
        Tabl1.SetFocus;
      end;

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

    Создайте в разделе implementation программный код процедур EditKeyPress и FormActivate1 (см. п. 8.3.3).

    procedure TForm1.EditKeyPress(Sender: TObject; var Key: Char);
    var
      nak:string[20];
      begin
      if Sender=Edit1 then
        nak:=Edit1.text
      else if Sender=Edit2 then
        nak:=Edit2.text
      else if Sender=Edit3 then
        nak:=Edit3.text
      else if Sender=Edit4 then
        nak:=Edit4.text
      else if Sender=Edit5 then
        nak:=Edit5.text
      else if Sender=Edit6 then
        nak:=Edit6.text
      else nak:=Edit7.text;
      case Key of
        '0'..'9',Chr(8):;
        '-':Key:=Chr(0);
        ',':if pos(',',nak) <>0 then Key:=Chr(0);
        Chr(13):if Sender=Edit1
            then Edit2.SetFocus
            else if Sender=Edit2
            then Edit3.SetFocus
            else if Sender=Edit3
            then Edit4.SetFocus
            else if Sender=Edit4
            then Edit5.SetFocus
            else if Sender=Edit5
            then Edit6.SetFocus
            else if Sender=Edit6
            then Edit7.SetFocus
            else if Sender=Edit7
            then
              begin
                FormActivate1(Sender);
                Tabl1.SetFocus;
              end;
        '.':begin
            MessageDlg('Для отделения дробной'
              +'части от целой'+#13
              +'используйте запятую',
              mtInformation,[mbOk],0);
            Key:=Chr(0);
          end;
        else Key:=Chr(0)
      end;
    end;

    Объявите в интерфейсной части:

    type TForm1 = class(TForm)
      Edit1: TEdit;
      …
      procedure FormActivate1(Sender: TObject);
    private

    Теперь выделите компонент Edit2 и на вкладке Events раскройте список. Из списка для onKeyPress щелчком установите EditKeyPress. Проделайте тоже для компонентов Edit3 … Edit7.

    8.4.4. Модификация программы имитационной модели

    Интерфейс приложения разработан. Согласно интерфейсу внесем изменения в исходную GPSS-модель (см. п. 8.2.2). Заменим строки программы с командой EQU и строки

    SrVrA	FUNCTION	P3,D10	; Среднее время выгрузки
    1,26/2,20/3,30/4,25/5,15/6,18/7,28/8,32/9,23/10,30

    командой

    INCLUDE          "Progr1.txt"        ; Подключение файла

    Модифицируем также сегмент задания времени моделирования.

    ;Сегмент задания времени моделирования
    	INCLUDE		"Progr2.txt" ; Подключение файла
    	TEST E		TG1,1,Met3 ; При TG1=1 - расчет результатов моделирования
    ;	TEST NE		N$VigTr,0,Met3
    	SAVEVALUE	VrVig,((X$VrVigS/N$VigTr)/60) ; Среднее время выгрузки, час
    	INCLUDE		"Progr3.txt" ; Подключение файла
    	INCLUDE		"Progr4.txt" ; Подключение файла
    	INCLUDE		"Progr5.txt" ; Подключение файла
    Met3	TERMINATE     1

    Разработка имитационной модели в виде приложения с интерфейсом завершена.

    Отладьте приложение и перейдите к работе с ним.

    8.5. Работа с приложением

    Поместите в папку D:\ModRTr файл GPSS.exe и GPSS-модель ModRasgTr.gps. Нахождение файла Rasg_transporta.exe в этой же папке необязательно. Запустите Rasg_transporta.exe.

    Нажмите кнопку ПРИМЕР. Автоматически будут введены данные, показанные на рис. 8.15.

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

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

    Нажмите OK. Повторите ввод числа с отделением его целой части от дробной части запятой в это же поле редактирования. Нажмите кнопку ВВОД. Появится предупреждение о другой ошибке (рис. 8.17). Нажмите OK и исправьте ошибку.

    (рис 8.15) Форма приложения с данными примера(рис 8.16) Сообщение об ошибке при вводе числа(рис 8.17) Сообщение об ошибке при вводе стандартного отклонения

    Далее удалите, например, количество пунктов разгрузки из поля редактирования и щелкните ВВОД. Появится предупреждение о том, что необходимо задать все исходные данные в полях редактирования (рис. 8.18). Щелкните OK и исправьте ошибку.

    Теперь удалите, например, среднее время разгрузки автомобиля второго типа из первой таблицы и щелкните ВВОД. Появится предупреждение о том, что необходимо задать все исходные данные в полях редактирования (рис. 8.19). Щелкните OK, исправьте ошибку и нажмите ВВОД.

    (рис 8.18) Предупреждение о необходимости ввода всех данных в поля редактирования(рис 8.19) Предупреждение о необходимости ввода всех данных в первую таблицу

    Теперь ошибок ввода исходных данных нет. Щелкните кнопку МОДЕЛИРОВАНИЕ.

    Выполните необходимые действия с GPSS-моделью. Закройте GPSS-exe и нажмите активную кнопку ВЫВОД. Во второй таблице появятся результаты моделирования (рис. 8.20):

  • среднее время разгрузки автомобилей различных типов;
  • коэффициенты использования пунктов разгрузки;
  • максимальные очереди на пункты разгрузки;
  • среднее время разгрузки одного транспорта.
  • (рис 8.20) Форма приложения с данными и результатами моделирования

    Вопросы для самоконтроля

  • Какова цель предназначения текстовых объектов и потоков данных?
  • Какой командой подключаются текстовые объекты к объе-ту GPSS World "Модель"? Формат этой команды.
  • Назначение и формат блока OPEN.
  • Назначение и формат блока CLOSE.
  • Назначение и формат блока READ.
  • Назначение и формат блока WRITE.
  • Назовите режимы работы блока WRITE и дайте им характеристику.
  • Назначение и формат блока SEEK.
  • Назначение и формат блока SELECT.
  • Вернуться к учебному плану