Жанр: Учеба
Техника программирования на турбо-С
...ая
выдается, начиная с координат окна, задаваемых значениями х и у.
void field_tally(WINDOW *wnd)
При обращении к этой функции на экран дисплея выводятся
значения всех данных, хранящихся в буфере, для всех полей
шаблона. Вы можете использовать эту функцию, когда, например, вы
заполнили буфер значениями из записи базы данных.
void field_window(FIELD *fld, char *helpname, int x, int y)
Эта функция обеспечивает выдачу контекстно-зависимого
help-окна для каждого поля шаблона. Параметр helpname является
строкой, содержащей мнемонику help-окна в текущем help-файле, и
специфицируется предварительно путем обращения к функции
load_help (см. Главу 7). Точно так же, как функция data_entry
осуществляет переход от поля к полю, обращение к функции set_help
для каждого из полей позволяет привязать конкретное help-окно для
каждого из них. Параметры х и у позволяют специфицировать позицию
экрана, с которой будет осуществляться выдача help-окна.
Заметьте, что эта функция, а также еще три, рассмотренные
ниже, не требуют наличия в списке параметров указателя WINDOW.
Для этих функций достаточно указателей FIELD, так как эти
указатели представляют собой указатели на цепочку связного
списка, который и осуществляет привязку функции к конкретному
окну. Эти функции модифицируют определенные ранее поля, не
обращая внимания на то, что они принадлежат конкретному шаблону
окна.
void clear_template(WINDOW *wnd)
Эта функция освобождает буферы сбора данных всех полей
шаблона, обращая их в пустую строку, заканчивающуюся нулевым
символом конца строки, а также отображает на экране все поля
шаблона.
void field_validate(FIELD *fld, int (*validfn)())
Эта функция относится к макросам. Она использует адрес
функции проверки допустимости вводимых значений (если таковая
будет написана пользователем). Стандартные функции,
осуществляющие проверку допустимости вводимых в поля данных,
обычно не осуществляют требуемой проверки на ошибочную ситуацию.
По этой причине пользователь обычно сам пишет функцию,
производящую контроль данных. Функция data_entry будет
осуществлять обращение к определенным вами функциям контроля
данных после того, как ею самой будет осуществлен их первичный
контроль. Если это так, то она будет передавать в эти ваши
функции адрес буфера сбора данных, и разработанные вами функции
контроля данных смогут осуществить проверку введенных
пользователем значений, находящихся уже в буфере. Ваша функция
контроля допустимости данных может содержать вызов функции
error_message (см. Главу 6) для обработки ситуации, когда будет
обнаружено недопустимое значение. При этом определенная вами
функция контроля данных должна возвращать лишь два значения ОК
или ERROR, которые, в свою очередь, определены в twindow.h. Если
функция возвращает значение ОК, то функция data_entry будет
обрабатывать следующее поле шаблона. Если же функция контроля
возвращает значение ERROR, то функция data_entry "остановится" на
поле, в данных которого обнаружена ошибка.
void field_protect(FIELD *fld, int prot)
Эта функция также относится к макросам. Она устанавливает
или отменяет (в зависимости от значения параметра prot) защиту
характеристик поля. Защищенное поле не обрабатывается
(игнорируется) функцией data_entry. Используя функцию
field_protect, вы можете управлять доступом пользователей к полям
шаблона, разрешая или запрещая запись в них данных.
Эта функция может использоваться совместно с функциями field
_validate, clear_template и field_fally для контроля над
изменениями, производимыми в записях базы данных, в случае, если
элементы записи базы данных отображаются в шаблоне.
Для понимания того, как значительно расширяет возможности
программы использование функции field_protect, рассмотрим шаблон,
изображенный на рисунке 8.1. Примите во внимание, что этот шаблон
содержит поля, образующие запись по одному служащему в файле базы
данных. Шаблон ввода данных используется для ввода, отображения,
поиска и изменения записей в файле. Перед началом ввода данных
ваша программа может обратиться к функции field_protect для
защиты всех полей, кроме поля "номер служащего". Затем вы можете
обратиться к функции field_validate, передав ей указатель на
обычные, разработанные вами функции контроля данных на
допустимость. После того, как пользователь введет данные в поле
"номер служащего", функция data_entry (будет описана позже)
осуществит обращение к разработанной вами функции контроля
данных, которая осуществит поиск и сравнение по ключу (номер
служащего) нужной записи в базе данных. Функция контроля данных
произведет загрузку соответствующих буферов накопления данных
элементами данных из найденной записи базы данных, а затем
обратится к функции field_fally для вывода значений элементов
данных на экран. После этого будет вызвана функция field_protect
для установки защиты для поля "номер служащего" и снятия защиты с
остальных полей. В итоге функция контроля данных передаст
управление функции data_entry, и пользователь получит возможность
произвести коррекцию значений элементов данных. По завершении
пользователем процесса обработки записи система передаст
управление прикладным функциям, которые непосредственно будут
обращаться в data_entry. Эти функции могут перезаписать
откорректированную запись в файл, очистить буфера данных и
шаблоны путем обращения к функции clear_template, переопределить
защиту полей шаблона (а значит, и записи), сняв защиту с поля
"номер служащего" и установив защиту для других полей, и
повторить весь процесс обработки записи заново.
----------------------------------------------------------------¬
¦ ¦
¦ ¦
¦ ¦
¦ -------------Employee Record-----------¬ ¦
¦ ¦ ¦ ¦
¦ ¦ Employee #: 377 ¦ ¦
¦ ¦ Name: Otis Cribblecoblis ¦ ¦
¦ ¦ Department: 2001 ¦ ¦
¦ ¦ Salary: 15450.00 ¦ ¦
¦ ¦ Date Hired: 01/02/55 ¦ ¦
¦ ¦ SSN: 221-52-1234 ¦ ¦
¦ ¦ ¦ ¦
¦ ¦ ¦ ¦
¦ L--------------------------------------- ¦
¦ ¦
¦ ¦
¦ ¦
L----------------------------------------------------------------
Рис. 8.1. Пример шаблона ввода данных
void field_help(FIELD *fld, int (*helpfn)())
Эта функция относится к макросам. Она позволяет вам
установить специальную help-функцию, которая будет вызываться
вместо стандартной help-функции. Эта функция используется для
отдельных полей шаблона, когда пользователю требуется получить по
ним более полную help-информацию, чем ему предоставлено текстом,
отображаемым в окне.
В процессе ввода данных в окно у пользователя могут
возникнуть различные вопросы относительно как предназначения
окна, так и вида входных данных. Для получения ответов на свои
вопросы пользователю достаточно нажать на специально выделенную
help-клавишу, которая инициирует обращение к специальной
help-функции. Функция data_entry передаст адрес буфера накопления
данных поля, что впоследствии даст возможность специальной
help-функции вернуть текущее значение в поле.
Эта отличительная черта функции field_help используется,
когда имеется список возможных значений, из которых пользователь
должен осуществлять выбор, но отображение всего списка в окне
постоянно нецелесообразно. Вы можете открыть еще одно окно для
выдачи help-информации с помощью вашей специальной help-функции,
отобразить в нем весь список возможных значений и затем
использовать функцию get_selection (см. Главу 6) для обеспечения
выбора пользователем нужного ему значения. Вы также можете, как
это делается в примере, который представлен в этой главе ниже,
записывать текущую дату в буферы накопления данных полей. Вам
предоставлена возможность осуществлять запросы к базе данных.
Очевидно, что при работе с записями файла "Служащий" базы данных
ваша help-функция может выдавать список номеров служащих и их
фамилии, выбирая эту информацию непосредственно из самого файла
"Служащий".
int data_entry(WINDOW *wnd)
Эта функция обрабатывает вводимые в шаблон данные.
Пользователь может просмотреть весь шаблон со значениями всех
полей, выдавая на дисплей текущие значения данных из
соответствующих буферов накопления данных. Пользователь
осуществляет ввод данных в поля в той последовательности, в
которой поля были установлены в шаблоне с помощью функции
establish_field, при этом позиция размещения поля в шаблоне во
внимание не принимается.
Поле, которое предназначено в данный момент для ввода в него
данных, отображается пользователю с учетом суммарного
пространства под вводимые данные, включая пунктуацию, и
выделяется повышенной яркостью в соответствии со значением
параметра ACCENT, определяющим цвет окна. Курсор устанавливается
в первой позиции поля, и функция переходит в режим ожидания ввода
данных. Пользователь может начать ввод данных или в текущее поле,
или установить текущим другое поле, используя клавишу "ВВОД",
клавишу табуляции "Таб" или клавиши управления курсором. Клавиши
"КЛЮЧ", "Страница вверх" ("PgUp"), "Страница вниз" ("PgDn"),
"КОН" ("End"), перемещения курсора в первую позицию первой строки
("Home") и функциональные клавиши (с "ПФ1" до "ПФ10", исключая
клавишу, за которой закреплен вызов help-функции) предназначены
для завершения процесса ввода данных и возврата из функции
data_entry, к которой перед этим было осуществлено обращение, в
точку вызова.
После ввода пользователем последнего символа поля происходит
выделение повышенной яркостью следующего поля и перемещение к
нему курсора. Перед этим функция data_entry обращается к своим
собственным функциям контроля данных и (если вы установили еще и
свои специальные функции контроля данных) к специальным функциям
контроля. Все эти функции должны в результате работы выдать
значение ОК, в противном случае функция data_entry не переместит
курсор к следующему полю.
Если пользователь нажал клавишу, за которой закреплен вызов
help-функции, то будет осуществлен вызов специальной help-функции
(если она вами определена), предназначенной для текущего поля,
путем передачи ей адреса буфера накопления данных поля. Если
help-функция вами не создана и help-окно "привязано" к полю, то
help-функции, описанные в Главе 7, обеспечат выдачу на экран
дисплея help-окна. Если ни help-окно, ни help-функция не
определены, то нажатие пользователем help-клавиши не приведет ни
к какому результату, если, конечно, программа использует
help-функции независимо от контекста вводимых в окно данных.
После того, как происходит возврат из функции data_entry в точку
ее вызова, все буферы полей содержат значения данных, которые
ввел пользователь. Эта функция возвращает управление в точку
вызова при нажатии клавиш, означающих конец ввода данных в
шаблон. Таковыми являются клавиша "КЛЮЧ", клавиши листания
страниц ("PgUp", "PgDn") или функциональные клавиши, приводящие к
завершению процесса ввода данных. Прикладное программное
обеспечение анализирует значение последней нажатой пользователем
клавиши для определения его намерений. Нажатие клавиши "КЛЮЧ",
например, может означать "Игнорируй все внесенные мной изменения
и верни меня к предыдущему содержанию шаблона". Клавиши "Страница
вверх" ("PgUp") и "Страница вниз" ("PgDn") означают (как
определено в keys.h), что пользователь хочет перейти к следующей
или предыдущей записи базы данных. Когда пользователь завершает
ввод данных, то код завершения процесса ввода передается в
программу, вызвавшую функцию data_entry, для дальнейшего
использования.
Исходный текст: entry.c
-----------------------------------------------------------------
Листинг 8.1 представляет собой исходный текст файла entry.c,
который содержит библиотечные функции поддержки оконного шаблона
ввода данных.
Листинг 8.1: entry.c
/*----------------entry.c----------------*/
#include "stdio.h"
#include "ctype.h"
#include "stdlib.h"
#include "alloc.h"
#include "mem.h"
#include "string.h"
#include "twindow.h"
#include "keys.h"
#define FIELDCHAR '_'
int insert_mode = FALSE; /* режим вставки, ВКЛ/ВЫКЛ */
extern int helpkey;
/*----------------локальные прототипы----------------*/
void addfield(WINDOW *wnd, FIELD *fld);
void disp_field(WINDOW *wnd, char *bf, char *msk);
void data_value(WINDOW *wnd, FIELD *fld);
void insert_status(void);
int read_field(WINDOW *wnd, FIELD *fld);
void right_justify(char *s);
void right_justify_zero_fill(char *s);
int validate_date(char *s);
int endstroke(int c);
int spaces(char *c);
/*----------------инициализация шаблона---------------*/
void init_template(WINDOW *wnd)
{
FIELD *fld, *fl;
fld = FHEAD;
while (fld) {
fl = fld-"fnxt;
free(fld);
fld = fl;
}
FHEAD = NULL;
}
/*---------------установка полей шаблона--------------*/
FIELD *establish_field(wnd, cl, rw, msk, bf, ty)
WINDOW *wnd;
int rw;
int cl;
char *msk;
char *bf;
int ty;
{
FIELD *fld;
if ( (fld = malloc(sizeof(FIELD))) == NULL)
return NULL;
fld-"fmask = msk;
fld-"frow = rw;
fld-"fcol = cl;
fld-"fbuff = bf;
fld-"ftype = ty;
fld-"fprot = 0;
fld-"fnxt = fld-"fprv = NULL;
fld-"fvalid =NULL;
fld-"fhelp = NULL;
fld-"fhwin = NULL;
fld-"flx = fld-"fly = 0;
addfield(wnd, fld);
return fld;
}
/*--------добавление поля в конец списка-----------*/
static void addfield(WINDOW *wnd, FIELD *fld)
{
if (FTAIL) {
fld-"fprv = FTAIL;
FTAIL-"fnxt = fld;
}
FTAIL = fld;
if (!FHEAD)
FHEAD = fld;
}
/*---------отображение данных в полях----------*/
static void disp_field(WINDOW *wnd, char *bf, char *msk)
{
while (*msk) {
wputchar(wnd, *msk != FIELDCHAR ? *msk : *bf++);
msk++;
}
}
/*--------отображение значений данных в полях-----------*/
static void data_value(WINDOW *wnd, FIELD *fld)
{
wcursor(wnd, fld-"fcol, fld-"frow);
disp_field(wnd, fld-"fbuff, fld-"fmask);
}
/*----------отображение всех полей в окне---------------*/
void field_tally(WINDOW *wnd)
{
FIELD *fld;
fld = FHEAD;
while (fld != NULL) {
data_value(wnd, fld);
fld = fld-"fnxt;
}
}
/*-----------установка help-окон для полей--------------*/
void field_window(FIELD *fld, char *hwin, int x, int y)
{
fld-"fhwin=hwin;
fld-"flx = x;
fld-"fly = y;
}
/*-----------очистка всех полей шаблона--------------*/
void clear_template(WINDOW *wnd)
{
FIELD *fld;
char *bf, *msk;
fld = FHEAD;
while (fld != NULL) {
bf = fld-"fbuff;
msk = fld-"fmask;
while (*msk) {
if (*msk == FIELDCHAR)
*bf++ = ' ';
msk++;
}
fld = fld-"fnxt;
}
field_tally(wnd);
}
/*---------установка режима вставки/замены курсора------------*/
static void insert_status()
{
set_cursor_type(insert_mode ? 0x0106 : 0x0607);
}
/*------------чтение поля с клавиатуры--------------*/
static int read_field(WINDOW *wnd, FIELD *fld)
{
char *mask = fld-"fmask, *buff = fld-"fbuff;
int done = FALSE, c, column;
column = fld-"fcol;
while (*mask != FIELDCHAR) {
column++;
mask++;
}
while (TRUE) {
wcursor(wnd, column, fld-"frow);
c = get_char();
if (fld-"ftype == 'A')
c = toupper©;
clear_message();
switch © {
case '\b':
case BS:
if (buff == fld-"fbuff) {
done = c == BS;
break;
}
--buff;
do {
--mask;
--column;
} while (*mask != FIELDCHAR);
if (c == BS)
break;
case DEL:
movmem(buff+1, buff, strlen(buff));
*(buff+strlen(buff)) = ' ';
wcursor(wnd, column, fld-"frow);
disp_field(wnd, buff, mask);
break;
case FWD:
do {
column++;
mask++;
} while (*mask && *mask != FIELDCHAR);
buff++;
break;
case INS:
insert_mode ^= TRUE;
insert_status();
break;
case '.':
if (fld-"ftype == 'C') {
if (*mask++ && *buff == ' ') {
*buff++ = '0';
if (*mask++ && *buff == ' ')
*buff++ = '0';
}
right_justify(fld-"fbuff);
wcursor(wnd, fld-"fcol, fld-"frow);
disp_field(wnd, fld-"fbuff, fld-"fmask);
column = fld-"fcol+strlen(fld-"fmask)-2;
mask = fld-"fmask+strlen(fld-"fmask)-2;
buff = fld-"fbuff+strlen(fld-"fbuff)-2;
break;
}
default:
if (endstroke©) {
done = TRUE;
break;
}
if (toupper(fld-"ftype)!='A'&&!isdigit©) {
error_message("Numbers only");
break;
}
if (insert_mode) {
movmem(buff, buff+1, strlen(buff)-1);
disp_field(wnd, buff, mask);
wcursor(wnd, column, fld-"frow);
}
*buff++ = c;
wputchar(wnd, c);
do {
column++;
mask++;
} while (*mask && *mask != FIELDCHAR);
if (! *mask)
c = FWD;
break;
}
if (!*mask)
done = TRUE;
if (done) {
if (fld-"ftype == 'D' &&
c != ESC &&
validate_date(fld-"fbuff) !=OK)
return ERROR;
break;
}
}
if (c != ESC && toupper(fld-"ftype) != 'A') {
if (fld-"ftype == 'C') {
if (*mask++ && *buff == ' ') {
*buff++ = '0';
if (*mask++ && *buff == ' ')
*buff++ = '0';
}
}
if (fld-"ftype == 'Z' || fld-"ftype == 'D')
right_justify_zero_fill(fld-"fbuff);
else
right_justify(fld-"fbuff);
wcursor(wnd, fld-"fcol, fld-"frow);
disp_field(wnd, fld-"fbuff, fld-"fmask);
}
return c;
}
/*-------проверка значения с на код клавиши завершения------*/
static int endstroke(int c)
{
switch © {
case '\r':
case '\n':
case '\t':
case ESC:
case F1:
case F2:
case F3:
case F4:
case F5:
case F6:
case F7:
case F8:
case F9:
case F10:
case PGUP:
case PGDN:
case HOME:
case END:
case UP:
case DN:
return TRUE;
default:
return FALSE;
}
}
/*------------выравнивание вправо, заполнение пробелами------*/
static void right_justify(char *s)
{
int len;
len = strlen(s);
while (*s == ' ' || *s == '0' && len) {
len--;
*s++ = ' ';
}
if (len)
while (*(s+(len-1)) == ' ') {
movmem (s, s+1, len-1);
*s = ' ';
}
}
/*-----------выравнивание вправо, заполнение нулями----------*/
static void right_justify_zero_fill(char *s)
{
int len;
if (spaces(s))
return;
len = strlen(s);
while (*(s + len - 1) == ' ') {
movmem(s, s + 1, len-1);
*s = '0';
}
}
/*---------------контроль пробелов-------------*/
int spaces(char *c)
{
while (*c == ' ')
c++;
return !*c;
}
/*----------------проверка даты---------------------*/
static int validate_date(char *s)
{
static int days [] =
{ 31,28,31,30,31,30,31,31,30,31,30,31 };
char date [7];
int mo;
strcpy(date, s);
if (spaces(date))
return OK;
days[1] = (atoi(date+4)%4) ? 28 : 29;
*(date + 4) = '\0';
mo = atoi(date+2);
*(date+2) = '\0';
if (mo && mo"13 && atoi(date) && atoi(date)"=days[mo-1])
return OK;
error_message("Invalid date");
return ERROR;
}
/*---------Процесс ввода данных в шаблон экрана-----------*/
int data_entry(WINDOW *wnd)
{
FIELD *fld;
int exitcode, isvalid, done=FALSE, oldhelpkey=helpkey;
field_tally(wnd);
fld = FHEAD;
/*--накопление данных, поступающих с клавиатуры на экране --*/
while (fld != NULL && done == FALSE) {
set_help(fld-"fhwin, fld-"flx, fld-"fly);
helpkey = (fld-"fhelp) ? 0 : oldhelpkey;
wcursor(wnd, fld-"fcol, fld-"frow);
if (fld-"fprot ==FALSE) {
reverse_video(wnd);
data_value(wnd, fld);
wcursor(wnd, fld-"fcol, fld-"frow);
exitcode = read_field(wnd, fld);
isvalid = (exitcode != ESC && fld-"fvalid) ?
(*(fld-"fvalid))(fld-"fbuff) : OK;
}
else {
exitcode = FWD;
isvalid = OK;
}
if (isvalid == OK) {
normal_vileo(wnd);
data_value(wnd, fld);
switch (exitcode) { /* передано редактору */
case F1: if (fld-"fhelp) {
(*(fld-"fhelp))(fld-"fbuff);
data_value(wnd, fld);
}
break;
case DN:
case '\r':
case '\t':
case FWD: fld = fld-"fnxt;
if (fld == NULL)
fld = FHEAD;
break;
case UP:
case BS: fld = fld-"fprv;
if (fld == NULL)
fld = FTAIL;
break;
default: done = endstroke(exitcode);
break;
}
}
}
helpkey = oldhelpkey;
return (exitcode);
}
/*-------- отображение приглашения к вводу---------*/
void wprompt(WINDOW *wnd, int x, int y, char *s)
{
wcursor(wnd, x, y);
wprintf(wnd, s);
}
Описание программы: entry.c
-----------------------------------------------------------------
Макроопределение FIELDCHAR программы entry.c идентифицирует
специальные символы, используемые в символьной маске поля при
определении байтов данных. По сути дела, идентифицированные с
помощью FIELDCHAR символы не являются символами в смысле данных,
так как используются в маске. В качестве значения FIELDCHAR
выступает символ нижнего подчеркивания. Вы можете изменить
определение FIELDCHAR, используя другие символы.
Привязка полей к окнам осуществляется с помощью двойного
связного списка. Список начинается и заканчивается в структуре
WINDOW для поля. Каждое поле представлено посредством структуры
FIELD, которая размещается в памяти при установке поля.
Функция init_template используется для инициализации окна с
шаблоном ввода данных. Она выполняет трассировку связного списка
FIELD и освобождает некоторые размещенные ранее в памяти
структуры FIELD.
Функция establish_field размещает в памяти и инициализирует
буфер FIELD, используя передаваемые ей при обращении значения или
принимая значения передаваемых переменных по умолчанию. Маска,
позиция размещения поля, адрес буфера и тип данных поля
передаются функции при обращении к ней. Очередная структура FIELD
добавляется в конец соответствующего связного списка FIELD,
специфицированного WINDOW. Указатель на очередную структуру FIELD
возвращается в точку вызова функции.
Функция addfield вызывается для добавления структуры FIELD к
связному списку, специфицированному WINDOW.
Функция disp_field используется для вывода значений данных,
введенных в поля, из буфера на экран дисплея. Маска данных,
передаваемая при обращении к функции, используется при
отображении содержимого поля. Обращение к функции содержит
WINDOW, указатель буфера поля и указатель маски. Подразумевается,
что курсор в окне всегда устанавливается на первую позицию
первого поля окна. Символы, хранящиеся в буфере, отображаются на
экране вместе с символами пунктуации, составляющими маску поля.
Функция data_value предназначается для отображения текущего
значения поля в окне. Функция устанавливает курсор в окне в
позицию первого символа поля и вызывает функцию disp_field,
передавая ей адрес WINDOW и адреса буфера поля и маски.
Функция field_fally используется для выдачи на экран
значений всех полей шаблона. Она осуществляет просмотр
"сверху-вниз" связного списка FIELD и осуществляет обращение к
функции data_value для каждого поля шаблона.
Функция field_window предназначена для установки оконной
help-информации для поля. Указанные при обращении к функции имя
help-информации и координаты экрана для ее выдачи копируются в
специфицированную при вызове функции структуру FIELD.
Функция clear_template обрабатывает "сверху-вниз" связной
список FIELD для специфицированного окна. Функция преобразует
буфер каждого поля шаблона в пустую строку, заканчивающуюся
нулевым символом, используя маску поля для определения
установленной при описании поля длины. Когда все поля обработаны
таким образом (почищены), функция обращается к field_fally.
Программа ввода данных работает в режимах вставки и замены
символов. Клавиша "ВСТ" ("Ins") используется для переключения
режимов работы программы, а переменная insert_mode служит для
индикации текущего режима работы. Функция
...Поділитися у соцмережах