ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 3

          Функция  display_window оперирует  по-разному для стековых и
     слоеных окон.  В  любом случае  она ничего  не  делает, если окно
     является видимым для пользователя.   Если окно невидимо, то путем
     вызова  функции  vswap    display_window   замещает   видеопамять
     буфером сохранения,  если действуют  слоеные  окна.  Для стековых
     окон делается проверка,  не скрыто ли окно.  Если окно скрыто, то
     оконный  буфер  сохранения  записывается  в  видеопамять  вызовом
     vrstr.  Если окно не скрыто, то оно никогда не выдается,  поэтому
     вызывается   vsave   для   сохранения    текущего     содержимого
     видеопамяти,    a   clear_window  и  wframe вызываются для выдачи
     пустого окна.

          Функция  close_all  уничтожает  все  окна  путем прохода  по
     списку структур WINDOW и вызова delete_window.

          Функция  delete_window  удаляет  окно  из  системы путем его
     скрытия,   освобождения   памяти,   занятой  буфером  сохранения,
     удаления  структуры  WINDOW  из  списка  и  освобождения  памяти,
     содержащей структуру WINDOW.

          Функция hide_window  вызывает  vswap   для   замены   буфера
     сохранения  видеопамятью  для  слоеного  окна  и вызова vrstr для
     восстановления видеопамяти для стекового окна.

          Функция  repos_window  имеется только  для слоеных окон. Она
     вызывается   одним   из   макросов   move_window,   rmove_window,
     rear_window  и  forefront.  Она  изменяет  положение  окна  путем
     создания  временного  окна,  помещая  временное окно  в  список в
     соответствии  с  информацией,  полученной  из  макроса, записывая
     оригинальное содержимое окна в буфер  сохранения временного окна,
     выдавая временное окно и скрывая оригинал.

          Crear_window записывает  пробелы  в  область  данных окна, а
     wframe и dtitle изображают окно с заголовком наверху. Эти функции
     используют функцию displ для записи значений в окно.

          Функция  wprintf  является  примером  нового предполагаемого
     стандарта ANSI  для функций  с  переменным  числом  параметров. В
     прошлом   большинство   компиляторов   обрабатывали   printf   на

                             - 2 -
     ассемблере для  просмотра переменного числа параметров  из стека.
     Предполагаемый  стандарт  использует  многоточие  (...)  в списке
     параметров функции для указания  присутствия    переменного числа
     параметров с различными  типами  данных.  Специальный тип массива
     va_list   используется   для   объявления   списка,   а  va_start
     устанавливает  начало  и конец списка.  Функция vsprintf является
     версией  sprintf,  которая допускает параметр  va_list.  В данном
     случае       параметры,        передаваемые       в      wprintf,
     перерабатываются vsprintf в  строку с именем dlin.   Затем строка
     выдается в окно по одному  символу за раз  путем вызова wputchar.
     Если у вас получится вызов   wprintf,   который  образует  строку
     более  100  символов, придется увеличить длину массива dlin.

          Функция wputchar  выдает  символ  в  окно  в текущей позиции
     курсора.  Расположение оконного  курсора  является  функцией двух
     элементов  структуры WINDOW,  которые указываются макросами WCURS
     (столбец)   и SCROLL  (строка).   Функция  реагирует   на символы
     новой строки (\n)  и табуляции (\t)  следующим образом. Для новой
     строки,   если   переменная  SCROLL   соответствует   низу  окна,
     содержимое   окна  проворачивается   вверх  на одну строку; иначе
     значение переменной SCROLL    увеличивается.   В   любом   случае
     переменная    WCURS  устанавливается   на   столбец  0.   Если  в
     wputchar     послан   символ    табуляции,     переменная   WCURS
     продвигается  к  следующей позиции табуляции  в  окне.  Остальные
     символы   отображаются  в  окне, а переменная  WCURS  возрастает.
     Строки,   длина   которых превышает ширину  окна, не переносятся;
     они обрезаются.

          Функция wcursor устанавливает переменные  WCURS  и SCROLL на
     координаты,   заданные  при   вызове.   Она  также  устанавливает
     видеокурсор   на  экранную   позицию,   соответствующую  оконному
     курсору.

          Функция get_selection  создает  блок  курсора   в   окне   и
     позволяет  пользователю  перемещать  блок  вверх и вниз,  а также
     производить  выбор  нажатием  клавиши  <Ввод>.   Макроопределение
     SELECT  ссылается на переменную в структуре WINDOW и используется

                             - 3 -
     для перемещения блока курсора в окне.  Функции accent и  deaccent
     используются  для  включения  и  выключения  блока  курсора путем
     изменения видеоатрибута строки на ACCENT и  NORMAL.  При  нажатии
     верхней  и  нижней  клавиш со стрелками функция изменяет значение
     переменной SELECT.  При вызове можно также передать адрес массива
     символов,  содержащего список клавиш,  используемых для выбора из
     окна.  Если  пользователь   нажимает   одну   из   этих   клавиш,
     производится  соответствующий  выбор  так  же,  как  если бы блок
     курсора находился в соответствующей строке и была  нажата клавиша
     <Ввод>.

          Функция scroll проворачивает порцию текста в  окне вверх или
     вниз  на  одну  строку.  Если окно является последним  и видимым,
     функция прокрутки ROM-BIOS применяется для ускорения по сравнению
     с программной прокруткой.  Функция ROM-BIOS не  применяется, если
     окно  имеет только  одну  строку текста из-за ошибки  в IBM  PC и
     некоторых моделях  АТ.  Эта  ошибка  вызывает  появление неверных
     видеорезультатов  при  попытке  провернуть  единственную  строку.
     Ошибка была устранена IBM в АТ  BIOS,  но в некоторых моделях она
     осталась. Если окно не является последним или если оно имеет одну
     строку  текста,  текстовая  область проворачивается  программно с
     помощью функций dget и displ для чтения и записи  символов текста
     из окна и в окно.

          Функция  waddr  оперирует  только  со  слоеными  окнами. Она
     возвращает целочисленный адрес позиции  в  окне,  где расположены
     символ и атрибут. Если окно не видимо, функция возвращает адрес в
     буфере сохранения, вычисленный  по  координатам x и y.  Если окно
     видимо,  сканируется список  для поиска окон,  более поздних, чем
     адресуемое  окно.  Если  более  позднее  окно  закрывает  позицию
     адресуемого   символа,    возвращается   адрес,   соответствующий
     сохраненному адресу этого окна.  Если ни одно  более позднее окно
     не закрывает позицию  символа,  возвращается  указатель  NULL для
     сообщения в точку вызова об использовании видеопамяти.

          Функция displ и функция dget вызываются для  выдачи и приема
     видеосимвола и  атрибута  в   и  из  слоеного  окна.  Эти функции

                             - 4 -
     вызывают waddr   для проверки  необходимости чтения  или записи в
     область сохранения. Если нет, адресуется видеопамять.

          Функция  wsvap меняет  местами  содержимое буфера сохранения
     слоеного  окна  и видеопамяти или,  возможно,  буферов сохранения
     более  поздних  окон,  которые  закрывают  адресуемое  окно.  Эта
     функция использует displ и dget для выполнения изменения.

          Функции  vsave и vrstr работают  со  стековыми окнами. Vsave
     копирует  содержимое  видеопамяти  в  буфер  сохранения,  а vrstr
     копирует буфер сохранения в видеопамять.

          Функция  acline вызывается  макросами  accent и deaccent для
     изменения выбранной строки  окна на цветовую  конфигурацию ACCENT
     или NORMAL.

          Функция add_list  добавляет структуру WINDOW в конец списка.

          Функция beg_list добавляет структуру WINDOW в начало списка.

          Функция remove_list удаляет структуру WINDOW из списка.

          Функция iusert_list  вставляет  структуру  WINDOW  в  список
     после другой заданной структуры WINDOW.

          Функция verify_wnd  ищет  в списке  заданный адрес структуры
     WINDOW.  Она возвращает истину или ложь в  зависимости от наличия
     или отсутствия структуры WINDOW в списке. Если заданный указатель
     WINDOW равен  NULL,  функция возвращает адрес последней структуры
     WINDOW в списке.

          Функция  error_message создает окно  для выдачи специального
     сообщения  об  ошибке.  Сообщение  записывается  в  окно  вызовом
     wprintf, и включается звуковой сигнал.

          Функция clear_message очищает последнее сообщение об ошибке.


                             - 5 -



                      Примеры окон
     -----------------------------------------------------------------

          Далее рассматриваются   возможности   оконной    библиотеки.
     Приводятся  примеры  программ,  каждая  из  которых  иллюстрирует
     рассматриваемые  возможности.  Примеры   состоят   из   небольшой
     управляющей   программы  с  главной  функцией,  которая  вызывает
     функцию примера для демонстрируемой возможности.  Функция примера
     содержит вызовы ранее рассмотренных библиотечных функций и служит
     иллюстрацией их использования.  Каждый пример программы  включает
     проектный  (.prj)  файл,  используемый  Турбо  Си  для построения
     выполняемой программы.

          Затем эти же самые примеры функций  будут  объединены в один
     выполняемый модуль,  который демонстрирует  оконные меню. Поэтому
     они написаны без собственных main-функций.


                           Перемещение  окна
                           -----------------

          При использовании  слоеных  окон   вам   доступны   функции,
     позволяющие   перемещать  окно  в  абсолютную  или  относительную
     позицию на экране. Заметим, что эти функции - move_window и rmove
     _window - недоступны для стековых окон.

          Программа, иллюстрирующая  перемещение  окна,  приведена  на
     листингах  6.3,  6.4  и  6.5.  Листинг  6.3  является   маленькой
     управляющей программой, а листинг 6.5 представляет проектный make
     -файл. Обращайтесь к листингу 6.4, testmove.c, при чтении данного
     описания.

          Для запуска примера введите следующую команду:


                             - 6 -
     c>move

          (В этом   и   последующих  примерах  предполагается,  что  С
     является вашим системным дисководом. Не вводите подсказку с>.).

          Помимо иллюстрации  движения  окна,  testmove.c   показывает
     также процесс создания окон, установку их цветов, выдачу на экран
     и запись текста в них.  Программа создает три  окна,  присваивает
     каждому  из них собственные цвета,  выдает их и записывает цитату
     во второе из трех  окон.  Этот  пример  иллюстрирует  возможность
     записи  текста  в  окно,  которое  частично закрыто другим окном.
     После запуска программы вы увидите на дисплее то, что показано на
     рисунке 6.4.

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і                                                              і
     і  C>                                                          і
     і                                                              і
     і              ЪДДДДДДДДДДДДДДДДДДДДДДї                        і
     і       ЪДДДДДДі I wouldn't care who  і                        і
     і       і      і wrote the laws if I  і                        і
     і       і      і could write the      і                        і
     і       і      і b ЪДДДДДДДДДї        і                        і
     і       і      і   і         іferson  і                        і
     і       і      АДДДі         ГДДДДДДДДЩ                        і
     і       і          і         і                                 і
     і       АДДДДДДДДДДґ         і                                 і
     і                  АДДДДДДДДДЩ                                 і
     і                                                              і
     і                                                              і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Рисунок 6.4. Перемещение слоеных окон.


          Теперь программа   ожидает   нажатия   клавиши.    Программа
     специально  ждет  нажатия одной из клавиш управления курсором или

                             - 7 -
     клавиши <Ключ>.  Каждое  нажатие  клавиши  со  стрелкой  вызывает
     перемещение   окна  на  одну  символьную  позицию  в  направлении
     стрелки.  Функция rmove_window используется для перемещения окна.
     Обратите внимание на то,  как центральное окно перемещается между
     двумя остальными.

          Когда вы нажимаете  клавишу  <Ключ>,  открытое  первым  окно
     уничтожается.  Еще  одно  нажатие  вызывает  уничтожение верхнего
     окна.  Заключительное нажатие уничтожает среднее окно с цитатой и
     завершает программу.

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


     Листинг 6.3: move.c

     /* move.c */

     void testmove(void);

     main()
     {
        testmove();
     }


     Листинг 6.4: testmove.c

     /* testmove.c */

     #include "twindow.h "

                             - 8 -
     #include "keys.h"

     void testmove()
     {
        WINDOW *wndA, *wndB, *wndC;
        int c;

        wndA = establish_window(5, 5, 9, 19);
        wndB = establish_window(10, 3, 9, 23);
        wndC = establish_window(13, 8, 9, 12);
        set_colors(wndA, ALL, RED,  YELLOW, BRIGHT);
        set_colors(wndB, ALL, AQUA, YELLOW, BRIGHT);
        set_colors(wndC, ALL, WHITE, YELLOW, BRIGHT);
        display_window(wndA);
        displey_window(wndB);
        display_window(wndC);
        wprintf(wndB, "\n I wouldn't care who");
        wprintf(wndB, "\n wrote the laws if I");
        wprintf(wndB, "\n could write the");
        wprintf(wndB, "\n ballads.");
        wprintf(wndB, "\n\n    Thomas Jefferson");
        do  {
            int x = 0, y = 0;
            c = get_char();
            switch (c)  {
                case FWD:   x++;
                            break;
                case BS:    --x;
                            break;
                case UP:    --y;
                            break;
                case DN:    y++;
                default:    break;
            }
            if (x || y)
                rmove_window(wndB, x, y);
        } while (c != ESC);

                             - 9 -
          delete_window(wndA);
          get_char();
          delete_window(wndC);
          get_char();
          delete_window(wndB);
     }



     Листинг 6.5: move.prj

     move
     testmove (twindow.h, keys.h)
     twindow (twindow.h, keys.h)
     ibmpc.obj



                        Подъем и опускание окон
                        -----------------------

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

          Программа, иллюстрирующая   подъемы   и   опускания    окон,
     приведена  в  листингах  6.6,  6.7  и  6.8.  Листинг 6.6 является
     маленькой управляющей программой, а листинг 6.8 - проектным make-
     файлом.  Обращайтесь к листингу 6.7, promote.c, при чтении данных
     разъяснений.

          Для запуска примера введите следующую команду:

                             - 10 -

     c>prom

          Программа promote.c использует те же образцы трех  окон, что
     и программа testmove.c. Теперь все три окна включают записанный в
     них текст,  каждый из которых содержит имя окна: window A, window
     B  и  window  C.  На  рисунке  6.5 показан первоначально выданный
     экран.

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і                                                               і
     і  C>                                                           і
     і                                                               і
     і             ЪДДДДДДДДДДДДДДДДДДДї                             і
     і             і  window B         і                             і
     і       ЪДДДДДґ                   і                             і
     і       і     і    ЪДДДДДДДДДДї   і                             і
     і       і win і    і          і   і                             і
     і       і     і    і          і   і                             і
     і       і     АДДДДґ window C ГДДДЩ                             і
     і       і          і          і                                 і
     і       АДДДДДДДДДДґ          і                                 і
     і                  АДДДДДДДДДДЩ                                 і
     і                                                               і
     і                                                               і
     і                                                               і
     і                                                               і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

              Рисунок 6.5. Подъем слоеных окон.

          Для подъема  и  опускания  окон   используется   клавиатура.
     Используйте  нажатия  клавиш  с  маленькими буквами а,  b и с для
     подъема окон,  названных этими  буквами.  Используйте  клавиши  с
     большими  буквами для их опускания.  Этот процесс продолжается до
     тех пор, пока вы не нажмете клавишу <Ключ> для уничтожения одного
     из окон. Еще два нажатия вызовут уничтожение остальных двух окон,

                             - 11 -
     и программа завершится.

     Листинг 6.6: prom.c

     /* prom.c */

     void promote(void);

     main()
     {
        promote();
     }

     Листинг 6.7: promote.c

     /* promote.c */

     #include "twindow.h"
     #include "keys.h"

     void promote()
     {
         WINDOW *wndA, *wndB, *wndC;
         int c;
         wndA = establish_window(5, 5, 9, 19);
         wndB = establish_window(10, 3, 9, 20);
         wndC = establish_window(13, 8, 9, 12);
         set_colors(wndA, ALL, RED, YELLOW, BRIGHT);
         set_colors(wndB, ALL, AQUA, YELLOW, BRIGHT);
         set_colors(wndC, ALL, WHITE, YELLOW, BRIGHT);
         display_window(wndA);
         display_window(wndB);
         display_window(wndC);
         wprintf(wndA, "\n\n Window A");
         wprintf(wndB, "\n\n Window B");
         wprintf(wndC, "\n\n Window C");
         do  {

                             - 12 -
             c = get_char();
             switch (c)  {
                 case 'a':   forefront(wndA);
                             break;
                 case 'b':   forefront(wndB);
                             break;
                 case 'c':   forefront(wndC);
                             break;
                 case 'A':   rear_window(wndA);
                             break;
                 case 'B':   rear_window(wndB);
                             break;
                 case 'C':   rear_window(wndC);
                             break;
                 default:    break;
         }
     } while (c != ESC);
          delete_window(wndA);
          get_char();
          delete_window(wndC);
          get_char();
          delete_window(wndB);
     }




     Листинг 6.8: prom.prj

     prom
     promote (twindow.h, keys.h)
     twindow (twindow.h, keys.h)
     ibmpc.obj



           Назначение заголовков и изменение цветов окна

                             - 13 -
           ---------------------------------------------

          Когда окно  создано,  вы  можете  назначить ему заголовок, а
     также установить цвета переднего плана и фона.

          Программа, иллюстрирующая заголовки и цвета  окон, приведена
     в листингах  6.9,  6.10  и  6.11.  Листинг 6.9 является маленькой
     управляющей  программой,  а листинг 6.11 - проектным make-файлом.
     Обращайтесь  к  листингу 6.10,  ccolor.c,   при   чтении   данных
     разъяснений.

          Для запуска примера вводите следующую команду

     c>color

          Снова выдается три окна. Каждое из них имеет свой цвет (если
     у вас цветной монитор), но ни у одного из них нет заголовка. Окна
     расположены  в  тех  же  местах  и  имеют те же размеры,  что и в
     предыдущих примерах. Программа ожидает нажатия клавиши с одной из
     букв:  r, g или b. Она будет использовать эти буквы для изменения
     заголовка среднего окна на "RED",  "GREEN" или  "BLUE",  а  также
     изменит  цвет  среднего окна на соответствующий новому заголовку.
     Рисунок 6.6 показывает экран после выбора алого (red) окна.

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і                                                               і
     і   C>                                                          і
     і                                                               і
     і                                                               і
     і                                                               і
     і               ЪДДДДДДДREDДДДДДДДї                             і
     і               і                 і                             і
     і          ЪДДДДґ                 і                             і
     і          і    і                 і                             і
     і          і    і   ЪДДДДДДДДДї   і                             і
     і          і    і   і         і   і                             і
     і          і    АДДДґ         ГДДДЩ                             і

                             - 14 -
     і          і        і         і                                 і
     і          АДДДДДДДДґ         і                                 і
     і                   АДДДДДДДДДЩ                                 і
     і                                                               і
     і                                                               і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

               Рисунок 6.6. Изменение цветов и заголовков.


          Нажмите клавишу  <Ключ>  для  выхода  и уничтожения окна,  а
     также любые две другие клавиши  для  уничтожения  двух  остальных
     окон и завершения программы.

     Листинг 6.9: color.c

     /* color.c */

     void ccolor(void);

     main()
     {
        ccolor();
     }

     Листинг 6.10: сcolor.c

     /* ccolor.c */

     #include "twindow.h"
     #include "keys.h"

     void ccolor()
     {
        WINDOW *wndA, *wndB, *wndC;
        int c;


                             - 15 -
        wndA = establish_window(8, 8, 9, 19);
        wndB = establish_window(13, 6, 9, 20);
        wndC = establish_window(16, 11, 9, 12);
        set_colors(wndA, ALL, RED, YELLOW, BRIGHT);
        set_colors(wndB, ALL, AQUA, YELLOW, BRIGHT);
        set_colors(wndC, ALL, WHITE, YELLOW, BRIGHT);
        display_window(wndA);
        display_window(wndB);
        display_window(wndC);
        do  {
            c = get_char();
            switch (c)  {
                case 'r':
                    set_title(wndB, " RED ");
                    set_colors(wndB, ALL, RED, WHITE, BRIGHT);
                    break;
                case 'b':
                    set_title(wndB, " BLUE ");
                    set_colors(wndB, ALL, BLUE, WHITE, BRIGHT);
                    break;
                case 'g':
                    set_title(wndB, " GREEN ");
                    set_colors(wndB, ALL, GREEN, WHITE, BRIGHT);
                    break;
                default:
                    break;
             }
          } while (c != ESC);
          delete_window(wndA);
          get_char();
          delete_window(wndC);
          get_char();
          delete_window(wndB);
     }




                             - 16 -

     Листинг 6.11: color.prj

     color
     ccolor (twindow.h, keys.h)
     twindow (twindow.h, keys.h)
     ibmpc.obj




                Сравнение стековых и слоеных окон
                ---------------------------------

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

          Программа, иллюстрирующая   различия   между   стековыми   и
     слоеными окнами, показана на листингах 6.12, 6.13 и 6.14. Листинг
     6.12 является маленькой управляющей программой,  а листинг 6.14 -
     проектным make-файлом.  Обращайтесь к листингу 6.13,  fast.c, при
     чтении данных разъяснений.

          Для запуска примера введите следующую команду:

     c>fast

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

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

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і ЪДДДДДДДДДДДДДДї                                              і
     і і ЪДДДДДДДДДДДДДДДї                                           і
     і і і ЪДДДДДДДДДДДДДДДї                                         і
     і і і і ЪДДДДДДДДДДДДДДДї                                       і
     і АДі і і ЪДДДДДДДДДДДДДДДї                                     і
     і   АДі і і ЪДДДДДДДДДДДДДДДї                                   і
     і     АДі і і ЪДДДДДДДДДДДДДДДї                                 і
     і       АДі і і ЪДДДДДДДДДДДДДДДї                               і
     і         АДі і і ЪДДДДДДДДДДДДДДДДї                            і
     і           АДі і і ЪДДДДДДДДДДДДДДДДДї                         і
     і             АДі і і ЪДДДДДДДДДДДДДДДДДДї                      і
     і               АДі і і ЪДДДДДДДДДДДДДДДДДДДї                   і
     і                 АДі і і ЪДДДДДДДДДДДДДДДДДДДї                 і
     і                   АДі і і ЪДДДДДДДДДДДДДДДДДДДї               і
     і                     АДі і і ЪДДДДДДДДДДДДДДДДДДДї             і
     і                       АДі і і                   і             і
     і                         АДі і Hello, Dolly # 14 і             і
     і                           АДі                   і             і
     і                             АДДДДДДДДДДДДДДДДДДДЩ             і
     і                                                               і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                Рисунок 6.7. Сравнение стековых и слоеных окон.


     Листинг 6.12: fast.c

     /* fast.c */

     void fasttest(void);

     main()
     {

                             - 18 -
         fasttest();
     }


     Листинг 6.13: fasttest.c

     /* fasttest.c */

     #include 
     #include "twindow.h"

     void fasttest()
     {
        int row, col;

        for (row = 0, col = 0; col < 15; row += 3, col++)   {
            establish_window(row, col, 10, 30);
            set_colors(NULL, ALL, RED, YELLOW, BRIGHT);
            display_window(NULL);
            wprintf(NULL, "\n\n\n  Hello, Dolly # %d", col);
        }
        get_char();
        while (col--)
            delete_window(NULL);
     }



     Листинг 6.14: fast.prj

     fast
     fasttest (twindow.h)
     twindow (twindow.h, keys.h)
     ibm.obj




                             - 19 -


     Перемещение, подъем, скрытие окон, меню, изменение интенсивности
     ----------------------------------------------------------------

          В следующем  примере  комбинируется несколько уже показанных
     возможностей   и   даются   примеры   еще   двух    возможностей:
     использование   get_selection   для  обработки  простого  меню  и
     использование set_intensity для изменения яркости переднего плана
     окон.

          Программа, иллюстрирующая  эти возможности,  представлена на
     листингах 6.15,  6.16 и 6.17.  Листинг  6.15  является  маленькой
     управляющей  программой,  а листинг 6.17 - проектным make-файлом.
     Обращайтесь  к  листингу  6.16,  poems.c,   при   чтении   данных
     разъяснений.

          Для запуска примера введите следующую команду:

     c>poetry

          Эта программа выдает пять различных стихотворений на экран и
     позволяет вам выбрать одно из них, перемещать его, поднять его на
     передний   план,  опустить  его  назад  и  уничтожить.  Программа
     начинает работу с выдачи оконного меню,  которое перечисляет  все
     стихотворения.  Вы  можете  переместить  курсор  вверх или вниз и
     выбрать одно стихотворение  нажатием  клавиши  <Ввод>.  Вы  также
     можете   нажать   одну   из   цифр  от  1  до  5,  выбирая  номер
     стихотворения.   В   результате    будет    показано    выбранное
     стихотворение. На рисунке 6.8 показано меню стихотворений.

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і                                                               і
     і   ЪДДДДДДДДДДДДДДДДДД Select A PoemДДДДДДДДДДДДї              і
     і   і                                            і              і
     і   і 1: TELL ALL THE TRUTH BUT TELL IT SLANT    і              і
     і   і 2: AFTER LONG SILENSE                      і              і

                             - 20 -
     і   і 3: A MAN SAID TO THE UNIVERSE              і              і
     і   і 4: FLYING CROOKED                          і              і
     і   і 5: THE IDLE LIFE I LEAD                    і              і
     і   і                                            і              і
     і   АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ              і
     і                                                               і
     і                                                               і
     і                                                               і
     і                                                               і
     і                                                               і
     і                                                               і
     і                                                               і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                    Рисунок 6.8. Меню стихотворений.


          После выбора  стихотворения  вы   можете   передвинуть   его
     клавишами  со  стрелками,  возвращаясь  к  меню  нажатием клавиши
     <Ключ> или выбирая другое стихотворение  нажатием соответствующей
     цифровой  клавиши.  Выбранное  текущее  стихотворение  выдается с
     повышенной яркостью,  а  все  остальные  -  с  обычной.  Если  вы
     выбираете  стихотворение,  выданное  с  обычной яркостью,  то оно
     становится  ярким,  а  остальные   -   обычными.   Для   перевода
     стихотворения  на  передний план нажмите клавишу <Плюс> (+);  для
     посылки его на фон нажмите клавишу <Минус> (-).  Для  уничтожения
     текущего   стихотворения   нажмите   клавишу   <Удл>.  Вы  можете
     восстановить его нажатием клавиши с номером.  После этого нажмите
     клавишу <Ключ> для возврата к меню,  а затем снова клавишу <Ключ>
     для выхода из программы.

          На рисунке  6.9  показаны  стихотворения,  разбросанные   по
     экрану в различных местах.

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД...
     і                          Ъ 1: TELL ALL THE TRUTH BUT TELL IT...
     і  C>                      і

                             - 21 -
     і                          і Tell all the truth but tell it sl...
     і                          і
     і ЪДДДДДДДДД 2: AFTER LONG SILENCE ДДДДДДДДДїt lies
     і і                                         іr infirm Delight
     і іSpeesh after long silense; it is right,  іb surprise
     і іAll other lovers being estranged or dead і ЪДДД 5: THE IDLE...
     і іUnfriendly lamplight hid under its shade,іhі
     і іThe curtaiЪДДДДДДДД 4: FLYING CROOKED ДДДД іThe idle life I...
     і іThat we deі                                іIs like a pleas...
     і іUpon the sіThe butterfly, a cabbare-white, іWherein I rest ...
     і іBodily decі(His honest idiocy of flight)   іThe dreams that...
     і іWe loved eіWill never now, it is too late, і
     і і          іMaster the art of flying straighіAnd still of al...
     і і          іYet has - who knows so well as IіIn turt so swif...
     і АДЪД3: A MAN SAID TO THE UNIVERSEДДДї o fly:іEach in its fan...
     і   і                                 і by gueіA nobler than t...
     і   іA man said to the universe:      іlessnesі
     і   і"Sur, I exist!"                  і       іAnd every eve I...
     і   і"However," replied the uviverse, іd gift іNoting my step ...
     і   і"The fast has not created in me  іes     іThat I have kvo...
     і   іA sense of obligation."          і       іIn all my life ...
     і   і               Stephen Crane     ГДДДДДДДґ         Robert...
     і   і                                 і       і
     і   АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ       АДДДДДДДДДДДДДДД...
     і
     і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                     Рисунок 6.9. Стихотворения.


     Листинг 6.15: poetry.c

     /* poetry.c */

     #include "twindow.h"
     void poems(void);

                             - 22 -

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

     Листинг 6.16: poems.c

     /* poems.c */

     #include 
     #include 
     #include 
     #include "twindow.h"
     #include "keys.h"

     /* локальные прототипы */
     void get_poem(int s);
     int ht (char **tb);
     int wd (char **tb);
     char *titles [] = {
         " 1: TELL ALL THE TRUTH BUT TELL IT SLANT ",
         " 2: AFTER LONG SILENSE ",
         " 3: A MAN SAID TO THE UNIVERSE ",
         " 4: FLYING CROOKED ",
         " 5: THE IDLE LIFE I LEAD ",0
     };
     WINDOW *pno [] = {0, 0, 0, 0, 0};
     static int x [] = {20, 15, 29, 10, 17};
     static int y [] = {5,10, 13, 18, 6};
     static int wcl [] [2] = {  {BLUE, WHITE},
                                {MAGENTA, WHITE},
                                {RED, WHITE},
                                {GREEN, WHITE},
                                {AQUA, WHITE}   };
     char *poem1 [] = {

                             - 23 -
         "Tell all the truth but tell it slant -",
         "Success in Circuit lies",
         "Too bright for our infirm Delight",
         "The Truth's superb surprise",
         "",
         "As Lightning to the Children eased",
         "With explanation kind",
         "The Truth must dazzle gradually",
         "Or every man be blind -",
         "                Emily Dickenson",
         0
     };
     char *poem2 [] = {
         "Speech after long silence; it is right,",
         "All other lovers being estranged or dead,",
         "Unfriendly lamplight hid under its shade,",
         "The curtains drawn upon unfriendly night,",
         "That we descant and yet again descant",
         "Upon the supreme theme of Art and Song:",
         "Bodily decrepitude is wisdom; young",
         "We loved each other and were ignorant.",
         "              William Butler Yeats",
         0
     };

     char *poem3 [] = {
         "A man said to the universe:",
         "\"Sir, I exist!\"",
         "\"However,\" replied the universe,",
         "\"The fast has not created in me",
         "A sense of obligation.\"",
         "               Stephen Crane",
         0
     };

     char *poem4 [] = {
         "The butterfly, a cabbage-white,",

                             - 24 -
         "(His honest idiocy of flight)",
         "Will never now, it is too late,",
         "Master the art of flying straight,",
         "Yet has - who knows so well as I? -",
         "A just sense of how not to fly:",
         "He lurches here and there by guess",
         "And God and hope and hopelessness.",
         "Even the aerobatic swift",
         "Has not his flyihg-crooked gift.",
         "              Robert Graves",
         0
     };

     char *poem5 [] = {
         "The idle life I lead",
         "Is like a pleasant sleep,",
         "Wherein I rest and heed",
         "The dreams that by me sweep.",
         "",
         "And still of all my dreams",
         "In turn so swiftly past,",
         "Each in its fancy seems,",
         "A nobler than the last.",
         "",
         "And every eve I say,",
         "Noting my step in bliss,",
         "That I have known no  day",
         "In all my life like this.",
         "         Robert Bridges",
         0
     };
     char **poem [] = {poem1,poem2,poem3,poem4,poem5,0};

     void poems()
     {
         int s = 0, i, c;
         WINDOW *mn;

                             - 25 -
         char **cp;

         cursor(0, 25);
         mn = establish_window(0, 0, 7, 45);
         set_title(mn, " Select A Poem ");
         set_colors(mn, ALL, BLUE, GREEN, BRIGHT);
         set_colors(mn, ACCENT, GREEN, WHITE, BRIGHT);
         display_window(mn);
         cp = titles;
         while (*cp)
             wprintf(mn, "\n%s", *cp++);
         while (1)   {
             set_help("poemmenu", 40, 10);
             s = get_selection(mn, s+1, "12345");
             if (s == 0)
                 break;
             if (s == FWD || s == BS)       {
                 s = 0;
                 continue;
             }
             hide_window(mn);
             get_poem(--s);
             c = 0;
             set_help("poems   ", 5, 15);
             while (c != ESC)    {
                 c = get_char();
                 switch (c)  {
                     case FWD:   rmove_window(pno[s], 1, 0);
                                 break;
                     case BS:    rmove_window(pno[s], -1,0);
                                 break;
                     case UP:    rmove_window(pno[s], 0, -1);
                                 break;
                     case DN:    rmove_window(pno[s], 0, 1);
                                 break;
                     case DEL:   delete_window(pno[s]);
                                 pno[s] = NULL;

                             - 26 -
                                 break;
                     case '+':   forefront(pno[s]);
                                 break;
                     case '-':   rear_window(pno[s]);
                     default:    break;
                 }
                 if (c > '0' && c < '6')
                     get_poem(s = c - '1');
              }
              forefront(mn);
              display_window(mn);
          }
          close_all();
          for (i = 0; i < 5; i++)
              pno[i] = NULL;
     }

     /* активизирует стихотворение по номеру */
     static void get_poem(int s)
     {
         char **cp;
         static int lastp = -1;
         if (lastp != -1)
             set_intensity(pno[lastp], DIM);
         lastp = s;
         if (pno [s])
             set_intensity(pno[s], BRIGHT);
         else    {
             pno [s] = establish_window
                 (x[s], y[s], ht(poem[s]), wd(poem[s]));
             set_title(pno[s], titles[s]);
             set_colors(pno[s],ALL,wcl[s][0],wcl[s][1], BRIGHT);
             set_border(pno[s], 1);
             display_window(pno[s]);
             cp = poem[s];
             while (*cp)
                 wprintf(pno[s], "\n %s", *cp++);

                             - 27 -
         }
     }
     /* вычисляет высоту показываемой таблицы окна */
     static int ht(char **tb)
     {
         int h = 0;
         while (*(tb + h++)) ;
         return h + 3;
     }
     /* вычисляет ширину показываемой таблицы окна */
     static int wd(char **tb)
     {
         int w = 0;
         while (*tb)     {
             w = max(w, strlen(*tb));
             tb++;
         }
         return w + 4;
     }




     Листинг 6.17: poetry.prj

     poetry
     poems (twindow.h, keys.h)
     thelp (twindow.h, keys.h)
     twindow (twindow.h, keys.h)
     ibmpc.obj

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


                             - 28 -



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

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



                                ГЛАВА 7
                                -------


                  Контекстно-управляемые окна подсказки
     -----------------------------------------------------------------

          Первой проблемой,   обычно  возникающей  при  запуске  новой
     программы,  является  незнакомство  программы  с  языком   своего
     пользователя.  Какая  клавиша должна быть нажата?  Какое действие
     будет следующим? Что выполняет данный элемент меню? Независимо от
     того,   сколько  усилий  вложено  в  разработку  самообъясняемого
     пользовательского  языка,  у   пользователей   всегда   возникают
     вопросы,   поскольку   язык   новой   системы   для  него  всегда
     иностранный.  Дело не только в знакомстве пользователей с языком,
     часто  они  даже  не  знают,  что система может,  а чего не может
     делать.  По традиции эта проблема решается обращением к  печатным
     руководствам   пользователя   и,   возможно,   автоматизированным

                             - 29 -
     справочникам.  Недостатком этих  решений  является  необходимость
     переключения  внимания пользователя от работы с системой к чтению
     руководства или запуску справочника.

          Если бы экраны были достаточно большими,  система  могла  бы
     поддерживать   постоянный  показ  руководства  пользователя.  Как
     только пользователю потребовалась бы информация, руководство было
     бы   доступно.  Это  решение  не  продержалось  бы  долго;  когда
     пользователь уже знает систему,  информация подсказки не нужна  и
     нежелательна.  Значимая  для  новичка  информация - это мусор для
     ветерана.

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

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

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

          Разработчик системы  решает,  как  много   и   какого   вида
     подсказки   система   будет   предусматривать  для  пользователя.
     Некоторые  системы  обладают  несколькими  уровнями  подсказки  в
     зависимости от опыта пользователя.  Программа обработки слов Word
     Star применяла эту технологию на протяжении  многих  лет.  Уровни
     подсказки  изменяются  от  простых сообщений типа "нажмите <Ключ>
     для возврата к..." до полных пользовательских  руководств. Многие
     разработчики   программ   предпочитают   передавать   руководство
     пользователя таким способом,  а  не  в  виде  больших  громоздких
     документов.  Эта  процедура  имеет два последствия:  пользователи
     связывают экстравагантные руководства  с  качеством  программ,  а
     большие книги способствуют борьбе с "программными пиратами".

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



              Программирование окон подсказки
     -----------------------------------------------------------------

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

          Программа,  использующая  программное обеспечение подсказки,
     должна   предусматривать   следующие   интерфейсы   с   функциями
     подсказки:
         - функциональный  вызов  для  задания  имени текстового файла
     подсказки;
         - значение функциональной клавиши подсказки;
         - функциональные  вызовы  для  идентификации   текущего  окна
     подсказки;
         - использование  функции  клавиатурного  ввода  get_char  для
     любого ввода с клавиатуры (get_char описана в Главе 4).

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

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

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

          Требуемое использование get_char лишает вас трех стандартных
     возможностей Си:

         - вы не сможете использовать стандартные библиотечные функции
     scanf  или  getchar,   поскольку  ни  одна  из  этих  функций  не
     использует функцию get_char;

         - вы не сможете воспользоваться стандартной функцией ввода  с
     консоли (getch), предусмотренной в Турбо Си;

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

          Потеря  функций scanf и getchar -  это  небольшая потеря для

                             - 33 -
     программирования диалога.  Эти функции бесполезны в интерактивной
     среде.  Они являются функциями буферизованного  ввода, требующими
     нажатия клавиши <Ввод>  для завершения ввода символа  или строки;
     кроме  того,  они нечувствительны к расположению курсора  и длине
     поля.  Эти  функции  дублируют  свой  ввод  в  стандартный вывод,
     соблюдая  соглашения  командной    строки   ДОС,   и   они  будут
     дублировать  изображения двойных символов  при вводе управляющего
     символа.  Если введена клавишная комбинация  Упр/С, функции могут
     аварийно   завершить   программу.   Функции   плохо   работают  с
     функциональными  или курсорными  клавишами.  Турбо Си включает их
     для  поддержки совместимости с UNIX.   Эти функции  происходят из
     компьютерных систем с телетайпными терминалами.

          Может  показаться,  что  вы  теряете ряд возможностей, когда
     лишаетесь устройства  stdin,  однако это устройство предназначено
     для программ, которые могут принимать входные данные из файлов и
     выходов других программ так же, как и с клавиатуры. Эти программы
     (или, по крайней мере, stdin используется для ввода данных в них)
     обычно не предназначены для использования в интерактивной среде.


                 Текстовый файл окна подсказки
     -----------------------------------------------------------------

          Окна подсказки  появляются,  когда   пользователь   нажимает
     функциональную  клавишу  подсказки,  описанную в текстовом файле.
     Текстовый файл подсказки - это  ASCII-файл,  который  вы  строите
     текстовым  редактором  Турбо  Си  или  любым  другим  редактором,
     который может создавать ASCII-файлы.

          Окна  подсказки  описываются  мнемоническим идентификатором,
     который  используется  программным  обеспечением   подсказки  для
     идентификации  и   расположения  текста.   Строки,  следующие  за
     идентификатором,  содержат текст, количество строк и длина строки
     которого  определяют высоту и ширину  окна  подсказки. На рисунке
     7.1  показан  небольшой  файл  подсказки,  описывающий  два  окна
     подсказки.

                             - 34 -

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і                                                               і
     і                                                               і
     і                                                               і
     і                                                     і
     і                    Enter the name of the                      і
     і                    employee as last name,                     і
     і                    comma, first name, viddle                  і
     і                    initial. Example:                          і
     і                    Hart, William S                            і
     і                                                     і
     і                    Enter the employee number                  і
     і                    with from I to life digits.                і
     і                    Example: 12345                             і
     і                                                          і
     і                                                               і
     і                                                               і
     і                                                               і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

               Рис. 7.1. Пример файла подсказки

          Идентификатор окна  подсказки  состоит   ровно   из   восьми
     символов и окружается угловыми скобками,  как показано на рисунке
     7.1.  Каждый идентификатор появляется в своей собственной строке,
     последней строкой файла должен быть лексический вход.  На рисунке
     7.2 приведены два окна  подсказки,  которые  будут  отображены  в
     результате этих описаний.

     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
     і                                                               і
     і      ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДї                           і
     і      і Enter the name of the      і                           і
     і      і employee as last name,     і                           і
     і      і comma, first name, middle, і                           і
     і      і initial. Example:          і                           і

                             - 35 -
     і      і Hart, William S            і                           і
     і      і  [Help] to return          і                           і
     і      АДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ                           і
     і                                                               і
     і                                                               і
     і                      ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї          і
     і                      і Enter the employee number   і          і
     і                      і with from 1 to five digits. і          і
     і                      і Example: 12345              і          і
     і                      і  [Help] to return           і          і
     і                      АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ          і
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

               Рис. 7.2. Примеры окон подсказки

          Все примеры   программ,   которые   приводятся   в   этой  и
     последующих главах, используют программное обеспечение подсказки.
     Далее   рассматривается  простой  пример  для  иллюстрации  самой
     подсказки,  а  затем  -  использование   подсказки   по   прямому
     назначению   -   для  предоставления  пользователю  интерактивной
     контекстно-управляемой подсказки. С этой целью один и тот же файл
     подсказки  предусматривается  для  всех  программ.  Он называется
     tcprogs.hlp и показан на листинге 7.1.

     Листинг 7.1: tcprogs.hlp

     
      Press 1, 2, or 3
      for a pithy maxim.
     
      Use arrow keys to move the cursor bars.
      Use Enter to make the selection.
     
      Arrows move the cursor bar.
      Enter will select the poem
      under the cursor bar.
      Press a digit (1-5) to

                             - 36 -
      select any other poem.
     
      Move poem with arrow keys
      Select poem with 1 - 5
      Use + to bring poem forward
      Use - to push poem back
     
      Enter the name of the person
      who is placing the order.
     
