Два основных режима работы с фреймами - видеорежим и режим отчета. Для видеорежима имеется 2 подрежима просмотра данных (в панели REPEAT): строчный (действует по умолчанию) и табличный (включается клавишей "Пробел" и отменяется клавишей "Esc"). В строчном режиме маркер (полоска, выделяющая текущую строку) движется по строкам (записям), а в табличном - по строкам и столбцам (позволяет выполнять горизонтальный скроллинг, в том числе полей выходящих за поле экрана). Из обеих подрежимов возможен переход в редактирование, нажатием клавиши "Enter" или "F4", если редактирование не запрещено.
Можно выделить следующие виды фреймов:
Описание фрейма может быть внутренним (в файле программы) или внешним (в отдельном файле, где может быть описан только один фрейм).
Если фрейм в файле единственный, он может быть описан неявно (без слова FRAME и двойных угловых скобок). Неявно описанный фрейм распознается по первому ключевому слову, например, LINES (см. Приложение C, примеры 1-3).
Явное описание выполняется с помощью оператора FRAME (Frame,frame) и имеет вид:
имя_фрейма - идентификатор (псевдоним) именованного фрейма (могут использоваться латинские и русские буквы, цифры и знак "_" ; регистр букв различается);
-v -ключ главного фрейма.
Примеры: /*Описание главного фрейма */ Frame -v << ... >> /*Описание зависимого фрейма */ frame << ... >> /*Описание именованного фрейма */ Frame Acce_Dks << ... >> (Точки ... здесь обозначают тело фрейма)
Описание фрейма может загружаться из внешнего файла (внешнее описание). Формат загрузки внешнего фрейма:
где
имя_фрейма - внутреннее имя (псевдоним) фрейма;
file - имя файла, из которого грузится описание фрейма (фрейм в файле должен быть один, а его описание может быть неявным). Путь и расширение файла по умолчанию совпадают с путем и расширением файла программы.
Примеры: /* Загрузка главного и зависимого фреймов */ frame -v ( new_dks) ; frame ( vi_pos ) ; /* Загрузка именованых фреймов */ Frame setpas (vi_set) ; frame vi_zpc (vi_zpc) ;
Тело фрейма в общем случае включает следующие разделы:
|
|
|
|
Отдельные элементы могут отсутствовать. В общем случае задача включает несколько фреймов, например:
/************************************************************/ /* Открытие БД и индексных файлов*/ use "dks" ; /* Журнал проводок */ use "doc" ; /* Журнал учета первичных документов */ Codetab kptab ; /* Кодовая таблица видов налогов */ /* Переменные и массив, используемых в сценарии */ NUM Cur_level, Max_Level, Сумма_нал [Codemax( kptab)] ; /* Процедура инициализации строки журнала проводок */ Proc Dks_Init( NUM New_Npd, CHAR New_Kp) { doc->Vd => dks->Vd ; New_Npd => dks->Npd ; ......... } /* Загрузка фрейма из файла vi_mat.pan с псевдонимом "Товар" */ Frame Товар ( vi_mat) ; /****** Главный фрейм (ключ -v) */ Frame -v << select doc ; /* Выбор базы */ index = d_pvd ; /* Сортировка по номерам документов */ ..... >> /***** Зависимый фрейм (Пример связи по ключу) **/ Frame << select dks ; index = r_vdp ; key = doc->Vd + Str( doc->Nd) + doc->Nde + doc->Pd ; ..... >> /***** Второй зависимый фрейм */ Frame << ..... >> /***** Сменная видеоформа (ключ -v)*/ Frame -v << ..... >> /* Здесь могут быть зависимые фреймы для сменной видеоформы. */ /************************************************************/
В отчетах также может быть задано несколько главных фреймов ("-v"). Они интерпретируются последовательно как несколько проходов. Например, первым проходом формируется промежуточная база данных (выборка), а вторым проходом - собственно отчет.
Запоминается состояние текущего фрейма и выполняется фрейм с указанным внутренним именем (псевдонимом). Значения параметра Number определяют режим выполнения фрейма:
Number | Режим ---------------------------------------------------------------- без параметра | Фрейм выполняется в режиме экранной формы | независимо от того, вызван он в отчете или | в экранной форме. 1 | Фрейм выполняеся без вывода на экран или в отчет 2 | Фрейм начинается сразу в режиме редактирования 6 | Фрейм включается в текущий отчет 10 | Перерисовывается только табличная форма фрейма | после чего происходит выход из фрейма Примеры: vi_zpc() ; setpas( 2);
(Об открытии баз данных и индексных файлов и операторах SELECT и KEY см. п.3.4)
Пример /* Использование SELECT, INDEX и KEY */ frame << select dks ; index = r_pvdpk ; key = doc->Vd + doc->Pd + Str( doc->Nd, Sizeof( Nd)) ; ... >>
Для изменения активного индексного файла или отмены сортировки записей базы данных служит функция INDEX(), а для переустановки или отмены границ доступа к записям текущей базы данных - функция KEY().
DOUBLE_MODE Параллельный вывод в отчет двух экземпляров страниц. ENTER_MODE Режим с выбором из справочника и выходом из его фрейма без редактирования (по умолчанию нажатие клавиши "Enter" включает редактор). FAST Режим с быстрой прокруткой: при нажатии навигационной клавиши и движении по главному фрейму данные в зависимых фреймах не перерисовываются и обновляются через 0.4 с после отпускания клавиши. FONT ^nn Выбор шрифта для отчета. Шрифт задается в виде двухзначного шестнадцатиричного числа nn с предшествующим символом "^". Каждый бит шестнадцатиричного числа означает определенную модификацию выбранного набора символов в стиле "Epson". Бит | Модификация ------------------------------------------------ 0 | 0 - 10 знаков на дюйм (шрифт "пика") | 1 - 12 знаков на дюйм (шрифт "элита") ------------------------------------------------ 1 | пропорциональный шрифт ------------------------------------------------ 2 | сжатый шрифт ------------------------------------------------ 3 | жирный шрифт ------------------------------------------------ 4 | двойной удар ------------------------------------------------ 5 | двойная ширина символа ------------------------------------------------ 6 | наклонный ------------------------------------------------ 7 | подчеркнутый ------------------------------------------------ Пример: FONT ^85 Число 85 имеет следующее побитовое представление: 8 5 ---- ---- 1000 0101 / | \ ------------ ------ ----- подчеркнутый сжатый элита INTERVAL n Интервал между строками отчета. Задается в виде числа n (от 0 до 250), которое означает количество 1/250 долей дюйма в стиле управления принтером "Epson". По умолчанию команда изменения интервала не генерируется. В видеоформах не имеет значения. Пример: INTERVAL 70 LINES n Количество строк на странице (в отчете) или число строк в табличной форме (на экране). По умолчанию на экране - 23 строки, в отчете - не происходит деление на страницы. Параметры LINES и UNDERLINE имеют значение, если задана табличная форма, то есть панель типа REPEAT. Пример: LINES 10 NOAPPEND Запрет добавления записей в базу данных. NOBAR Убирает статусную строку внизу экрана (добавляет 2 строки). NOCOPY Запрет копирования записей в базу данных. NODELETE Запрет удаления и восстановления записей в базе данных. NOEDIT Запрет редактирования записей в базе данных. NOSKIP Запрет движения по базе данных (показ только текущей записи). POSITION x y len h Задает координаты окна экранной формы: x, y - координаты верхнего левого угла экранной формы, len - длина окна, h - высота окна. По умолчанию экранная форма занимает весь доступный экран, т.е. имеет координаты: x = 0, y = 0, len = 80, h = 23 Оператор POSITION имеет смысл задавать для вызываемых экранных форм, которые "всплывают" в какой-то части экрана и, отработав, исчезают. Пример: POSITION 5 5 50 10 PRESET n Предварительное позициирование на конкретную запись по ее номеру n в базе данных. SCROLL n [m] Разрешение горизонтального скроллинга табличной формы (в табличном режиме просмотра). Параметр n данного оператора означает ширину видимой части табличной формы. Остальная часть табличной формы не видна на экране (может быть просмотрена при движении курсора вправо). Второй, необязательный параметр m означает количество нескроллируемых (зафиксированных) начальных гнезд табличной формы. Пример: SCROLL 78 2 Это означает, что ширина видимой части таблицы не должна превышать 78 символов и два первых гнезда должны оставаться на своих местах. SIDES n Управляет видом рамки и тенью бордюра. Значение n может быть от 0 до 7: 0 -без рамки, 1 -одинарная, 2 -двойная, 3 -сплошная рамка, 4 -с тенью; Пример: SIDES 5 /* Одинарная рамка и тень (1+4) */ STREAM Режим потокового ввода: переход на следующую строку (запись) выполняется при нажатии клавиши "Enter" в последнем поле без нажатии клавиши "Вниз". TIMEOUT n Интервал срабатывания внутреннего таймера. Имеет обязательный параметр n - время в секундах. Если в течение заданного интервала не нажимались никакие клавиши, то генерируется событие TIMEOUT: и выполняется связанная с ним пользовательская программа. Пример: TIMEOUT 5 Это означает, что при отсутствии реальной работы с клавиатурой через каждые 5 секунд программа будет "оживать" и выполнять действия, запрограммированные в качестве реакции на данное событие. UNDERLINE n Смещение отчета от верхней границы листа или смещение табличной формы вниз от верхней границы окнна. Параметры LINES и UNDERLINE имеют значение, если задана табличная форма, то есть панель типа REPEAT. Пример: UNDERLINE 4 WITH имя1 [имя2 ...] Определяет, какие базы данных должны обновляться вместе с текущей в случае их редактирования (по умолчанию - только текущая база данных фрейма). Параметры имя1, имя2 ... задают псевдонимы баз данных. Пример: WITH client Цветовая гамма экранной формы Цветовая гамма для всей системы задается в файле конфигурации (z.cfg). Цветовая гамма, заданная для конкретной экранной формы, имеет наивысший приоритет, но действует только в пределах данной экранной формы. Операторы цветовой гаммы определяют цвета следующих элементов экранной формы: WCOL ^nn Цвет фона основной части экрана (экранной формы). PCOL ^nn Цвет отображения информации из базы данных. ACOL ^nn Цвет строчного курсора. ECOL ^nn Цвет маркера редактируемого гнезда. CCOL ^nn Цвет маркера текущей строки активной табличной формы. (Соответствует параметру CURCOL в конфигурационном файле). BACKCOL ^nn Цвет текущей строки пассивного фрейма (откуда ушел курсор) Цвет задается в виде шестнадцатиричного числа nn с предшествующим символом "^". Каждый бит шестнадцатиричного числа (например, 1E) означает определенную составляющую цвета: 0 - синяя составляющая цвета символа; 1 - зеленая составляющая цвета символа; 2 - красная составляющая цвета символа; 3 - режим повышенной яркости символа; 4 - синяя составляющая фона; 5 - зеленая составляющая фона; 6 - красная составляющая фона; 7 - режим мерцания символа. По умолчанию установлены следующие цвета: WCOL 1f PCOL 1e ACOL 3f ECOL 4f CCOL 70 BACKCOL 12 Пример: WCOL ^1C Здесь шестнадцатиричное число 1C имеет следующее побитовое представление и означает: 1 С ──── ──── 0001 1100 / │ \ ───────────── ──── ─────── на синем фоне ярко красный символ Пример задания параметров настройки: LINES 14 UNDERLINE 4 NODELETE NOCOPY FAST CCOL ^30
Любая панель фрейма описывается по следующей схеме:
Элемент описания Пример --------------------------------------------------------------------
Вид панели На экране В отчете --------------------------------------------------------------------------- HEAD Стабильная часть видеоформы Заголовочная часть ("шапка") REPEAT Табличная форма Строка повторения ("тело") TAIL Сменная часть видеоформы Заключительная часть ("хвост") TOP Шапка табличной формы Вершина текущего листа BOTTOM Подножье табличной формы Подножье текущего листа TITL Не интерпретируется Заголовок и хвост подраздела ---------------------------------------------------------------------------
Панель HEAD во фрейме может быть только одна, а панелей TAIL - несколько. В отчете это соответствует нескольким идущим друг за другом частям "хвоста" (это можно оформить и одним оператором TAIL). В экранном режиме несколько панелей TAIL соответствует сменным панелям, переключение между ними производится программно (функцией PANEL() ) или с помощью пар клавиш:
Панели TOP и BOTTOM выполняются соответственно в начале и конце нового листа отчета. Для первого листа действует HEAD, а не TOP.
Использование различных панелей для формирования многопозиционных документов с вложенными секциями можно пояснить на примере условного отчета (слева -схема отчета, справа - используемые панели):
СПИСОК СТУДЕНТОВ ВУЗА | HEAD ___________________________________________ | Графа 1 Графа 2 Графа 3 | ------------------------------------------- | Факультет ABC | TITL ------------- | Кафедра ABC1 | TITL | *********** *************** ************* | REPEAT *********** *************** ************* | ..... | *********** *************** ************* | - 1 - | BOTTOM ============================================== ___________________________________________ | 1 2 3 | TOP ------------------------------------------- | *********** *************** ************* | *********** *************** ************* | Итого по кафедре: ____ | TITL ...... | ...... | | Кафедра ABCn | TITL | *********** *************** ************* | *********** *************** ************* | REPEAT *********** *************** ************* | Итого по кафедре: ____ | TITL | Итого по факультету: _____ | TITL ....... | ....... | | Факультет XYZ | TITL ------------- | ....... | ....... | | Итого по факультету: _____ | TITL | ### Итого по вузу: _______ | TAIL | - 10 - | BOTTOM
TITL - панель фрейма, в которой описывается заголовок и окончание подраздела отчета. Правила ее описания отличаются от остальных панелей фрейма.
Подраздел (секция) отчета - это выделенная по некоторому признаку группа записей, в которой данный признак сохраняет постоянное значение. Записи группируются вместе путем предварительного индексирования базы данных по соответствующему выражению.
Например, пусть в базе данных списочного состава завода для каждого человека указаны: фамилия (FIO), цех (CEH) и бригада (BRIG). Проиндексировав базу данных по выражению вида: "CEH + BRIG", можно составить отчет, в котором люди будут сгруппированы по цехам, а внутри цеха по бригадам. Описание подзаголовков при этом может иметь следующий вид:
/* Подзаголовок раздела по цеху */ TITL CEH; { Цех N XXXX } CEH; { Итого по цеху: XXXX } Kol1 ; /* Подзаголовок раздела по бригаде */ TITL BRIG; { Бригада N XXXX } BRIG; { Итого по бригаде: XXX } Kol2; /* Kol1,Kol2 - переменные для подсчета (в панели REPEAT) количества записей по подразделам */Внимание:
Цикл - необязательный элемент описания фрейма, который интерпретируется только генератором отчетов; для экранных форм не имеет значения. Цикл заставляет включить данную панель в отчет несколько раз подряд для одной и той же текущей записи базы данных. Описание цикла имеет вид:
где
Пример /* Вывод частей хвоста в отчете */ TAIL CYCLE (0, Codemax( chtab)) IF( ob_dt [@J] # 0 .or. ob_kt [@J] # 0) { | XXXX | XXXXXXXXXXXXXXXXXXX.XX| XXXXXXXXXXXXXXXXXXX.XX| } Codestr( chtab, @J), $ ob_dt [@J], $ ob_kt [@J] ;
где усл_выраж - выражение логического типа.
Условие фильтрации интерпретируется только в отчетах. При этом данная панель выполняется (входит в отчет) только для записей, для которых условие фильтрации имеет значение "истина" (.TRUE.).
Пример: IF( Recno() > 10 .OR. Recno() < 3) /* Если ввести данное условие фильтрации в панель REPEAT отчета, то в него не войдут записи с номерами 3 - 10 */
Пример: { ^1F Сумма^00 XXXXXXXXXXXXXXX }
{ ХХХ.ХХ } /*Вывод числа на экран (в отчет) по формату N 6, 2 */
Описание действий имеет вид простого или составного оператора.
Примеры: /* Накопление суммы поля dks->SUM в переменную @0 */ frame sum_doc << select dks ; index = r_pvdpk ; key = doc->Vd + Str( doc->Nd ) + doc->Nde + doc->Pd ; HEAD {} 0 => @0 ; REPEAT {} Sum +> @0 ; >> /* Модификация полей Dks->Fcod, Dks->Date */ Frame accept_Dks_k << select Dks ; index = r_nknk ; key = ' '+ doc->Vd + Str(doc->Nd) + doc->Nde + doc->Pd; REPEAT {} Fcod = 'K' ? ' '=> Fcod : .not. EMPTY (Fcod) ? 'D'=> Fcod , doc->Date > Date ? doc->Date => Date , Write() ; >> /* Очистка записей в базе данных blanks */ frame clear_pos_in << select blanks ; index = bl_dk ; key = Doc_key + Str(script->Npd) ; REPEAT {} { '' => blanks->Nknd ; Ctod("99999999") => blanks->Dated ; 0 => blanks->Sumd ; '' => blanks->Vkd ; 0 => blanks->Nkd ; '' => blanks->Fcodd ; Write(blanks) ; } ; >>
Описание полей обычно связано с описанием гнезд ввода-вывода информации в рисунке панели. Количественное равенство числа гнезд и описаний полей не является обязательным. Если описаний меньше, чем гнезд, то избыточные гнезда останутся незаполненными (пустыми).
Если описаний больше, чем гнезд, то все гнезда будут заполнены, а избыточные описания будут выполнены, но не войдут в отчет и не будут отображены на экране (для экранных форм). Это позволяет запрограммировать пост-действия, которые будут выполняться после интерпретации данной панели.
Описание поля в общем случае имеет следующую структуру (необязательные элементы заключены в квадратные скобки):
------------------------------------------------------------
Опции могут сопровождаться комментариями и располагаться на нескольких строках, например:
$ /* (млрд) (млн) (тыс) (рубли).(коп) */ ! /* редактирование только по клавише*/ ^1F /* ярко белым цветом на синем фоне */
Сводное описание опций приведено в следующей таблице.
--------------------------------------------------------------------- Опция Интерпретация в видеоформах Интерпретация в отчетах --------------------------------------------------------------------- $ Выводит числа на экран Аналогично в стиле: 123 456 789.12 В этом же стиле позволяет их редактировать. Выводит даты в формате ДД.ММ.ГГГГ Аналогично В этом же стиле позволяет их редактировать. ! Запрет редактирования поля Действует только на числовые при вызове редактора по данные. Подавляет вывод клавише "Enter" (мягкий запрет) нулевых значений. !! Полный запрет редактирования Действует как опция ! данного поля. !!! Разрешение установки фокуса Действует как опция ! с запретом редактирования данного поля. ^nn Задает цвет данного поля Пока не используется (где nn от 00 до FF, cм. п.4.2.) ---------------------------------------------------------------------Одиночный "!" означает "мягкий" запрет редактирования, действующий лишь для упрощенного входа в режим редактирования (по клавише "Enter"), а двойной "!!" - полный запрет редактирования, например:
!! ^1F { Seek( podr, Str( Nkd)) ; podr->P_name ; }, /* Редактор экранных форм будет обходить "стороной" данное гнездо (поле "podr->P_name") */Редактирование вычисляемых значений интерпретатором не допускается. В режиме редактирования такие поля "проскакиваются". Чтобы нередактируемое поле не проскакивалось, следует дать опцию "!!!".
По умолчанию для данных типа DATE используется формат "ДД.MM.ГГ". Если дата вводится в кратком формате, то значения года 00-09 заменяются на 2000-2009, а значения 10-99 - на 1910-1999.
Опция "$" позволяет вводить /выводить даты в формате "ДД.MM.ГГГГ" (т.е. со столетием).
Пример: /* Дата в полном формате (с опциями цвета и запрета редактирования) */ REPEAT { XXXXXXXXXX } $ !! ^0e doc->Date;Для данных типа NUM опция "$" позволяет вводить и выводить значения в "денежной" форме (с отделением пробелами триад миллиардов, миллионов, тысяч, рублей и точкой - копеек).
Пример /* Использование различных опций */ REPEAT { X XXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX.XX XXXXXXXX } { Recno() > 0 .and. Npd > Num_posl ? Npd => Num_posl; Del() }, ! Npd => Num_posl, !! Nknk, $ Sum, Date ;
Реакции на события полей действуют только в видеоформах (в отчетах не интерпретируются). События видеополя описываются перед его выражением (блоком).
Пример: /* Cобытия для поля Vkd */ ED_BEG : Codefield( Vd, '1' ) = '#' ? EdStop() : Say( "Для выбора из меню нажмите F6 ") ED_END : { Vkd = ' ' ? 0 => Nkd ; Codefield(Vd,'3') = '*' ? Vkd => Vkk ; Fresh() } NEXT : Vkd = ' ' .and. Codefield( Vd, '1' ) # '#' ? { LastChar("F3") ; Next(0) } Vkd, /* События для поля Nkd */ F3 : { Nkd => @99 ; vi_client() ; /* Вызов картотеки клиентов */ Lastchar() # "Esc" ? /* Был ли откат по Esc ? */ { @99 => Nkd ; Fresh( +1) ; } /* Обновляем Nkd и перерисовываем следующее гнездо */ } ED_END : Fresh( +1) /* Перерисовываем следующее гнездо */ Nkd, /* Номер контрагента ДТ */ /************************************************************/
Событие наступает при переходе к редактированию данного поля. В реакции на данное событие можно запрограммировать предварительные (подготовительные) действия, которые необходимо совершить перед началом редактирования данного гнезда.
В частности, можно отменить редактирование поля, выполнив функцию EDSTOP(). В этом случае интерпретатор сразу переходит к редактированию следующего гнезда.
Пример: ED_BEG : Substr( Codestr( doc->Vd),4,1) # ' ' ? Edstop()
Событие наступает по завершению редактирования данного поля, но только в том случае, если действия по редактированию фактически проводились (независимо от исхода редактирования). Если мы в процессе редактирования просто "проскочили" данное поле, воспользовавшись навигационными клавишами, событие не наступает.В реакции на данное событие можно запрограммировать действия, которые необходимо совершить по окончанию редактирования поля. В частности, можно перепозициироваться в связанной базе данных в соответствии с изменившимся в результате редактирования значением текущего поля, а также перерисовать поля, зависящие от значения редактируемого поля.
Пример: /* По окончанию редактирования переписываем новое значение переменной New_Field в поле базы данных */ ED_END : { New_Field => base->Field ; Fresh( +1) }
Событие наступает по завершению редактирования данного поля, независимо от того, производились ли фактически действия по его редактированию. Событие наступает, даже если мы в процессе редактирования просто "проскочили" данное поле, воспользовавшись навигационными клавишами.В реакции на данное событие можно запрограммировать действия, которые необходимо совершить по выходу из редактирования поля, например, проверить, удовлетворяет ли определенным условиям значение текущего поля.
Пример: NEXT : Kp = ' ' ? Beep() /* Если поле пустое - писк */
Событие наступает, если в процессе редактирования нажали клавишу "F3". Клавиша "F3" обычно используется, чтобы "заглянуть" в справочник.В реакции на данное событие программируются действия, связанные с организацией просмотра одной или нескольких картотек и выбором нужного элемента из нужной картотеки. Можно также перепозициироваться в связанной базе данных в соответствии с изменившимся в результате произведенного выбора значением текущего или любого иного поля, а также перерисовать поля, зависящие от значения редактируемого поля.
Пример: F3 : { Nkd => @99 ; Vkd = 'П' ? vi_pod() : Vkd = 'Т' ? vi_tit() : Vkd = 'К' ? vi_cln() : Vkd = 'С' ? vi_sot() ; Lastchar() # "Esc" ? { @99 => Nkd ; Fresh( +1) ; Fresh( +2) } }
Событие наступает в табличном режиме просмотра при нажатии клавиши "Enter". Нормальной реакцией на нажатие клавиши "Enter" является переход в режим редактирования. Однако, если описано событие ENTER, то вместо перехода к редактированию выполняется реакция на данное событие. В ней можно, в частности, произвести вызов новой видеоформы, раскрывающей содержание текущего поля.
Пример: ENTER : { Vkd = 'П' ? vi_pod() : Vkd = 'Т' ? vi_tit() : Vkd = 'К' ? vi_cln() : Vkd = 'С' ? vi_sot() ; }
Событие наступает в табличном режиме просмотра (включается "пробелом") при переходе маркером на данное поле.
Пример: REPEAT { XXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXX } name, FOCUS : reply("Поле len") len, dat;
Выражение для отображения значения может представлять собой :
Примеры описаний выражений полей /* Переменная и элемент массива */ New_, Ch_ar [i], /* Поле Field1 базы данных bas1 */ bas1->Field1, /* Поле Field2 текущей базы */ Field2, /* Поле Count либо RS (условное выражение) */ New_ > 0 ? { Seek( base, Key) ; base->Count ; } : client->RS, /* Операторы присваивания и накопления (редактируется источник значения) */ base->Field_ => Name, /* Редактируется поле Field_ */ base->Val1 +> @1, /* Редактируется поле Value */ base->Val2 +> @1 => @2, /* Редактируется поле Value */ /* Блок вычисления редактируемой переменной Val */ { Seek( base, Key) ; base->Value => Val ; Val ; }, /* ! Вычисляемые выражения (не редактируются) */ Field_ + "01", Recno() + 2, /* Установка фокуса редактора (без редактирования) */ !!! "Подтвердите ввод" ;
Многие события обрабатываются интерпретатором самостоятельно в соответствии с внутренними алгоритмами. Можно также задать в программе свои реакции на ряд событий. Реакция на событие представляет собой оператор (простой или блок), выполняемый при наступлении события.
Описание события и реакции имеет следующий вид:
Пример: ED_BEG : Sum => Old_Sum /* По началу редактирования запоминаем сумму */ /* Если сумма изменилась, корректируется массив и выполняется процедура t_renal() */ ED_END : Sum # Old_Sum ? { Sum - Old_Sum +> Nal_sum [@J] ; t_renal( 1) }Внимание:
События и реакции, описанные в панели HEAD, относятся ко всему фрейму в целом. Большинство событий описываются только в панели HEAD.
2. По функциональному признаку события можно разбить на:
Событие PREVIOUS Его можно использовать для всех панелей видеоформ и отчетов.
События для панели HEAD видеоформ
ED_BEG ED_END ENTER ESC FROMLOW FROMNEXT HELP KEY MINUS NEWBUF PLUS PREPROC PREVIOUS RECEIVE RETURN START TAB TIMEOUT TOLOW TONEXT WRITE ALT_0..ALT_9 ALT_F1..ALT_F10 ALT_A..ALT_Z F8 F9 События для панели HEAD отчетов
START RETURN PREPROC PREVIOUS События для полей видеоформ (см.п.4.4.3.)
ED_BEG ED_END ENTER F3 FOCUS NEXT
События входа и выхода
PREVIOUS PREPROC START RETURN ESC События перехода в другие фреймы и возврата
TOLOW FROMLOW TONEXT FROMNEXT События добавления и редактирования
NEWBUF ED_BEG ED_END WRITE События нажатия клавиш и прочие
KEY ENTER MINUS PLUS TAB HELP ALT_0..ALT_9 ALT_F1..ALT_F10 ALT_A..ALT_Z F8, F9 TIMEOUT RECEIVE
Событие наступает непосредственно перед интерпретацией панели и выводом ее на экран или в отчет. В реакции можно менять границы цикла и переменные, входящие в условие фильтрации IF( ) данной панели. Событие выполняется для любой панели.
Пример: REPEAT IF( @L1) { XXXX XXXXXX } Recno(), Nd ; PREVIOUS : /* Ищем связанную запись в базе "proc.dbf" и вычисляем условие */ { Seek( proc, Str( Recno(), 6)) ; proc->Okl > 10 * Min_Okl => @L1 ; } /* Панель REPEAT выполняется для всех записей базы данных. При переходе к каждой следующей записи вначале выполняется реакция на событие PREVIOUS (определяется значение переменной @L1), затем проверяется условие фильтрации IF( @L1) и выполняется или нет тело панели REPEAT для данной записи.*/
Событие наступает непосредственно после события START. На момент выполнения события PREPROC база данных уже открыта, но индекс и ключ к ней еще не определены, что позволяет в реакции на данное событие выполнить условную установку пары "индекс-ключ".
Пример: PREPROC : { Tabmenu( vdtab) => Point_Num ; Point_Num > 0 ? { Index( doc:d_pd) ; Key( Codefield( vdtab, Point_Num, '#')) } ; } /* В этом примере перед выполнением текущего фрейма на экран выдается меню на основе кодовой таблицы (файл "vdtab.dic"), например, с перечнем всех видов документов. Если Вы выбрали какой либо конкретный вид документов, то на экране появятся только документы данного вида. Об этом позаботятся функции Index() - установка индексного файла и Key() - установка ключа. Если Вы отказались от выбора клавишей "Esc" то на экране появится полный список документов, т.к. в этом случае не устанавливается ни индексный файл, ни ключ. */
Событие наступает непосредственно после входа в данный фрейм, до вычисления интерпретатором значения ключа связи. В блоке реакции можно выполнить однократные предварительные действия, например, установить начальные значения переменных, в том числе входящих в выражение ключа. Ключ в этом случае будет вычислен исходя из обновленных значений его составляющих.
Пример: START : { 0 => Alfa => Betta ; /* Сброс переменных */ vi_date() ; /* Ввод отчетного периода */ Lastchar() = 'Esc' ? Exit() ; /* Откат по "Esc" */ } /* Здесь перед выполнением текущего фрейма будут обнулены переменные Alfa и Betta, после чего вызывается видеоформа vi_date, запрашивающая значения некоторых переменных. В случае нажатия клавиши "Esc" производится немедленный выход из текущего фрейма без его интерпретации (функция Exit() ). */
Событие наступает непосредственно перед нормальным выходом из текущей экранной формы (по клавише "F10") или фрейма отчета. С помощью реакции на данное событие можно запомнить выбранную из справочника клавишей "Enter" запись (должен быть установлен режим выбора опцией ENTER_MODE). Можно также вернуть значение в вызывающую экранную форму или выдать сообщение на экран при завершении прогона отчета.
Событие наступает непосредственно перед принудительным выходом (по клавише "Esc") из текущей экранной формы. С реакции на данное событие можно возвратить значение в вызывающую экранную форму.
Пример: NOCOPY NOAPPEND NOEDIT ENTER_MODE HEAD { /* Рисунок панели */ } Vd, Ndoc, Kart_name( Vkk, Nkk), Kart_town( Vkk, Nkk); RETURN : Recno() => @0 ; /* Номер выбранной записи*/ ESC: 0 => @0; REPEAT { XXXXXX XXXXXXXX XXXXXXXXXXXXXXXXXX.XX X XXXXXX } Nd, Dreg, $ SumDoc, Vkk, Nkk ;
2. События перехода в другие фреймы и возврата
Эти события возникают при переходе в зависимый или сменный фрейм или возврате из него при нажатии соответствующих клавиш (cм. п.4.1.3).
Для восстановления стандартной реакции используется функция Default() (иначе, например, после обработки события TONEXT не попадем в следующий главный фрейм).
Примеры: /*******************************************/ TOLOW : cena_mod() ; /*******************************************/ FROMLOW : Lastchar() = 'Enter' ? Lastchar( "Enter") : Default() ; /*******************************************/ RETURN : Recno() => @99 ; FROMLOW : Lastchar() = 'Enter' .and. @99 # 0 ? { Go( client, @99) ; Show( 2) ; } /*******************************************/ TONEXT : { 0 => @99 ; Default() ; } FROMNEXT : { @99 > 0 ? { Go( @99); Show( 2); } } /*******************************************/ FROMNEXT : { Adjust(boxs, 0) ; create_list( 1) ; Show() ; } ; /*******************************************/
3. События добавления и редактирования
Пример: NEWBUF : { '51' => DT ; '6004' => KT ; @S10 => RM ; } /* Здесь при переходе к новой записи поле DT (дебет) инициализируется значением '51' (значение дебетуемого счета), поле KT - значением '6004', а поле RM (рабочее место) значением переменной @S10. Эти значения можно затем изменить в процессе редактирования (если редактирование не запрещено). */
Событие наступает при входе в режим редактирования нажатием клавиши "F4" или "Enter". В реакции на данное событие можно запрограммировать предварительные действия, которые необходимо совершить перед началом редактирования. В частности, можно отменить режим редактирования, вызвав функцию EDSTOP().
Пример: ED_BEG : Flag = '*' ? Edstop() ; /* Выполняется проверка поля Flag текущей базы данных и при наличии в этом поле символа '*' переход в режим редактирования не производится. */
Событие наступает по выходу из режима редактирования независимо от исхода редактирования. В блоке реакции на данное событие можно запрограммировать действия, которые необходимо совершить по окончанию редактирования записи. В частности, можно проанализировать результат редактирования и в случае несоответствия отменить запись измененных значений в базу данных.
Пример: ED_END : Recno() < 1 .and. Kol = 0 .and. Sum = 0 ? Updated( 0) ; /* Реакция на окончание редактирования в данном примере заключается в том, что производится проверка результатов редактирования, и, в случае неудовлетворительных результатов (поля Kol и Sum в новой проводке не заполнены), сбрасывается флаг редактирования, что отменяет образование новой записи и запись в базу данных (блокируется попытка ввести в журнал проводок пустую, незначащую проводку). */
Cобытие наступает непосредственно перед записью информации в базу данных после выхода из режима редактирования. Перед выполнением данного события производится захват текущей записи или счетчика записей для нового буфера. При работе в сети обработка данного события позволяет получить достоверное значение счетчика записей.
Пример: WRITE : /* Текущая база - "detal.dbf" */ Recno() < 1 ? { Initbuf( proc) ; Reccount() => proc->Count ; Write( proc, 0) ; } /* В данном примере для каждой новой записи базы данных "detal.dbf" образуется новая запись в связанной базе "proc.dbf" и значение будущего номера вновь образуемой записи базы данных "detal.dbf" будет занесено в поле Count базы данных "proc.dbf", которое используется как поле связи между двумя базами. */
4. События нажатия клавиш и прочие
Cобытия наступают в случае нажатия соответствующей клавиши или пары клавиш. В pеакции на эти события можно описать требуемые действия.
Стандартная реакция на нажатие клавиши "F8" - пометка текущей записи на удаление или снятие пометки, а клавиши "F9"- создание отчета по заранее подготовленной форме (перечень отчетов должен быть в файле с расширением ".lst"). Можно задать свои реакции на нажатие этих клавиш.
Примеры: /*******************************************/ TAB : Video( Rtrim( CodeField( Vd, '6')) ) ; /*В ответ на нажатие клавиши "Tab" производится вызов в оверлейном режиме видеоформы, имя которой записано в поле '6' кодовой таблицы, связанной с кодированным полем Vd (вид документа). На экране раскрывается образ данного документа с возможностью его pедактиpования.*/ /*******************************************/ ALT_1 : /* просмотр документов по Дебету */ { 'К' => VKSS ; Recno() => NKSS ; '' => NKN ; 0 => @200 ; Info_mnu( 'D', 'S') ; } /*******************************************/ ALT_2 : /* просмотр документов по Кредиту */ { 'К' => VKSS ; Recno() => NKSS ; '' => NKN ; 0 => @200 ; Info_mnu( 'K', 'S') ; } /*******************************************/ F8 : Deleted() ? Mark(' ') : Substr(@RIGHTS,1,1) = '1' ? Mark('*') ; /*******************************************/ ENTER : Recno() < 1 ? Default() ; /*******************************************/ F9 : Recno() > 0 ? { .F. => @L0 ; Val(Tabno) => @10 ; Box => @11 ; Report( "cen_mn") ; .T. => @L0 ; Adjust(boxs, 0) ; create_list( 1) ; Show() ; } /*******************************************/
Событие наступает в результате нажатия пары клавиш "Alt+F1", с помощью этого вызывается обычно пользовательская подсказка.
Пример: HELP : View( "doc_all") ; /* Просмотр на экране файла "doc_all." */
Событие наступает в результате нажатия любой незарезервированной клавиши, если реакция на нее не описана явно. Блок обработки сам должен определить код нажатой клавиши.
Пример: KEY : Lastchar() = '\1' ? Menu( "menu_1.mnu") : Lastchar() = '\2' ? Menu( "menu_2.mnu") ; /* В этом примере описана реакция на клавиши '1' и '2'. В первом случае вызывается и выполняется меню из файла "menu_1.mnu", во втором - из файла "menu_2.mnu". */
Событие наступает периодически, если задан интервал его наступления (в секундах). Первый раз событие наступает по истечении заданного интервала с момента последнего нажатия любой клавиши на клавиатуре. При интенсивной работе с клавиатурой это событие может вообще не наступить. Оно используется, например, для периодического обновления информации на экране во время продолжительной паузы в работе.
Пример: TIMEOUT : { Saldo( 1) => Sum_New ; Sum_New # Sum_Old ? { Beep() ; Sum_New => Sum_Old ; } } /* Периодически производится расчет сальдо и если значение сальдо не совпадает с ранее вычисленным, подается звуковой сигнал. (Можно заниматься другим делом; компьютер сообщит, что остатки на расчетном счете изменились). */
Асинхронное событие, срабатывает при получении дейтаграммы.
(см.п.5.4 Сетевые функции).