Жанр: Учеба

Техника программирования на турбо-С

сторінка №10

ая
выдается, начиная с координат окна, задаваемых значениями х и у.

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 служит для
индикации текущего режима работы. Функция

Список сторінок

Поділитися у соцмережах

☏ Замовлення реклами: +3805044-68-872

© Асоціація електронних бібліотек України

☝ Усі матеріали сайту (зокрема статті, зображення, рекламні оголошення тощо) призначені лише для попереднього ознайомлення. Усі права на публікації, представлені на сайті, належать їхнім законним власникам. Просимо Вас не зберігати копії інформації.