Жанр: Учеба

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

сторінка №13

начиная со следующей
строки относительно строки текста, в которой обнаружен факт
завершения слова. Таким образом, эта процедура создает промежуток
между завершенным (законченным) словом и текстом следующей
строки. Функция lastword вызывается для анализа нового символа,
если он является символом, вводимым в последнее слово, или если
факт завершения очередного слова явился результатом вставки в
предыдущее слово строки. Эта проверка осуществляется программой в
случае изменения местоположения курсора после обнаружения конца
слова. Результат такой проверки запоминается в переменной svlw.
Координата X принимает значение конца строки текста. Если символ,
предшествующий последнему символу, отличен от пробела, то для
позиционирования курсора в начале следующего слова (и изменения
координаты X) используется функция back_word. Функция carrtn
вызывается для логической вставки новой строки в текущей
X-позиции. (На самом деле физической вставки строки
непосредственно в буфер не происходит в силу того, что буфер
представляет собой обычный двумерный массив прямоугольной формы.
Поэтому осуществляется лишь сдвиг текста и освобождение внутри
него пространства). Курсор позиционируется на символе, следующим
за символом, непосредственно добавленным в буфер. Функция
forward вызывается, не обращая внимания даже на факт окончания
слова, для коррекции координаты X.

Функция erase_buffer открывает окно и запрашивает у
пользователя разрешение на выполнение команды очистки (erase). По
соглашению пользователя функция очищает буфер и переопределяет
значения всех переменных и указателей.

Функция lastword проводит анализ координаты X расположения
курсора в последнем слове строки, определяемой координатой Y.

Функция last_char переопределяет координату Y расположения
курсора, присваивая ей значение на единицу больше, чем позиция
расположения последнего отображаемого символа в строке.

Функция test_para вызывается в случае необходимости
переформатирования параграфа для проверки возможности его
выполнения. Переключатель клавиатуры "Scroll Lock" должен
находиться в выключенном состоянии (off), и число завершающих
пробелов текущей строки текста должно быть больше длины первого
слова следующей строки текста. Если это условие выполняется,
функция test_para вызывает функцию paraform, которая позволяет
переформатировать параграф.

Функция trailing_spaces осуществляет подсчет завершающих
пробелов строки текста.

Функция first_woldlen подсчитывает длину первого слова
следующей строки текста.

Функция paraform осуществляет переформатирование параграфа,
если, естественно, предварительно параграф был отделен от
остального текста двумя пустыми строками. Функция paraform
вызывается в результате нажатия пользователем клавиши "F4" или в
результате работы функции test_para, осуществляющей
автоматическое принятие решения о возможности переформатирования
параграфа. Во всех этих случаях, если предварительно переменные
blkbeg и blkend не получили соответствующих значений для блока
текста, включающего текущий параграф, функция устанавливает
соответствующие значения этих переменных. Значение переменной
blkbeg устанавливается равным текущей строке текста. Функция
просматривает текст вперед, начиная с текущей строки, на предмет
наличия двух пустых строк (строк, целиком состоящих из пробелов)
или достижения конца буфера, устанавливая при этом значение
переменной blkend.

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


Функция blank_line используется в том случае, если
специфицированная строка целиком состоит из пробелов для анализа
строки.
Функция delete_word уничтожает слово в буфере. Если текущее
значение координаты месторасположения курсора X соответствует
пробелу, то функция уничтожает пробел, предшествующий следующему
слову; таким образом, функция уничтожает слово, начиная с
позиции, специфицированной кординатой X, но после
пробела, стоящего за предшествующим словом, до начала следующего
слова.

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

Функция delete_block реботает точно так же, как и функция
delete_line, однако оперирует с блоком текста, который содержит
более одной строки текста.

Функция mvblock используется для перемещения и копирования
блока текста. Вначале происходит размещение в памяти буфера для
хранения текста, и блок текста помещается в этот буфер. Если
операция перемещения блока текста предпочтительнее, чем его
копирование, то вызывается функция уничтожения блока текста
delete_block() в буфере редактора. Текст в буфере редактора
смещается вправо, начиная с текущей строки, освобождая место для
блока текста, который будет перемещен сюда или скопирован на это
место. Текст из промежуточного буфера перемещается на
освобожденное после сдвижки текста пространство. Промежуточный
буфер удаляется из памяти и восстанавливается изображение окна
после обращения к функции display_text.

Функции copy_block и move_block вызываются для копирования и
перемещения блока текста соответственно. Эти функции используют
mvblock для выполнения возложенных на них операций.

Функция findlast организует поиск последнего значащего
символа в буфере и устанавливает указатель lstptr на следующую
за ним позицию.

