Описание функций организации диалогов

Разработка программ с графическим пользовательски интерфейсом в HomeLisp-е основано на понятии диалога. С точки зрения пользователя, диалог - это окно Windows, в котором размещены элементы управления, которым назначены обработчики событий (типа нажатия кнопки, выбор элемента списка, включения/выключения радиокнопки и т.д.) С точки зрения ядра HomeLisp-a диалог - это специальным образом созданный атом, имеющий в своем списке свойств флаг DIALOG. Аналогично, элемент управления с точки зрения ядра HomeLisp-a - это специальным образом созданный атом, имеющий в своем списке свойств флаг CONTROL. Эти флаги (DIALOG и CONTROL) добавляются в список свойств атома функциями DLGCREATE и DLGADDCONTROL соответственно. Атом с флагом DIALOG в списке свойств будем называть идентификатором диалога. Соответственно, атом с флагом CONTROL в списке свойств будем называть идентификатором контрола.

Атом, не имеющий списка свойств, будем называть чистым атомом.

Для разработки программы с графическим интерфейсом необходимо:

создать диалог (вызвав функцию DLGCREATE)
разместить на диалоговой форме нужные элементы управления (вызвав нужное число раз функцию DLGADDCONTROL)
при необходимости присвоить свойствам элементов управления нужные значения (для этого служат функции DLGADDITEM, DLGPUTLIST, DLGPUTPICTURE, DLGPUTTEXT)
при необходимости назначить элементам управления обработчики событий (вызвав функцию DLGSETEVENT)
отобразить диалог (вызвав функцию DLGSHOW)

Для скрытия диалога (без разрушения его внутренних структур и с возможностью повторного отображения) служит функция DLGHIDE. После того, как диалог станет ненужным, его следует удалить, вызвав функцию DLGDESTROY. Процедуры - обработчики событий должны быть написаны на HomeLisp-е. Для получения измененных пользователями свойств элементов управления в процедурах - обработчиках событий могут использоваться функции DLGCHKOPT, DLGGETLIST и DLGGETTEXT. Разумеется, эти функции могут использоваться и не в процедурах - обработчиках (если это имеет смысл). При необходимости сделать элемент управления невидимым (или проявить невидимый элемент управления) следует вызывать функцию DLGCNTHIDESHOW.

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

В предлагаемой версии HomeLisp поддерживаются следующие типы элементов управления: командные кнопки, текст-боксы, лист-боксы (списки), комбо-боксы, радиокнопки, чек-боксы (галочки). Тип элемента управления (контрола) задается числом типа FIXED. Для всех контролов в стандартной библиотеке имеется набор констант, приведенный в следующей таблице:  

Константа Описание
_LABEL = 1 Задает метку (надпись)
_TEXT = 2 Задает поле ввода (текстбокс)
_LIST = 3 Задает простой список
_COMBO = 4 Задает выпадающий список (комбо-бокс)
_BUTTON = 5 Задает командную кнопку
_CHECK = 6 Задает чек-бокс (галочку)
_OPTION = 7 Задает радио-кнопку


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


("Имя" размер b i u)


Здесь "Имя" - строка, задающая имя фонта (например, "Tahoma" или "Courier"). Размер задает размер шрифта в пунктах. b i u - признаки стиля Bold, italic и underline соответственно. Значение 1 означает наличие признака 0 - отсутствие.

Событийная модель HomeLisp-a предельно проста: каждый вид контрола позволяет обработать единственный вид события. Это событие для кнопки, чек-бокса, радиокнопки, списка, комбо-бокса вызывается кликом мыши или клавишей Enter, а для текст-бокса нажатием клавиши.

Имена всех диалоговых функций имеют префикс DLG. Диалоговые функции доступны во всех режимах работы, кроме, естественно, WEB-компоненты.

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

Важное предупреждение

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