Enter the address of the person who is placing the order. The State may be one of these: VA, NC, SC, GA, FL Enter the phone number of the person who is placing the order Enter the amount of the order --------Cursor Movement----- --------Page Movement-------- arrows = move text cursor Ctrl-Home = Beginning of File Ctrl-T = Top of Window Ctrl-End = End of File Ctrl-B = Bottom of Window PgUp = Previous Page Ctrl -> = Next Word PgDn = Next Page Ctrl <- = Previous Word Home = Beginning of Line --------Editor Control------- End = End of Line Scroll Lock = No Auto Reform --------Block Controls----- ---------Edit Commands-------- F4 = Form Paragraph F2 or Esc = Done F5 = Mark Block Beginning F3 = Erase File F6 = Mark Block End Ins = Toggle Insert Mode - 37 - F7 = Move Block Del = Delete Char F8 = Copy Block <-- = Rubout F9 = Delete Block Ctrl-D = Delete Word F10 = Unmark Block Alt-D = Delete Line Функции подсказки ----------------------------------------------------------------- Для введения контекстно-управляемых окон подсказки в ваши программы необходимо к ним добавить два вызова функций, которые находятся в исходном файле thelp.c, представленном ниже в листинге 7.2. void load_help(char *filename) Вызовите эту функцию для загрузки файла подсказки или перехода к другому файлу подсказки. Функция открывает файл подсказки и анализирует в нем сообщения подсказки, строя таблицу идентификаторов окон подсказки, их размеров и расположений в файле подсказки. void set_help(char *helpname, int x, int y) Эта функция задает текущее окно подсказки с восьмисимвольным массивом, соответствующим наименованию окна в файле подсказки. Наименование окружается в файле подсказки угловыми скобками, причем не включает в себя эти скобки. Целые числа х и y задают координаты верхнего левого угла (в символьных позициях) окна подсказки, что позволяет пользователям использовать одно и то же окно в различных контекстах, но в различных листах экрана. - 38 - Изменение функциональной клавиши подсказки ----------------------------------------------------------------- Если вам нужно задать значение функциональной клавиши, отличной от (по умолчанию), вы должны изменить значение глобальной целочисленной переменной helpkey. Эта переменная объявлена в ibmpc.c в Главе 4. Вы можете включить исходный файл keys.h (см. Главу 4) в вашу программу и использовать одно из определенных в этом файле значений клавиш. Следующий фрагмент изменяет функциональную клавишу подсказки на . #include "keys.h" extern int helpkey; helpkey = F2; Изменение функции подсказки ----------------------------------------------------------------- Файл с именем ibmpc.c в Главе 4 включает указатель на функцию с именем helpfunc. Обычно этот указатель содержит значение NULL. Когда используются функции подсказки, указатель инициализируется адресом функции с именем help. Если вам нужно использовать другую функцию, скажем, вместо стандартной функции help, вы можете изменить значение указателя helpfunc. Для применения функциональной клавиши подсказки для вызова вашей функции используйте следующие операторы: extern void (*helpfunc)(); void yourfunc(); helpfunc = yourfunc; Вы можете вернуться к указанию helpfunc на стандартную функцию подсказки с помощью следующих операторов: extern void (*helpfunc)(); - 39 - extern void help(); helpfunc = help; Выключение подсказки ----------------------------------------------------------------- Имеются три пути для выключения подсказки: вы можете установить значение функциональной клавиши подсказки равным 0; можно установить указатель функции подсказки равным NULL; можно вызвать set_help, передавая указатель на строку нулевой длины. Для включения подсказки необходимо отменить выбранное действие. Исходный листинг: thelp.c ----------------------------------------------------------------- Теперь перейдем к листингу 7.2 thelp.c. Этот файл является исходным текстом функций, поддерживающих контекстно-управляемые окна подсказки. Листинг 7.2: thelp.c /*---------------------thelp.c------------------*/ #include #include #include #include "twindow.h" #include "keys.h" #define MAXHELPS 25 #define HBG WHITE #define HFG BLACK #define HINT DIM - 40 - #define TRUE 1 #define FALSE 0 static struct helps { char hname [9]; int h, w; long hptr; } hps [MAXHELPS+1]; static int hp = 0; static int ch = 0; static int hx, hy; FILE *helpfp = NULL; long ftell(); char *fgets(); void help(); char helpname[64]; void getline(char *lineh); /*--------------загружает файл определения HELP!-------------*/ void load_help(char *hn) { extern void (*helpfunc)(); extern int helpkey; char lineh [80]; if (strcmp(helpname, hn) == 0) return; helpfunc = help; helpkey = F1; hp = 0; strcpy(helpname, hn); if ((helpfp = fopen(helpname, "r")) == NULL) return; getline(lineh); while (1) { - 41 - if (hp == MAXHELPS) break; if (strncmp(lineh, "", 5) == 0) break; if (*lineh != '<') continue; hps[hp].h = 3; hps[hp].w =18; strncpy(hps[hp].hname, lineh+1, 8); hps[hp].hptr = ftell(helpfp); getline(lineh); while (*lineh != '<') { hps[hp].h++; hps[hp].w = max(hps[hp].w, strlen(lineh)+2); getline(lineh); } hp++; } } /*--------получает строку текста из файла подсказки---------*/ static void getline(char *lineh) { if (fgets(lineh, 80, helpfp) == NULL) strcpy(lineh, ""); } /*-----устанавливает текущий активный экран подсказки--------*/ void set_help(char *s, int x, int y) { for (ch = 0; ch < hp; ch++) if (strncmp(s, hps[ch].hname, 8) == 0) break; hx = x; hy = y; } /*-------------выдает текущее окно подсказки-----------------*/ void help() - 42 - { char ln [80]; int i, xx, yy; WINDOW *wnd; extern int helpkey; if (hp && ch != hp) { curr_cursor(&xx, &yy); cursor(0, 25); wnd = establish_window(hx, hy, hps[ch].h, hps[ch].w); set_colors(wnd, ALL, HBG, HFG, HINT); display_window(wnd); fseek(helpfp, hps[ch].hptr, 0); for (i = 0; i < hps[ch].h-3; i++) { getline(ln); wprintf(wnd, ln); } wprintf(wnd, "[Help] to return"); while (get_char() != helpkey) putchar(BELL); delete_window(wnd); cursor(xx, yy); } } Описание программы: thelp.c ----------------------------------------------------------------- Программа thelp.c содержит четыре имени #define, устанавливающих глобальные параметры системы подсказки. MAXHELPS получает значение максимального количества окон подсказки, которое программа может поддерживать одновременно. HBG, HFG и HINT являются цветами фона, переднего плана и яркостью окон подсказки. Структура helps описывает окно подсказки. Она содержит мнемоническое имя окна, его высоту и ширину, а также символьное - 43 - смещение описания окна в текстовом файле, включающем окна подсказки. Массив hps структур helps содержит один элемент для каждого окна в текстовом файле и строится функцией load_help. Функция load_help читает текстовый файл подсказки, заданный при вызове, и строит массив hps. Она распознает угловую скобку, идентифицирующую каждое имя окна, копируя имя и символьное смещение в файле в структуру. Затем она читает текст окна для определения длины и ширины окна. Длина яляется функцией количества строк текста, а ширина является функцией размера самой длинной строки текста окна. Функция set_help просматривает массив для поиска окна с именем, заданным при вызове. Целочисленная переменная ch, которая используется для индексации в массиве при поиске, будет содержать индекс текущего окна при нажатии функциональной клавиши подсказки. Переменные hx и hy получают значения при вызове. Эта процедура устанавливает позицию окна. Функция help вызывается функцией get_char из ibmpc.c при нажатии заданной функциональной клавиши подсказки. Функция help сохраняет текущую позицию курсора и убирает курсор с экрана. Создается окно подсказки с координатами и размерами, записанными в элементе массива с индексом ch. Текущая символьная позиция в текстовом файле перемещается к месту, указанному в элементе массива. Каждая строка текста читается из файла и записывается в окно. Дописывается последняя строка, сообщающая пользователю о необходимости повторного нажатия клавиши подсказки для очистки окна подсказки и возврата. Программа ожидает нажатия клавиши подсказки, уничтожает окно и восстанавливает курсор на экране в прежнем положении. Пример контекстно-управляемой подсказки ----------------------------------------------------------------- Программы на листингах 7.3, 7.4 и 7.5 представляют пример использования программного обеспечения подсказки. Листинг 7.3, - 44 - sayings.c, содержит главную функцию, вызывающую функцию примера, maxims.c, показанную в листинге 7.4. Листинг 7.5 является проектным make-файлом, используемым Турбо Си для построения этого примера. Для запуска программы вводите следующую команду: c>sayings Программа sayings.c загружает файл teprogs.hlp с помощью вызова load_help и вызывает функцию с именем maxims. Такая последовательность была выбрана для того, чтобы maxims.c могла быть встроена в последующие программы, предусматривающие примеры обработки меню и резидентных в памяти утилит. Maxims.c показывает, как использовать set_help и get_char в ваших программах. Используется только одно окно подсказки. Maxims.c открывает окно и ожидает нажатия клавиши. Если вы нажимаете 1, 2 или 3, в окне показывается одна из трех старых пословиц. На рисунке 7.3 изображено окно с одной из таких выданных пословиц. Если вы нажмете <Ключ>, программа завершится. Если будет нажата , выдается окно подсказки, как показано на рисунке 7.4. ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї і і і C> і і і і і і і і і і ЪДДДДДДДДДДДДДДДДPress F1 for helpДДДДДДДДДДДДДДДДї і і і A rolling stone gathers no moss і і і АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ і і і і і і і і і і і - 45 - і і АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Рис. 7.3. Выданная пословица ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї і і і C> і і і і і і і і і і ЪДДДДДДДДДДДДДДДДPress F1 for helpДДДДДДДДВДДДДДДДДДДДДДДДДДДїі і і A rolling stone gathers no moss іPress 1, 2 or 3 іі і АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґfor a pithy maxim.іі і і[Help] to return іі і АДДДДДДДДДДДДДДДДДДЩі і і і і і і і і і і і і АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Рис. 7.4. Подсказка для пословиц Листинг 7.3: sayings.c /*--------------sayings.c--------------*/ #include "twindow.h" void maxims(void); main() - 46 - { load_help("tcprogs.hlp"); maxims(); } Листинг 7.4: maxims.c /*--------------------maxims.c-----------------*/ #include "twindow.h" #include "keys.h" void maxims() { int c; WINDOW *wnd; set_help("maxims ", 50, 10); wnd = establish_window(5, 10, 3, 50); set_title(wnd, "Press F1 for help"); set_colors(wnd, ALL, RED, WHITE, DIM); display_window(wnd); while ((c = get_char()) != ESC) { switch (c) { case '1': wprintf(wnd, "\nA stitch in time \ saves nine "); break; case '2': wprintf(wnd, "\nA rolling stone \ gathers no moss"); break; case '3': wprintf(wnd, "\nA penny saved \ is a penny earned"); break; - 47 - default: break; } } delete_window(wnd); } Листинг 7.5: sayings.prj saying maxims (twindow.h, keys.h) thelp (twindow.h, keys.h) twindow (twindow.h, keys.h) ibmpc.obj Резюме ----------------------------------------------------------------- Ваши оконные средства теперь включают возможность контекстно -управляемой подсказки. Следующие главы содержат дополнительные возможности обработки окон и примеры их использования. Каждый пример использует окна контекстно-управляемой подсказки, поэтому ваше понимание средств подсказки возрастает с каждой добавленной возможностью. Это обучение имеет существенное значение, поскольку, как правило, диалоговые программы должны предусматривать оперативную подсказку пользователю. Следующее дополнение к использованию окон в диалоговой программе представлено в Главе 8, которая описывает использование окон в качестве форм для ввода данных. Глава 8 включает функции, позволяющие вам описывать содержимое и формат шаблона ввода данных, и описывает программное обеспечение для сбора элементов данных, вводимых пользователем в форму. - 48 - ГЛАВА 8 ------- Иcпользование данных в окнах ----------------------------------------------------------------- Интерактивные программы интерпретируют значения данных внутри компьютера в соответствии с типами данных, определенными пользователем. Эти значения данных могут интерпретироваться по-разному, поэтому программы могут использовать разнообразные технические приемы для интерпретации значений вводимых данных. Например, текстовый процессор интерпретирует данные, поступающие на его вход, как текст произвольной формы. Электронный бланк интерпретирует данные в соответствии с совокупностью форматов строки и столбца, в которой в данный момент находится курсор. Однако одни и те же данные каждая программа "видит и чувствует" по-разному. Поэтому даже правильное копирование входного потока одной программы на вход другой может привести к массе спорных результатов, которые в этом случае выдает вторая программа. Многие интерактивные программы воспринимают значения данных непосредственно в той форме, в которой пользователь осуществляет их физический ввод (например, данные в печатной форме (бланк)). Каждая, сходная с печатной, форма представления данных определялась Государственной налоговой службой. Формо- ориентированные интерактивные программы интерпретируют программы как лист бумаги, содержащий поля со значениями данных и текст, описывающий значение каждого поля. После того, как пользователь введет значение данного в соответствующие позиции поля, программное обеспечение проверяет допустимость введенного значения и дальнейшее управление курсором. В этой главе формо-ориентированный ввод данных, указание доступа к ним и контроль операций над ними реализован путем использования окна как шаблона для ввода данных. Шаблон ввода данных включает в себя окно вместе с описанием вводимых в каждое поле данных и именами - 49 - полей ввода данных. Шаблон ввода данных ----------------------------------------------------------------- Перед вводом данных в окно вы должны прежде всего открыть окно, задать атрибуты шаблона ввода данных, соответствующие описанию данных в прикладной программе, обрабатывающей их, а также описать расположение полей ввода данных и присвоить им имена. После того, как шаблон готов, вы можете вызвать функцию ввода данных, которая осуществит управление чтением всех элементов данных с шаблона. По завершению работы функции, когда все значения элементов данных размещаются в указанном вами буфере, производится проверка на их допустимость, преобразование по указанным форматам и считывание в некоторой последовательности для обработки вашей прикладной программой. Поле ввода данных ----------------------------------------------------------------- Поле ввода данных, по сути дела, представляет собой элемент данных. Оно может быть датой, результатом вычисления суммы чего-либо, именем или вычисленной средней заработной платой. Поле ввода данных имеет следующие характеристики: оно имеет определенную длину и формат и должно занимать одну строку окна. Поле ввода данных - традиционный элемент систем управления базами данных (СУБД). После того, как вы описали поля шаблона, вы должны специфицировать позицию размещения поля в шаблоне, атрибуты, выходной буфер, функцию проверки допустимости данных, help-информацию и маску вводимых данных для каждого поля. Эти компоненты описания полей рассматриваются ниже. - 50 - Позиция ------------------------------------------------------------------ Позиция поля задается выражением, состоящим из номера строки и столбца символьных координат, соответствующих местоположению текста в шаблоне окна. Предпочтительнее задавать координаты позиции поля относительно координат окна, а не экрана; если вы вдруг решите изменить координаты расположения самого окна, то в случае описания позиции поля в координатах окна описание позиции поля вам изменять не придется. Атрибуты ------------------------------------------------------------------ Атрибут поля позволяет описать вводимые в него данные как имеющие один из существующих типов данных. Тип данных задается отдельной буквой (которые рассмотрены в данной главе). Однако уже сейчас вам необходимо знать, что вы можете специфицировать поле как поле даты, спецификации, денежной единицы или как числовое. Задание атрибута поля позволяет контролировать, каким способом будут интерпретированы значения данных в поле. Буфер ----------------------------------------------------------------- Для каждого поля назначается выходной буфер данных, который является адресом символьного массива, в котором будет происходить накопление данных. Ваша программа резервирует память под этот буфер и передает его адрес данным внутри прикладной программы. - 51 - Проверка допустимости значений ----------------------------------------------------------------- Ваша программа генерирует адрес функции проверки допустимости вводимых значений так, как будто сама эта функция используется. Программное обеспечение ввода данных будет вызывать эту функцию всегда после того, как вы ввели данное в поле. Следует заметить, что при вводе данных программное обеспечение само осуществляет автоматическую проверку некоторых основных ограничений в соответствии с атрибутами поля, однако, используя дополнительные подпрограммы проверки значений, вы можете существенно расширить и усложнить проверку данных по различным критериям. Help-информация ----------------------------------------------------------------- Вы можете специфицировать вспомогательное help-окно (которое описано в Главе 7) для каждого поля, а также help-функцию для каждого поля, которая будет вам выдавать справочную информацию о предназначении каждого поля в случае, если постоянный текст, описывающий поле и отображаемый в окне, не удовлетворяет вашему любопытству. Help-окно получает информацию из специального help-файла, в связи с чем включение help-функций в программу обязательно. При желании вы можете не специфицировать свои help-функции, а использовать стандартные help-функции пакета, которые могут быть вызваны пользователем путем нажатия на соответствующую help-клавишу. Следует помнить, что использование соответствующей help-спецификации эффективно лишь в процессе ввода пользователем данных в поле, для которого эта help-информация предназначена. - 52 - Маска вводимых данных ----------------------------------------------------------------- Когда вы определяете поле для ввода данных, вы можете задать маску для всех вводимых в это поле значений. Эта маска специфицируется в массиве символов, включающем в себя символы нижнего подчеркивания и пунктуации. Символ нижнего подчеркивания соответствует позиции маски, в которой возможен ввод данных, а пунктуация служит для обозначения других (различных) отображаемых символов кода ASCII. Длина элементов данных описывается количеством символов нижнего подчеркивания, а длина буфера, выделяемого под вводимые данные, описываемые маской, должна быть не меньше, чем длина элемента данных плюс 1. Символы пунктуации в буфер не перекачиваются. Например, маска вводимых данных, касающихся номера телефона (включая код местности и расширение) может иметь следующий вид: char phone_mask [] = "(____)____-____ ext:_____";


Яндекс цитирования