Функция carrtn отслеживает ситуацию возврата каретки при
окончании строки текста внутри буфера редактора вслед за
движением курсора пользователя. Она вычисляет адрес первого
символа следующей строки текста по текущей позиции символа, в
которой позиционирован курсор. Если включен режим "Вставка
символа", функция должна обеспечить "раздвигание" строки текста,
которое достигается смещением текста, находящегося в буфере
редактора, вправо, начиная с позиции, в которой расположен
курсор, к концу текущей строки и заполнения образовавшихся пустот
избыточными пробелами. Новая строка подвергается точно такому же
сдвигу и заполнению пробелами до минимальной ее длины после
операции вставки.

Функция downward используется для отслеживания изменения
координат следующей (возможно, новой) строки текста и, если
включен режим "Вставка", для переопределения значения указателя
lstptr.
Большинство функций, к которым осуществляется обращение,
используют прямо или косвенно координаты позиции расположения
курсора. Такими функциями являются find_end, backspace,
fore_word, spaceup, back_word, spacedn, forward, downward и
upward.
Пример: Использование редактора
-----------------------------------------------------------------

Листинги 9.2, 9.3 и 9.4 демонстрируют пример использования
оконного редактора текстов в диалоговой программе.

Листинг 9.2 содержит текст программы note.c, которая
является главной функцией, обращающейся к функции notepad.c,
исходный текст которой приведен в листинге 9.3. Функция notepad.c
выделена в отдельный файл в связи с тем, что она используется в
примерах меню (Глава 10) и при описании резидентных утилит (Глава
12).


Листинг 9.4 содержит пример make-файла Турбо Си, в
соответствии с которым строится пример использования оконного
редактора.

Функция notepad.c обрабатывает файл, имя которого определено
в массиве, описанном как external. В данном примере этот массив
определен в note.c, и имя файла указано как note.pad. Если такой
файл уже существует на момент запуска примера, то notepad.c
считывает его в буфер редактора.

Notepad.c устанавливает окно, заключает его в рамку,
присваивает окну название, назначает цвета для окна и отображает
его на экране дисплея. Затем notepad.c вызывает функцию оконного
редактора text_editor. По завершении работы функции text_editor
notepad.c уничтожает окно и сохраняет строки текста в буфере, в
который был записан последний нужный текст. Затем notepad.c
записывает содержимое буфера в файл (note.pad).

Листинг 9.2. note.c

/* ------ note.c ---------*/

#include "twindow.h"

void notepad(void);
char notefile [] = "note.pad";

main()
{
load_help("tcprogs.hlp");
notepad();
}

Листинг 9.3: notepad.c

/* ----------------- notepad.c -----------------*/

#include "stdio.h"
#include "mem.h"
#include "twindow.h"

#define LWID 60
#define WHT 10
#define PADHT 20

char bf [PADHT] [LWID];
extern char notefile[];