Список функций управления диалогами
Имя функции К-во аргументов Тип аргументов Выполняемое действие
  DLGADDCONTROL 10 1-2 - ATOM; 3-7 - FIXED; 8 - LIST; 9-STRING; 10 - FIXED Добавляет к диалогу, заданному 1-м аргументом, контрол, задаваемый вторым аргументом. Третий аргумент задает тип контрола; 4-5 аргументы задают координаты левого верхнего угла; 6-7 аргументы задают ширину и высоту; 8-й аргумент задает фонт; 9-й - надпись; 10-й - выравнивание.
  DLGADDITEM 2 1- ATOM, 2-STRING Заносит в лист-бокс или комбо-бокс элемент, задаваемый вторым аргументом
  DLGCLEARLIST 1 ATOM Чистит лист-бокс или комбо-бокс, задаваемый аргументом
  DLGCNTHIDESHOW 1 ATOM Скрывает/отображает контрол, заданный аргументом
  DLGCREATE 4 1-ATOM; 2-3-FIXED; 4-STRING Создает диалог (форму) с шириной и высотой, задаваемой 2 и 3 параметрами и заголовком, задаваемым 4-м параметром. Первый параметр (атом) получает в список свойств флаг DIALOG.
  DLGDELITEM 2 1-ATOM; 2-STRING/FIXED Удаляет из списка или выпадающего списка (заданного первым параметром) элемент по значению или по номеру
  DLGDESTROY 1 ATOM Уничтожает диалог, заданный параметром
  DLGGETCHKOPT 1 ATOM Получает статус чек-бокса или радиокнопки, заданной единственным параметром.
  DLGGETLIST 2 1-ATOM; 2-FIXED Первый параметр должен задавать контрол (лист-бокс или комбо-бокс). Для лист-бокса при значении второго параметра -1, возвращается список выделенных элементов; при значении 1, возвращаются номера выделенных элементов; при прочих значениях возвращается активный элемент. Для комбо-бокса всегда возвращается активный элемент.
  DLGGETTEXT 1 ATOM Для текстбокса, заданного аргументом, возвращается текст из поля ввода.
  DLGHIDE 1 ATOM Скрывает диалог, заданный аргументом
  DLGPUTLIST 2 1-ATOM; 2-LIST В комбо-бокс или лист-бокс, заданный первым аргументом, заносится список, заданный вторым аргументом. Старое содержимое контрола стирается.
  DLGPUTPICTURE 2 1-ATOM; 2-FIXED У кнопки, заданной первым аргументом, устанавливается иконка с номером, заданным вторым аргументом.
  DLGPUTTEXT 2 1-ATOM; 2-STRING Для кнопки, метки, текст-бокса, чек-бокса и радиокнопки, заданной первым аргументом, устанавливается текст, заданный вторым аргументом.
  DLGSETEVENT 2 1-ATOM; 2-EXPR У контрола, заданного первым аргументом, устанавливается процедура-событие, задаваемая вторым аргументом.
  DLGSHOW 3 ATOM, [FIXED,FIXED] Отображает диалог, заданный аргументом
  DLGSHOWEVENT 1 ATOM Возвращает имя функции-обработчика события
DLGADDCONTROL  

Функция DLGADDCONTROL добавляет контрол к диалогу. Функция принимает десять параметров.

Первым параметром является идентификатор диалога.

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

Третий параметр задает тип контрола - число типа FIXED из диапазона 1-7 (см. таблицу типов контролов).

Четвертый и пятый параметры задают координаты левого верхнего угла контрола (в пикселах) относительно левого верхнего угла формы диалога.

Шестой и седьмой параметры задают ширину и высоту контрола (в пикселах).

Восьмой параметр задает шрифт контрола (см. задание фонта в виде списка).

Девятый параметр задает текст (типа STRING). Этот параметр задается для меток, текст-боксов, кнопок, чек-боксов, радиокнопок. Для списков и комбо-боксов параметр игнорируется (можно поставить Nil). Для меток, кнопок, чек-боксов, радиокнопок параметр задает надпись, а для текст-боксов - изначальный текст в поле ввода.

