Работа в конструкторе диалогов.

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

В этом разделе описывается работа со встренным конструктором диалогов (экранным дизайнером) HomeLisp. Последовательность действий по созданию визуального интерфейса в HomeLisp довольно схожа с работой в таких системах, как Visual Basic, VBA или Deplphi. Разумеется, возможности и событийная модель HomeLisp, описанная здесь, заметно скромнее, чем у перечисленных выше профессиональных систем разработки. Тем не менее, даже эти скромные возможности вполне позволяют создать простой графический интерфейс для программ, написанных на HomeLisp.

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

Надпись;

Поле ввода;

Простой список;

Выпадающий список;

Командная кнопка;

Радиокнопка;

Галочка.

Событийная модель HomeLisp очень проста: с каждым элементом управления связан один тип событий. С полем ввода (TextBox) связано событие KeyPressed, заключающееся в том, что пользователь ввел в поле ввода символ. С остальными элементами управления связано событие Click (щелчок мыши). Процедура-обработчик события для поля ввода получает, как параметр, ASCII-код клавиши, нажатой пользователем. Обработчики события Click не получают параметров.

В экранном дизайнере диалог может быть "нарисован" мышью (при минимальном участии клавиатуры). Дизайнер также генерирует заглушки процедур-обработчиков событий для каждого из элементов управления. Содержательную часть кода процедур-обработчиков событий должен написать человек.

Сверстанный диалог можно сохранить в текстовом файле с расширением ".dlg" (и впоследствии восстановить с целью продолжения работы). Полностью готовый диалог следует "протранслировать" в Лисп-код, после чего диалог готов для выполнения.

Для того, чтобы из среды разработки вызвать дизайнер, пользователь должен активизировать четвертую кнопку панели инструментов:


или пункт главного меню "Диалоги". Окно экранного дизайнера выглядит так:


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

Опишем органы управления дизайнером чуть подробнее. Командная панель (тулбар) дизайнер имеет вид:


Кнопки командной панели (перечисленные слева направо) предназначены для:

Загрузить диалог сохраненный ранее в файле .dlg;

Сохранить диалог в файле формата .dlg;

Вырезать выделенный текст и поместить его в буфер обмена (кнопка активна только в режиме корректировки программного кода);

Скопировать выделенный текст и поместить его в буфер обмена (кнопка активна только в режиме корректировки программного кода);

Вставить текст из буфера обмена с текущего положения курсора (кнопка активна только в режиме корректировки программного кода и при непустом буфере обмена);

Вставить стандартный шаблон вызова функции с текущего положения курсора (кнопка активна только в режиме корректировки программного кода);

Сгенерировать Лисп-код диалога (включает программное создание диалога, добавление органов управления и назначение обработчиков событий);

Выйти из конструктора диалогов и вернуться в среду разработки.

Панель инструментов конструктора показана на отдельном рисунке ниже:


Два ряда кнопок в верхней части панели служат для выбора "рисуемого" элемента управления. При этом самая левая кнопка в первом ряду (с изображением стрелки) служит для отказа от выбора типа. Активная в данный момент кнопка обводится синей рамкой.

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

Еще ниже располагается выпадающий список объектов диалога. Каждому элементу управления дается уникальное стандартное имя и оно добавляется в выпадающий список объектов. Если пользователь удалит элемент управления, его имя автоматически удалится из списка объектов диалога.

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

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

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

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


После того, как пользователь отпустит левую клавишу мыши, рамка исчезнет, а на месте рамки появится соответствующий элемент управления:


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

Описанным выше образом, размещаем на форме диалога еще одно поле ввода (для результата) и две командные кнопки. Вид полученного диалога приводится ниже:


Пусть читатель обратит внимание, что в выпадающй список, расположенный между палитрой инструментов и окном свойств, добавляются имена выбранных элементов управления. Первое поле ввода будет называться _TXT_1, второе - _TXT_2 и т.д. Диалогу тоже присваивается имя _DLG_. В поля ввода при их создании автоматически заносится текст Поле_ввода_1, Поле_ввода_2 и т.д. Аналогично, на командных кнопках формируются надписи Кнопка-1, Кнопка-2 и т.д.

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


Аналогичным образом очищается второе поле ввода, а на кнопки наносятся надписи "Вычислить" и "Закрыть" соответственно:


На командные кнопки можно посадить иконки. Для того, чтобы сделать это, выделяем щелчком мыши нужную кнопку, переходим в окно свойств, и дважды щелкаем по белому полю справа от надписи "иконка". На поле появится кнопка с тремя точками:


Щелкаем по этой кнопке, - появится форма выбора иконки:


Выбираем нужную иконку, нажимаем кнопку "Принять", - и диалог принимает окончательный вид:


Теперь необходимо назначить кнопкам процедуры-обработчики событий. Начнем с кнопки "Закрыть". Выделяем эту кнопку щелчком мыши, а затем щелкаем по кнопке с изображением желтой молнии. Открывается окно редактирования кода:


В теле функции-обработчика события пишем вызов DLGHIDE:


Щелкаем по кнопке с изображением руки (переходим от редактирования кода к дизайну), выбираем кнопку "Вычислить" и, щелкнув по желтой молнии, открываем ее обработчик. В этом обработчике пишем следующее:


Тело функции-обработчика представляет собой PROG-конструкцию. Используются две локальные (связанные) переменные x и y. В переменую x заносится текст, введенный пользователем в первое поле ввода. Чтобы предотвратить возможные ошибки, вычисление факториала заключается в TRY-EXCEPT-группу. Поскольку функция fact требует аргумента типа FIXED, то используется функция STR2FIX. Если при вычислении факториала произойдет любая ошибка, переменная y получит значение "Ошибка при вычислении". В любом случае, значение переменной y заносится в текстовое поле _TXT_2.

Диалог готов. Перед тем, как генерировать Лисп-код, диалог рекомендуется сохранить. Для этого следует выбрать пункт главного меню "Сохранить" или нажать кнопку на панели инструментов с изображением дискеты. Откроется окно "Сохранить как":


Выбираем имя test и нажимаем кнопку сохранить. Выдается сообщение "Диалог сохранен". Теперь следует сгенерировать Лисп-код нашего диалога. Для этого нажимаем седьмую кнопку панели инструментов (или выбираем пункт главного меню "Сгенерировать"). Снова появится окно "Сохранить как":


Задаем имя test и нажимаем кнопку "Сохранить". Выдается сообщение "Лисп-код сгенерирован", а в выбранной директории появится файл test.lsp, содержащий полный код диалога. При желании можно посмотреть Лисп-код. Он будет выглядеть так:


//
//  Программа отображения диалога _Dlg_
//

(prog nil

      (dlgCreate '_Dlg_ 274 157 "")

      (dlgAddControl '_Dlg_ '_TXT_1 _TEXT 11 8 157 24 '("Tahoma" 8 1 0 0) "" 0 &H80000008 &H80000005)

      (dlgAddControl '_Dlg_ '_BUT_1 _BUTTON 176 3 81 35 '("Tahoma" 8,25 1 0 0) "Вычислить")

      (dlgAddControl '_Dlg_ '_TXT_2 _TEXT 11 46 246 36 '("Tahoma" 8 1 0 0) "" 0 &H80000008 &H80000005)

      (dlgAddControl '_Dlg_ '_BUT_2 _BUTTON 51 86 189 42 '("Tahoma" 8,25 1 0 0) "Закрыть")
      
      (dlgPutPicture '_BUT_2 36)

      //
      // Обработчик события CLICK для кнопки _BUT_2
      //

      (defun _BUT_2_Click  Nil 

          (dlgHide '_DLG_)

      )

      //
      //   Назначение процедуры-события _BUT_2_Click  контролу _BUT_2
      //

      (dlgSetEvent '_BUT_2 '_BUT_2_Click )
      
      //
      // Обработчик события CLICK для кнопки _BUT_1
      //

      (defun _BUT_1_Click  Nil 

                  (PROG (x y)

                     (setq x (dlgGetText '_Txt_1))

                     (TRY

                           (setq y (fact (str2fix x)))

                      EXCEPT

                          (setq y "Ошибка при вычислении")

                      )

                     (dlgPutText '_Txt_2 y)

                  )

      )

      //
      //   Назначение процедуры-события _BUT_1_Click  контролу _BUT_1
      //

      (dlgSetEvent '_BUT_1 '_BUT_1_Click )

      //
      //   Отображение диалога _Dlg_
      //

      (dlgShow '_Dlg_)
)

Можно попытаться исполнить сгенерированный код. Для этого выходим из дизайнера (нажав кнопку "Выход"), и пробуем загрузить и выполнить файл test.lsp. На экране появляется спроектированная выше форма. Вводим в первое поле ввода 10 и нажимаем кнопку Вычислить:


Диалог вполне работоспособен. Если ввести в поле ввода отрицательное число, то будет выдано сообщение об ошибке:


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

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