void notepad()
{
WINDOW *wnd;
FILE *fp, *fopen();
int i, ctr = 0;

set_help("notepad ",0,0);
setmem(bf, sizeof bf, ' ');
if ((fp = fopen(notefile, "rt")) != NULL) {
while (fread(bf [ctr], LWID, 1, fp))
ctr++;
fclose(fp);
}
wnd = establish_window
((80-(LWID+2))/2, (25-(WHT+2))/2, WHT+2, LWID+2);
set_border(wnd, 3);
set_title(wnd, " Note Pad ");
set_colors(wnd, ALL, BLUE, AQUA, BRIGHT);
set_colors(wnd, ACCENT, WHITE, BLACK, DIM);
display_window(wnd);
text_editor(wnd, bf[0], (unsigned) LWID * PADHT);
delete_window(wnd);
ctr = PADHT;
while (--ctr) {
for (i = 0; i " LWID; i++)
if( bf [ctr] [i] != ' ')
break;
if (i " LWID)
break;
}
fp = fopen(notefile, "w");
for (i = 0; i " ctr+1; i++)
fwrite(bf[i], LWID, 1, fp);
fclose(fp);
}

Листинг 9.4 note.prj

note
notepad(twindow.h)
editor(twindow.h, keys.h)
thelp(twindow.h, keys.h)
twindow(twindow.h, keys.h)
ibmpc.obj

Для выполнения примера введите команду

C " note

После трансляции и редактирования ваших программ вы увидите
на экране дисплея копию рисунка 9.2. При первом запуске примера
файл note.pad будет пустым. После того, как вы введете с помощью
редактора какую-либо информацию, при выходе из редактора по
клавише "ESC" или "F2" данные будут запомнены в файле note.pad
для дальнейшего использования. Естественно, что если вы запомнили
текст, то при следующем выполнении программы он будет вам
отображаться в окне редактора.

----------------------------------------------------------------¬
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ----------------- Note Pad --------------¬ ¦
¦ ¦The window notepad can be used to record ¦ ¦
¦ ¦random thoughts, appointments, reminders,¦ ¦
¦ ¦and daily activities._ ¦ ¦
¦ ¦ ¦ ¦
¦ ¦ ¦ ¦
¦ ¦ ¦ ¦
¦ L------------------------------------------ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
L----------------------------------------------------------------

Рис. 9.2 Пример использования редактора.

При вводе текста и его дальнейшей обработке используйте
перечень команд, отображенный на рисунке 9.1. Нажав клавишу "F1",
вы можете получить перечень этих команд на экране своего дисплея.

Резюме
-----------------------------------------------------------------

Итак, мы рассмотрели еще одну дополнительную возможность,
которая может быть добавлена в список библиотеки поддержки
оконной технологии. Таким образом, изученное вами на настоящий
момент программное обеспечение может использоваться как
функциональное средство поддержки специализированных задач,
ориентированных на использование оконной технологии. Программное
обеспечение позволяет организовать диалоговую help-поддержку,
шаблоны ввода данных, а также использовать оконный текстовый
редактор. Следующей дополнительной возможностью, которая может
вами с успехом применяться, является иерархическая система меню,
используемых в окне. Эта система меню включает в себя скользящее
меню-строку и систему появляющихся меню типа "pop-down" (этот тип
меню еще называют "всплывающим", так как его появление на экране
очень напоминает эффект всплытия из "глубины" дисплея) для выбора
и выполнения различных функций прикладной программой, в которой
система меню используется.

ГЛАВА 10


--------

Оконные меню
-----------------------------------------------------------------

Итак, сейчас вы уже можете адресовать область
пользовательского интерфейса интерактивной системы,
ссответствующую определенным операциям. Для ввода различных полей
данных - это средства поддержки формо-ориентированного ввода; для
ввода текста - это оконный текстовый редактор; для обеспечения
пользователей help-информацией по этим операциям - это контекстно
-зависимая help-система; для поддержки каждой из этих операций -
библиотека функций окна. Ранее мы с вами рассмотрели примеры
адресации области пользовательского интерфейса для случая, когда
прикладная программа использует только одну из операций. Однако
диалоговые системы обычно обеспечивают поддержку целого ряда
операций, которые может инициализировать пользователь. Выбор
конкретной операции, которую необходимо выполнить в данный
момент, чаще осуществляется пользователем интерактивной системы,
чем самой системой. Это связано с тем, что зачастую требуется
выбор из группы сложных независимых операций, а пользователь
всегда лучше знает, какая именно операция должна быть выполнена в
данный момент.

Меню
-----------------------------------------------------------------

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

Вы уже встречались с одним из видов меню в Главе 6 при
рассмотрении программы poetry.exe. Это меню содержало список
опций окна. Пользователь мог осуществлять выбор из этого меню
путем нажатия клавиш, соответствующих одной из опций меню, или
путем перемещения курсора по элементам меню и нажатия клавиши
"ВВОД" в позиции соответствующего элемента. Такой тип меню
является наиболее часто используемым в интерактивных системах, но
в то же время относится к разряду наиболее эффективных и
понимаемых пользователем приемов.

Другим популярным типом меню, который часто используется в
компьютерах, снабженных графическим пользовательским интерфейсом
и манипулятором типа "мышь", является меню в виде скользящей
строки (sliding bar menu). Этот тип меню представляет собой
горизонтальное меню, расположенное в верхней части, с
"всплывающими" вертикальными меню, раскрывающими и
конкретизирующими содержание выбранных из горизонтального меню
элементов. Вертикальные меню "всплывают" под соответствующими
элементами горизонтального меню, и после этого пользователь
получает возможность осуществлять выборку из вертикального меню,
перемещаясь по нему вверх и вниз. Примером такого меню может
служить система меню, принятая во Framework-II - широко
распространенном продукте фирмы Ashton Tate .

К преимуществам такого типа меню относится то, что оно
занимает минимальную область экрана (обычно - одна строка) и
наиболее полно отражает взгляд пользователя на конкретное
приложение программы. Вертикальные меню реализованы в виде
"всплывающих" окон. Вследствие того, что они лишь временно
перекрывают изображение на экране, не уничтожая его, применение
такого меню раскрывает новые перспективы в разработке диалоговых
систем. На рисунке 10.1 представлен пример именно такого меню.
Пользователи системы Borland's Superkey могут видоизменить это
меню.

---------------------------------------------------------------¬
¦-------------------------------------------------------------¬¦
¦¦ Macros Commands Functions Options Defaults Encryption ¦¦
¦L----------------------------T-------------------------T------¦
¦ ¦ Arrow keys OFF ¦ ¦
¦ ¦ Bottom line OFF ¦ ¦
¦ ¦ Command stack ON ¦ ¦
¦ ¦ Format fields OFF ¦ ¦
¦ ¦ Keyb. click OFF ¦ ¦
¦ ¦ One finger OFF ¦ ¦
¦ ¦ Playback delay 0 ¦ ¦
¦ ¦ proTect delay OFF ¦ ¦
¦ ¦ sUspend OFF ¦ ¦
¦ ¦ disk Wait OFF ¦ ¦
¦ ¦ Save optoins ¦ ¦
¦ L-------------------------- ¦
¦ ¦
¦ ¦
L---------------------------------------------------------------

Рис. 10.1 Пример меню

Процесс, образующий оконное меню
-----------------------------------------------------------------

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

Основной таблицей меню является массив MENU-структур.
Структура MENU определена в twindow.h (см. Главу 6). Этот массив
является входным для каждого процесса выборки из скользящей менюстроки.
Каждый ввод выбранного элемента меню содержит
отображаемое пользователю имя элемента меню и ряд указателей,
описывающих содержание "всплывающего" вертикального меню,
соответствующего указанному пользователю элементу горизонтального
меню. Эти указатели включают в себя указатель на массив имен
элементов "всплывающего" меню и указатель на массив указателей
функций на языке Си. Имена отображаются во "всплывающем" меню, а
функции входят в состав системы, использующей это меню, и
выполняются, когда пользователь отмечает в качестве выбранных
соответствующие имена элементов меню.
Иерархическая система меню состоит из двух уровней. Первый
уровень включает в себя выборку из горизонтального меню и
ограничен лишь шестью элементами вследствие того, что элементы
этого уровня располагаются на одной строке. Любая выборка
элемента на этом уровне приводит к появлению соответствующего
"всплывающего" меню на втором уровне. Размер "всплывающего" меню
ограничен 21 элементами, что соответствует максимальному числу
строк, которое может быть включено в "всплывающее" меню. Каждая
выборка на этом уровне приводит к вызову определенной Си-функции
из закрепленных за элементами меню.

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

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

Функции поддержки меню
-----------------------------------------------------------------

Для использования оконных меню в этой главе вы должны
вначале сгенерировать массив MENU, затем массив, на который
ссылается массив MENU, а также написать и оттранслировать
прикладные функции, которые будут выполняться, когда пользователь
выберет конкретный элемент "всплывающего" меню. Затем вы так или
иначе обращаетесь к функции menu_select, которая описана ниже.

void menu_select(char *name, Menu *mn)

Эта функция активизирует меню-процесс, отображая на экране
дисплея горизонтальное скользящее меню-строку и переходя в
состояние ожидания использования пользователем клавиатуры для
выборки из меню. Указатель name является именем заголовка
скользящей меню-строки. Указатель mn содержит адрес массива
структур MENU в вызывающей программе. Этот массив и указатель на
массив MENU определяют иерархию меню для меню-процесса.


После того, как функция menu_select отобразила
горизонтальное меню, пользователь, используя клавиши управления
курсором вправо и влево, может перемещаться по меню. Если
пользователь нажал клавишу "КЛЮЧ" ("ESC"), то меню-процесс
прерывается, и управление передается в точку вызова функции menu_
select. Если же пользователь нажал клавишу "ВВОД" ("ENTER"), то
осуществляется привязка конкретного "всплывающего" вертикального
меню к текущему элементу горизонтального меню (определяется
текущим положением маркера меню или курсора) и отображение
нужного вертикального меню.

Во время отображения вертикального "всплывающего" меню
пользователь может использовать клавиши передвижения курсора
вправо и влево для выбора других элементов горизонтального
меню-строки. В этом режиме в соответствии с движением курсора в
меню-строке осуществляется последовательное отображение
вертикальных меню, причем перед отображением очередного
вертикального меню предыдущее вертикальное меню уничтожается.
Если пользователь нажмет клавишу "КЛЮЧ" ("ESC"), то текущее
"всплывающее" меню уничтожается, и процесс возвращается к
обработке скользящего меню-строки аналогично описанному выше.
Пользователь может использовать клавиши перемещения курсора вверх
и вниз для навигации по вертикальному меню и выбора нужного
элемента меню. После того, как нужный элемент выбран, нужно
нажать клавишу "ВВОД" ("ENTER"). Нажатие этой клавиши приведет к
исчезновению как вертикального, так и горизонтального меню и
вызову функции, соответствующей указателю, хранимому в массиве
указателей функций "всплывающего"меню и, в свою очередь,
соответствующего выбранному элементу меню. Выполнение функций
осуществляется путем обычного обращения к ним.

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

Исходный листинг: tmenu.c
-----------------------------------------------------------------

Листинг 10.1 содержит текст библиотечной функции tmenu.c,
предназначенной для поддержки предварительного описания
меню-про

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

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

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

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

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