Деcятый параметр задает выравнивание надписи. (Число типа FIXED из диапазона 0 - 2; можно использовать константы _LEFT=0, _RIGHT=1, _CENTER=2 . Этот параметр имеет смысл задавать для текст-боксов, чек-боксов и радиокнопок. Для остальных параметр игнорируется (можно задать Nil).

При успешном завершении функция возвращает идентификатор добавленного контрола.

Вот пример вызова функции:


(dlgCreate 'd-1 200 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _BUTTON 
               10 10 100 40 
               '("Tahoma" 8.25 1 0 1)
               "Кнопочка" Nil)

 ==> 'c-1

(proplist 'c-1)

==> (CONTROL OWNER d-1 Type        5 
                       Left       10 
                       Top        10 
                       width     100 
                       height     40 
                       Font      ("Tahoma" 8.25 1 0 1) 
                       ForeColor NIL 
                       BackColor -2147483633 
                       TEXT      "Кнопочка" 
                       ALIGN     0
    )

(dlgShow 'd-1)

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

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

Если "погасить" диалог и выполнить приведенный ниже код:


(putprop 'c-1 'BackColor _WHITE)

==> c-1

(putprop 'c-1 'Font '("Times" 12 1 1 0))

==> c-1

(dlgShow 'd-1)

То пользователь увидит, что характеристики командной кнопки изменились:

DLGADDITEM  

Функция DLGADDITEM позволяет добавить в лист-бокс или комбо-бокс элемент списка. Старое содержимое списка при этом не стирается. Вызов этой функции в цикле позволяет заполнить/дополнить список нужным содержанием. Другой способ формирования списка дает функция DLGPUTLIST.

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

Если контрол, заданный первым параметром, не является списком или комбо-боксом, то возбуждается состояние ошибки.

Вот пример заполнения списка:


(dlgCreate 'd-1 200 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _LIST 
               10 10 60 80 
               '("Tahoma" 8.25 1 0 0) 
               nil _LEFT)

 ==> c-1

(dlgAddItem 'c-1 "Мышка")

 ==> c-1

(dlgAddItem 'c-1 "Кошка")

 ==> c-1

(dlgAddItem 'c-1 "Жучка")

 ==> c-1

(dlgAddItem 'c-1 "Внучка")

 ==> c-1

(dlgAddItem 'c-1 "Бабка")

 ==> c-1

(dlgAddItem 'c-1 "Дедка")

 ==> c-1

(dlgShow 'd-1)

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


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

DLGCLEARLIST  

Функция DLGCLEARLIST очистить список или комбо-бокс. Функция требует единственный обязательный параметр - идентификатор контрола (CONTROL). Этот контрол должен быть списком или комбо-боксом, в противном случае возбуждается состояние ошибки.

Вот развернутый пример вызова DLGCLEARLIST:


(defun clr nil (dlgClearList 'c-1))

 ==> clr

(dlgCreate 'd-1 200 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _LIST 
               10 10 60 80 
               '("Tahoma" 8.25 1 0 0)
               nil _LEFT)

 ==> c-1

(dlgAddControl 'd-1 'c-2 _BUTTON 
               90 10 100 40 
               '("Tahoma" 8.25 1 0 1)
               "Очистить" Nil)

 ==> c-2

(dlgSetEvent 'c-2 'clr)

 ==> clr

(dlgAddItem 'c-1 "Мышка")

 ==> c-1

(dlgAddItem 'c-1 "Кошка")

 ==> c-1

(dlgAddItem 'c-1 "Жучка")

 ==> c-1

(dlgAddItem 'c-1 "Внучка")

 ==> c-1

(dlgAddItem 'c-1 "Бабка")

 ==> c-1

(dlgAddItem 'c-1 "Дедка")

 ==> c-1

(dlgShow 'd-1)

Здесь создается функция clr, которая чистит список контрола c-1. Пусть читатель обратит внимание, что эта функция может быть зоздана до создания самого контрола. Далее создается диалог и к нему добавляется список командная кнопка. Затем кнопке в качестве обработчика события устанавливается функция clr, список заполняется данными и диалог отображается. Пользователь увидит следующее:


После нажатия кнопки список будет очищен:


DLGCNTHIDESHOW  

Функция DLGCNTHIDESHOW скрывать и отображать контрол. Функция действует, как двоичный переключатель: первый вызов скрывает контрол, второй - отображает. Функция требует единственный параметр типа CONTROL.

Вот пример использования этой функции:


(defun HideShow nil (dlgCntHideShow 'c-1))

 ==> HideShow

(dlgCreate 'd-1 200 100 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _LABEL 10 10 60 80 '("Tahoma" 10 1 0 0) "Надпись" _LEFT _RED)

 ==> c-1

(dlgAddControl 'd-1 'c-2 _BUTTON 90 10 100 40 '("Tahoma" 9 1 0 1) "Нажми" Nil)

 ==> c-2

(dlgSetEvent 'c-2 'HideShow)

 ==> HideShow

(dlgShow 'd-1)

Создается функция HideShow, которая будет скрывать/проявлять контрол c-1. Затем создается диалог и на нем размещается метка и кнопка. Затем функция HideShow устанавливается, как обработчик события для кнопки. После выполнения приведенного кода пользователь увидит:


После нажатия кнопки надпись исчезнет:

DLGCREATE  

Функция DLGCREATE создает диалог. Эта функция требует четыре обязательных параметра. Первый параметр должен быть чистым атомом (после успешного завершения этот атом станет идентификатором диалога). Второй и третий параметры (оба типа FIXED) задают ширину и высоту окна диалога в пикселах. Последний параметр (типа STRING) задает надпись в заголовке формы.

При успешном завершении функция возвращает идентификатор диалога. Следует обратить внимание, что создание диалога не означает его отбражения. Для отображения созданного диалога служит функция DLGSHOW.


(dlgCreate 'd-1 200 200 "Диалог")

==> d-1

(proplist 'd-1)

==> (DIALOG width 200 height 200 title "Диалог" DLGHANDLE 1)

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

Если изменить значения свойств width, height или title, то изменятся значения ширины, высоты и текста заголовка окна диалога. Свойство DLGHANDLE модифицировать нельзя; попытка изменить это свойство вызовет ошибку. Ниже приводится пример диалога с командными кнопками, нажатие на которые изменяет ширину окна диалога:

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

(prog nil

      (dlgCreate '_Dlg_ 170 195 "Модификация")

      (dlgAddControl '_Dlg_ '_BUT_1 _BUTTON 13 11 133 42 '("Tahoma" 8,25 1 0 0) "Шире...")

      (dlgAddControl '_Dlg_ '_BUT_2 _BUTTON 13 58 133 43 '("Tahoma" 8,25 1 0 0) "Уже...")

      (dlgAddControl '_Dlg_ '_BUT_3 _BUTTON 12 111 134 41 '("Tahoma" 8,25 1 0 0) "Закрыть")

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

      (defun _BUT_1_Click  Nil 

           (prog (x)

             (setq x (getprop '_dlg_ 'width))
             (setq x (+ x 50)) 
             (putprop '_dlg_ 'width x)       

           )

      )

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

      (dlgSetEvent '_BUT_1 '_BUT_1_Click )

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

      (defun _BUT_3_Click  Nil 

          (prog nil
            (dlgHide '_dlg_)
            (dlgDestroy '_dlg_)
            (gc)
          ) 
      )

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

      (dlgSetEvent '_BUT_3 '_BUT_3_Click )

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

      (defun _BUT_2_Click  Nil 

           (prog (x)

             (setq x (getprop '_dlg_ 'width))
             (setq x (- x 50))

             (cond ((<= x 160) (return nil)))        
       
             (putprop '_dlg_ 'width x)       

           )

      )

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

      (dlgSetEvent '_BUT_2 '_BUT_2_Click )

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

      (dlgShow '_Dlg_)
)

Если выполнить приведенный выше программный код, то будет отображен следующий следующий диалог:

При нажатии на кнопку "Шире" ширина окна диалога увеличится:

При нажатии на кнопку "Уже" ширина окна диалога уменьшится.

DLGDELITEM  

Функция DLGDELITEM требует два параметра. Первый параметр должен задавать контрол типа LISTBOX или COMBOBOX. Второй параметр может быть строкой или целым числом. Если задана строка, то из внутреннего списка LISTBOX/COMBOBOX будет удален первый элемент, совпадающий с заданной строкой. Если такого элемента не существует, список не изменится.

Если второй параметр есть число FIXED, то будет произведена попытка удаления элемента с заданным номером из внутреннего списка контрола. В этом случае значение числа должно лежать в отрезке [0 , (к-во элементов списка-1)]. Если число выходит за пределы этого отрезка, будет возбуждено состояние ошибки.

Все сказанное демонстрируется примером:



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

(prog nil

      (dlgCreate '_Dlg_ 254 392 "Работа со списками")

      (dlgAddControl '_Dlg_ '_CMB_1 _COMBO 18 18 217 24 '("Tahoma" 9 1 0 0) 
                     &H80000012 &H8000000A)

      (dlgAddControl '_Dlg_ '_BUT_1 _BUTTON 16 56 216 51 '("Tahoma" 9 1 0 0) 
                     "Показать")

      (dlgAddControl '_Dlg_ '_BUT_2 _BUTTON 16 110 216 51 '("Tahoma" 9 1 0 0) 
                     "Очистить весь список")

      (dlgAddControl '_Dlg_ '_BUT_3 _BUTTON 16 165 216 51 '("Tahoma" 9 1 0 0) 
                     "Удалить элемент")

      (dlgAddControl '_Dlg_ '_BUT_4 _BUTTON 16 221 216 51 '("Tahoma" 9 1 0 0) 
                     "Закрыть")

      (dlgAddControl '_Dlg_ '_OPT_1 _OPTION 18 287 214 22 '("Tahoma" 9 1 0 0) 
                     "Показать все" 0 &H80000012 &H8000000F -1)

      (dlgAddControl '_Dlg_ '_OPT_2 _OPTION 18 320 214 21 '("Tahoma" 9 1 0 0) 
                     "Показать выбранное" 0 &H80000012 &H8000000F)


      (defun clr nil (dlgClearList '_CMB_1))

      (defun exi nil (prog nil (dlgHide '_Dlg_) (dlgDestroy '_Dlg_)))

      (defun sho nil
             (say (output 
                    (prog nil
                       (cond ((= (dlgGetChkOpt '_OPT_1) 1) 
                              (return (dlgGetList '_CMB_1 2)))
                             (t  (return (dlgGetList '_CMB_1 0)))
                    ) 
                  ) 
             )
       )
      )

      //(defun del nil (dlgDelItem '_CMB_1 (car (dlgGetList '_CMB_1 -1))))
      
      (defun del nil (dlgDelItem '_CMB_1 0))

      //
      // Назначение обработчиков событий
      //
       
      (dlgSetEvent '_BUT_1 'sho)      

      (dlgSetEvent '_BUT_2 'clr)

      (dlgSetEvent '_BUT_3 'del)

      (dlgSetEvent '_BUT_4 'exi)

      (dlgPutList '_CMB_1 '("Мышка" "Кошка" "Жучка" "Внучка" "Бабка" "Дедка"))

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

      (dlgShow '_Dlg_)

)

Если выполнить приведенный код, то будет выведен диалог:

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

DLGDESTROY  

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

Все сказанное демонстрируется примером:


(dlgCreate 'd-1 200 200 "Диалог")

==> d-1

(proplist 'd-1)

==> (DIALOG width 200 height 200 title "Диалог" DLGHANDLE 1)

(dlgDestroy 'd-1)

==> T

(proplist 'd-1)

==> NIL

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

DLGCHKOPT  

Функция DLGCHKOPT опрашивает статус чек-бокса или радиокнопки. Функция принимает параметр типа CONTROL и возвращает единицу если чек-бокс или радиокнопка активизированы и нуль в противном случае.

Вот пример использования Функции DLGCHKOPT:


(dlgCreate 'd-1 200 200 "Диалог")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _CHECK 8 8 175 50 
               '("FixedSys" 8 0 0 0) "Что-либо...") 

 ==> c-1

(dlgAddControl 'd-1 'c-2 _CHECK 8 58 175 50 
               '("FixedSys" 8 0 0 0) "Еще что-то...") 

 ==> c-2

(dlgAddControl 'd-1 'b-2 _BUTTON 8 130 175 40
               '("Tahoma" 9 1 1 0) "Опросить")

 ==> b-2

(defun d-1_Click Nil (say (strcat "Chk1=" 
                                  (fix2str (dlgGetChkOpt 'c-1))
                                  " "
                                  "Chk2=" 
                                  (fix2str (dlgGetChkOpt 'c-2))
                           )
                      )
)

 ==> d-1_Click

(dlgSetEvent 'b-2 'd-1_Click)

 ==> d-1_Click

(dlgShow 'd-1)

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



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



DLGGETLIST  

Функция DLGGETLIST предназначена для получения списка выбранных пользователем элементов для списка (лист-бокса) или комбо-бокса. Функция принимает два параметра: идентификатор контрола (CONTROL) и индикатор (типа FIXED). Функция работает так:

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

Для комбо-бокса значение индикатора игнорируется и всегда возвращается активный элемент.

Вот пример, иллюстрирующий сказанное:


(dlgCreate 'd-1 120 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _LIST 10 10 95 80 '("Tahoma" 9 1 0 0) nil _LEFT)

 ==> c-1

(dlgAddControl 'd-1 'b-2 _BUTTON 8 87 97 40 '("Tahoma" 9 1 0 0) "Опросить")

 ==> b-2

(dlgAddControl 'd-1 'b-3 _BUTTON 8 130 97 40 '("Tahoma" 9 1 0 0) "Закрыть")

 ==> b-3

(dlgAddItem 'c-1 "Мышка")

 ==> c-1

(dlgAddItem 'c-1 "Кошка")

 ==> c-1

(dlgAddItem 'c-1 "Жучка")

 ==> c-1

(dlgAddItem 'c-1 "Внучка")

 ==> c-1

(dlgAddItem 'c-1 "Бабка")

 ==> c-1

(dlgAddItem 'c-1 "Дедка")

 ==> c-1

(defun b-2_Click Nil (say (output (dlggetlist 'c-1 -1))))

 ==> b-2_Click

(defun b-3_Click Nil (dlgHide 'd-1))

 ==> b-3_Click

(dlgSetEvent 'b-2 'b-2_click)

 ==> b-2_Click

(dlgSetEvent 'b-3 'b-3_click)

 ==> b-3_Click

(dlgShow 'd-1)

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


Теперь, если мышью или клавиатурой выбрать какие-либо элементы:


а затем нажать кнопку "Опросить", то пользователь увидит выбранные элементы:

DLGGETTEXT  

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

Рассмотрим следующий пример:


(dlgCreate 'd-1 120 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _TEXT 10 10 95 12 '("Tahoma" 9 1 0 0) "" _LEFT)

 ==> c-1

(dlgAddControl 'd-1 'b-2 _BUTTON 8 87 97 40 '("Tahoma" 9 1 0 0) "Опросить")

 ==> b-2

(dlgAddControl 'd-1 'b-3 _BUTTON 8 130 97 40 '("Tahoma" 9 1 0 0) "Закрыть")

 ==> b-3

(defun b-2_Click Nil (say (dlggettext 'c-1 -1)))

 ==> b-2_Click

(defun b-3_Click Nil (dlgHide 'd-1))

 ==> b-3_Click

(dlgSetEvent 'b-2 'b-2_click)

 ==> b-2_Click

(dlgSetEvent 'b-3 'b-3_click)

 ==> b-3_Click

(dlgShow 'd-1)

 ==> d-1

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


Если теперь в поле ввода ввести текст:


и нажать кнопку "Опросить", то получим:


DLGHIDE  

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

Приведенный ниже пример подтверждает это:


(dlgCreate 'd-1 120 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _TEXT 10 10 95 12 '("Tahoma" 9 1 0 0) "" _LEFT)

 ==> c-1

(dlgAddControl 'd-1 'b-2 _BUTTON 8 87 97 40 '("Tahoma" 9 1 0 0) "Опросить")

 ==> b-2

(dlgAddControl 'd-1 'b-3 _BUTTON 8 130 97 40 '("Tahoma" 9 1 0 0) "Закрыть")

 ==> b-3

(defun b-2_Click Nil (say (dlggettext 'c-1 -1)))

 ==> b-2_Click

(defun b-3_Click Nil (dlgHide 'd-1))

 ==> b-3_Click

(dlgSetEvent 'b-2 'b-2_click)

 ==> b-2_Click

(dlgSetEvent 'b-3 'b-3_click)

 ==> b-3_Click

(dlgShow 'd-1)

 ==> d-1

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

DLGPUTLIST  

Функция DLGPUTLIST позволяет занести список в лист-бокс или в комбо-бокс. Функция принимает два обязательных параметра: идентификатор контрола и одноуровневый список, состоящий из строк. При успешном завершении функция возвращает T.

Ниже приводится два примера вызова функции DLGPUTLIST:


(dlgCreate 'd-1 120 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _LIST 
               10 10 95 80 
               '("Tahoma" 9 1 0 0) 
               nil _LEFT)

 ==> c-1

(dlgAddControl 'd-1 'b-2 _BUTTON
               8 87 97 40 
               '("Tahoma" 9 1 0 0) 
               "Занести")

 ==> b-2

(dlgAddControl 'd-1 'b-3 _BUTTON 
               8 130 97 40 
               '("Tahoma" 9 1 0 0) 
               "Закрыть")

 ==> b-3

(defun b-2_Click Nil (dlgPutList 'c-1 
                      '("Мышка"
                        "Кошка"
                        "Жучка"
                        "Внучка"
                        "Бабка" 
                        "Дедка")))

 ==> b-2_Click

(defun b-3_Click Nil (dlgHide 'd-1))

 ==> b-3_Click

(dlgSetEvent 'b-2 'b-2_click)

 ==> b-2_Click

(dlgSetEvent 'b-3 'b-3_click)

 ==> b-3_Click

(dlgShow 'd-1)

Здесь создается простой список (лист-бокс) и две кнопки. Обработчик нажатия одной из кнопок заносит содержимое в изначально пустой список. Если выполнить приведенные выше команды, то пользователь увидит:


После нажатия на кнопку "Занести" пользователь увидит заполненный список:


Вот аналогичный пример, но с заполнением комбо-бокса:


(dlgCreate 'd-1 120 200 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _COMBO 
               10 10 95 12 
               '("Tahoma" 9 1 0 0) 
               nil _LEFT)

 ==> c-1

(dlgAddControl 'd-1 'b-2 _BUTTON
               8 87 97 40 
               '("Tahoma" 9 1 0 0) 
               "Занести")

 ==> b-2

(dlgAddControl 'd-1 'b-3 _BUTTON 
               8 130 97 40 
               '("Tahoma" 9 1 0 0) 
               "Закрыть")

 ==> b-3

(defun b-2_Click Nil (dlgPutList 'c-1 
                      '("Мышка"
                        "Кошка"
                        "Жучка"
                        "Внучка"
                        "Бабка" 
                        "Дедка")))

 ==> b-2_Click

(defun b-3_Click Nil (dlgHide 'd-1))

 ==> b-3_Click

(dlgSetEvent 'b-2 'b-2_click)

 ==> b-2_Click

(dlgSetEvent 'b-3 'b-3_click)

 ==> b-3_Click

(dlgShow 'd-1)

Здесь создается выпадающий список (комбо-бокс) и две кнопки. Обработчик нажатия одной из кнопок заносит содержимое в изначально пустой комбо-бокс. Если выполнить приведенные выше команды, то пользователь увидит:


После нажатия на кнопку "Занести" пользователь увидит заполненный список:

DLGPUTPICTURE  

Функция DLGPUTPICTURE позволяет поместить иконку на командную кнопку. К сожалению, иконку приходится выбрать из встроенного автором в программу списка иконок. Возможно, в последующих версиях HomeLisp можно будет загружать иконки из внешних файлов. Функция DLGPUTPICTURE принимает два обязательных параметра: идентификатор командной кнопки и номер иконки (число типа FIXED в интервале 1 - 42). Следует отметить, что высота кнопки должна быть достаточна для размещения выбранной иконки.

Вот пример вызова Функции DLGPUTPICTURE:


(dlgCreate 'd-1 180 100 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _BUTTON 10 10 150 60 '("Tahoma" 9 1 0 0) "Нажми!" Nil)

 ==> c-1

(defun setpic nil (prog nil 
                        (dlgPutPicture 'c-1 
                                       (str2fix (ask "Задайте номер иконки")))))

 ==> setpic

(dlgSetEvent 'c-1 'setpic)

 ==> setpic

(dlgShow 'd-1)

Создается диалог и к нему добавляется командная кнопка. Кнопке назначается функция-обработчик нажатия, в которой запрашивается номер иконки (вызов ASK), этот номер из строковой формы преобразуется в числовую (вызов STR2FIX) и подается на вход DLGPUTPICTURE.

Если пользователь выполнит приведенный выше код, нажмет кнопку (которая изначально не содержит иконки), и введет 4 , то на кнопку будет помещена следующая иконка:

DLGPUTTEXT  

Функция DLGPUTTEXT позволяет для кнопки, чек-бокса, радиокнопи установить текстовую надпись. Для текст-бокса эта функция позволяет занести текст в область ввода. Функция требует два обязательных параметра: идентификатор контрола и текст/надпись (типа STRING).

Пользоваться этой функцией несложно:


(dlgCreate 'd-1 180 100 "Проба")

 ==> d-1

(dlgAddControl 'd-1 'c-1 _BUTTON 
               10 10 150 60 
               '("Tahoma" 9 1 0 0) "Нажми!" Nil)

 ==> c-1

(defun setpic nil (prog nil (dlgPutText 'c-1 "Еще раз!")))

 ==> setpic

(dlgSetEvent 'c-1 'setpic)

 ==> setpic

(dlgShow 'd-1)

После отображения диалога пользователь увидит:


А после нажатия на кнопку:

DLGSETEVENT  

Функция DLGSETEVENT назначает контролу обработчик события. Функция требует два параметра: идентификатор контрола и имя функции-обработчика. При успешном завершении функция возвращает имя функции-обработчика.

Как уже было отмечено во введении, событийная модель в HomeLisp-e очень проста. С каждым типом контролов связано одно событие, которое можно обработать программно (с помощью функции-обработчика). Эти события представлены в нижеследующей таблице:

Контрол Событие
Метка (_LABEL) Щелчок мышью.
Текст-бокс (_TEXT) Нажатие клавиши. Процедуре-обработчику передается ASCII-код нажатой клавиши.
Лист-бокс (_LIST) Выбор элемента списка мышью (одиночный клик) или клавиатурой.
Комбо-бокс (_COMBO) Выбор элемента списка мышью (одиночный клик) или клавиатурой.
Кнопка (_BUTTON) Одиночный клик или Enter.
Чек-бокс (_CHECK) Одиночный клик или Enter.
Радиокнопка (_OPTION) Одиночный клик или Enter.

Ниже приводится не слишком тривиальный пример. В нем выполняется обработка события для текст-бокса с запоминанием кодов нажатых клавиш. Для запоминания используется функция PUSH, написанная на Лиспе:


(dlgCreate 'd-1 200 170 "Проба")

 ==> d-1

(dlgAddControl 'd-1 't-1 
               _TEXT 10 10 170 12 
               '("Tahoma" 9 1 0 0) "" _LEFT)

 ==> t-1

(dlgAddControl 'd-1 'b-1 
                _BUTTON 10 40 170 40 
                '("Tahoma" 9 1 0 0) 
                "Показать" _CENTER)

 ==> b-1

(dlgAddControl 'd-1 'b-2 
               _BUTTON 10 90 170 40 
               '("Tahoma" 9 1 0 0) 
               "Закрыть" _CENTER)

 ==> b-2

(defun add-key (keyascii) 
               (push keyascii key-log)
)

 ==> add-key

(defun show-log nil (say (output key-log)))

 ==> show-log

(defun quit nil (dlgHide 'd-1))

 ==> quit

(dlgSetEvent 't-1 'add-key)

 ==> add-key

(dlgSetEvent 'b-1 'show-log)

 ==> show-log

(dlgSetEvent 'b-2 'quit)

 ==> quit

(setq key-log nil)

 ==> NIL

(dlgShow 'd-1)

В примере создается диалог с текст-боксом и двумя кнопками. Текст-боксу назначается обработчик события, который добавляет код очередной нажатой клавиши к списку, являющемуся значением переменной key-log. Одной из кнопок назначается обработчик, который отображает текущее состояние списка key-log. Другая кнопка служит для скрытия диалога. Важно, что перед отображением диалога, переменной key-log присваивается значение Nil.

Если ввести текст в текст-бокс:


и нажать кнопку "Показать", то можно увидеть коды всех нажатых клавиш:


Следует отметить только, что коды клавиш запоминаются в списке в обратном порядке. Это связано с особенностью работы функции PUSH.

DLGSHOW  

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