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



 

Часть 13

Глава 12. Объекты управления
Большинство приложений Windows используют устройства интерфейса пользователя с общим названием управления. Следующая таблица описывает управления Windows, поддерживаемые типами объектов ObjectWindows:
     Таблица 12.1. Управления Windows, поддерживаемые ObjectWindows
----------------------------------------------------------------
Управление     Тип объекта    Использование
----------------------------------------------------------------
блок списка    TListBox       Прокручиваемый список элементов
                              (например, файлов) из которых можно
                              сделать выбор.
линейка        TScrollBar     Автономная линейка прокрутки,
прокрутки                     по появлению аналогичная
                              прокручивающимся окнам и блокам
                              списка.
кнопка нажатия TButton        Кнопка для нажатия со связанным с
                              ней текстом.
блок проверки  TCheckBox      Состоящая из блока кнопка, которая
                              может проверяться, а может и нет, со
                              связанным текстом.
кнопка выбора  TRadioButton   Кнопка, которая может проверяться,
                              а может и нет. Обычно используется
                              во взаимоисключающих группах.
блок группы    TGroupBox      Статический прямоугольник с текстом
                              в левом верхнем углу.
управление     TEdit          Поле для ввода текста пользователем.
редактированием
статическое    TStatic        Фрагмент отображаемого текста,
управление                    который не может быть изменен
                              пользователем.
комбинированный TComboBox     Комбинация блока списка и
блок                          управления редактированием.
клиент MDI     TMDICLient     Описан в Главе 13.
----------------------------------------------------------------
На Рис.12.1 показано проявление на экране некоторых типичных управлений.
Рис.12.1. Примеры некоторых управлений
ObjectWindows определяет типы объектов для всех приведенных выше типов управлений, которые могут использоваться в качестве дочерних окон вне других окон. Управления, которые являются частью блока диалога, есть элементы интерфейса управления, который зада
н в ресурсе и им не требуется соответствующий объект ObjectWindows (см. Главу 11). Материал данной главы относится к функционированию объектов управления и показывает, как они могут быть использованы в окне.
Тип объекта TControl
В Windows управления являются специализированными окнами. В ObjectWindows тип TControl происходит от типа TWindow. Объекты управления аналогичны объектам окна по по способу их создания и удаления и по образу их поведения в качестве дочерних окон. Они отл
ичаются от окон по способу их реагирования на сообщения Windows (wm_).
Вы можете заметить, что типы управления ObjectWindows обладают всеми функциональными возможностями, которые требуются вашему приложениями, поэтому очень часто вы будете использовать уже существующие типы без изменений. Вы можете использовать существующие
 типы в неограниченном числе комбинаций, на основании функциональных требований вашей программы. В некоторых случаях вам может потребоваться определить производные типы управления. Например, вы можете определить специализированный тип блока списка с имен
ем StatesListBox, который хранит названия 50 штатов и автоматически отображает их при своем создании.
Тип TControl, аналогично TWindowsObject, является абстрактным типом объекта. Вы будете широко использовать его производные TListBox, TButton и другие. Данный раздел описывает общее поведение всех объектов управления.
Конструирование и создание объектов управления
Жизнь управления обычно протекает параллельно жизни его родительского окна. Согласно типичному сценарию объект родительского окна определяет поле данных для каждого из его родительских окон. Если вы создаете тип окна с именем SampleWindow, то он может им
еть поле данных с именем LB1 для хранения объекта TListBox.
Кроме полей данных родительские окна поддерживают список их дочерних окон в поле ChildList. Все дочерние управления объекта окна автоматически добавляются к этому списку, поэтому им не требуются отдельные поля данных. Однако, иногда может оказаться более
 удобным получать доступ и манипулировать объектами управления, если они имеют соответствующие поля объектов. Редко используемые управления (например, статические управления или блоки групп) не должны иметь специально выделенных для них полей. Для других
 управлений вы сами должны решить, не будет ли ими легче манипулировать с указателем в их родительском окне.
При создании управлений есть два этапа. Сначала конструируется объект управления, а уже затем создается соответствующий элемент управления. Оба эти этапа обычно выполняются при конструировании и создании объекта родительского окна. Метод родительского ок
на Init обычно вызывает конструкторы его дочерних управлений. Например, этот метод Init типа окна конструирует новый объект блока списка и записывает его в поле объекта LB1:
constructor SampleWindow.Init(AParent: PWindowsObject; ATitle:
 PChar);
begin
 TWindow.Init(AParent, ATitle);
 LB1:=New(PListBox, Init(@Self, id_LB1, 20, 20, 100, 80));
end;
Шесть полей в конструкторе блока списка Init представляют соответственно объект управления родительского окна, ID управления, координаты x и y его левого верхнего угла на экране (относительно области клиента его родительского окна), его ширину (W), и выс
оту (H). Все производные TControl в ObjectWindows берут по крайней мере эти шесть параметров, за исключением TMDIClient (см. Главу 13, "Объекты MDI").
Объекты управления, которые не имеют соответствующего индивидуального поля объекта, конструируются следующим образом:
constructor TSampleWindow.Init(AParent: PWindowsObject; ATitle:
 PChar);
var TempLBox: PListBox;
begin
 TWindow.Init(AParent, ATitle);
 TempLBox:=New(PListBox, Init(@Self, id_LB1, 20, 20, 100, 80));
end;
Все производные TControl за исключением TMDIClient имеют стиль ws_Child и ws_Visible из вызова TControl.Init. Если вам нужно сменить стиль управления, то вы можете манипулировать его полем Attr.Style, как это описано для окон в Главе 11.
Все элементы управления объектов управления автоматически создаются методом SetupWindow, унаследованным объектом родительского окна. Вам не нужно явно вызывать Create для ваших объектов управления.
В случае необходимости управления также заполняются и устанавливаются в SetupWindow. Приведем типичную реализацию метода SetupWindow:
procedure SampleWindow.SetupWindow;
begin
 TWindow.SetupWinow;               {создание управления полями}
 {Add items to list:}
 LB1^AddString('Item 1');
 LB1^AddString('Item 2');
end;
Для отображения управлений не нужно вызывать Show. Как дочерние окна они автоматически отображаются и перерисовываются вместе с родительским окном. Однако, вы можете использовать Show для отображения и укрытия управлений.
Подводя итог вопросу создания управления, можно сказать следующее. Все, что вам нужно сделать, это по желанию определить поля в типе объекта вашего родительского окна для хранения каждого дочернего управления. Затем для вашего типа окна определить констр
уктор Init, который создает объект управления и SetupWindow, который устанавливает объект управления. Обратите внимание на то, что вся работа делается родителями, а в это время дети отдыхают. Похоже, что всегда так получается.
Разрушение и освобождение управления
Как и для создания управлений, за их уничтожение отвечает родительское окно. Элемент управления автоматически уничтожается вместе с элементом родительского окна, когда пользователь закрывает окно или приложение. Соответствующий объект управления автомати
чески уничтожается деструктором родительского окна.
Обработка сообщений и управления
Связь между объектом окна и его объектами управления аналогична связи между объектом диалога и его объектами управления. Как и диалогу, окну нужен механизм манипулирования его управлениями и реакции на события управления (например, выбор из блока списка)
.
Манипуляция управлениями окна
Диалоги манипулируют своими управлениями путем посылки им сообщений методом SendDlgItemMsg с именем управляющего сообщения, подобным lb_AddString, в качестве параметра (см. Главу 11). Однако, объекты управления упрощают этот процесс, предлагая методы неп
осредственного манипулирования управлениями на экране, например, TListBox.AddString.
Когда объекты управления имеют соответствующие поля объекта, то проще вызвать методы управления:
LB1^.AddString('Scotts Valley');
Однако, манипулирование объектом управления без поля объекта требует выделения объекта из списка дочерних окон родительского окна. Используйте метод GetChieldWithID:
var
 TheListBox: PListBox;
begin
 TheListBox:=PListBox(ChildWithID(id_LB1));
 TheListBox^.AddString('Scotts Valley');
end;
Реакция на сообщения управления
События в управлениях окна приводят к появлению управляющих информационных сообщений (см. "Реакция на события управления" в Главе 6). В большинстве случаев объекты окна реагируют на управляющие информационные сообщения вызовом методов реакции, основанным
 на дочерних ID. Для этого нужно определить методы реакции на сообщения, основанные на дочерних ID, в типе родительского окна для каждого дочернего управления:
TSampleWindow=object(TWindow)
 LB1: PListBox;
 BN1, BN2: Button;
 ST1: PStatic;
 procedure IDLB1(var Msg: TMessage); virtual id_First+id_LB1;
 procedure IDBN1(var Msg: TMessage); virtual id_First+id_LN1;
 procedure IDBN2(var Msg: TMessage); virtual id_First+id_LN2;
end;
В вашем методе реакции Msg.lParamHi несет информационный код управления (например, lbn_SelChange и bn_Clicked). Напишите реакцию для обработки важных информационных кодов:
procedure TSampleWindow.IDLB1(var Msg: TMessage);
begin
 case Msg.lParamHi of
  lbn_SelChange: {Обработка изменений выбора};
  lbn_DblClk: {Управление выбором двойным указанием};
  end;
end;
Однако, бывают моменты, когда вам нужно, чтобы объект управления сам реагировал на управляющее информационное сообщение. Для этого нужно встраивать метод реакции в управление. Например, вам нужно разработать кнопку, которая меняла бы свой текст при нажат
ии ее пользователем, или управление редактированием, которое позволяло бы вводить только цифры. Это можно реализовать для управлений окна, поскольку они являются объектами управления. Управляющие элементы диалога не могут отреагировать на управляющее инф
ормационное сообщение, если они не связаны с объектами управления (с помощью InitResource).
В этих особых случаях вам нужен обладающий заданным поведением тип управления, вместо дублирования его для каждого родительского окна. Результатом будет автономный тип объекта, который может быть многократно использован во многих приложениях.
Для программирования объекта управления с непосредственной реакцией на информационные сообщения нужно для его типа определить метод реакции, основанный на сообщении (а не основанный на дочернем ID метод реакции для объекта его родительского окна). В каче
стве идентификатора заголовка метода используйте сумму nf_First и код информационного управления. Для этого определим тип, производный от существующего типа управления:
TSpecializedLB=object(TListBox)
 procedure LBNSelChange(var Msg: TMessage); virtual nf_First +
  lbn_SelChange;
 procedure LBNDblClk(var Msg: TMessage); virtual nf_First +
  lbn_DblClk;
end;
procedure TSpecializedLB.LBNSelChange(var Msg: TMessage);
begin
 {Обработка изменений выбора};
 Msg.Result:=1;
end;
Если вы не хотите, чтобы родительское окно получало информационное сообщение после его обработки управлением, Нужно установить результат сообщения (Msg.Result) равным 1. Если не установить результат равным 1, то можно провести дополнительную обработку из
 объекта родительского окна.
Окна, которые действуют как диалоги
Блоки диалога с управлениями позволяют пользователю с помощью клавиши Tab циклически переходить от одного блока управления к другому. Клавиши со стрелками можно использовать для задания варианта в кнопке выбора в блоке группы. Для моделирования этого инт
ерфейса клавиатуры для окон с управлениями, нужно вызвать метод TWindowsObject EnableKBHandler для объекта окна в его конструкторе.
Управление блоком списка
Использование блока списка это самый простой способ запросить пользователя программы Windows сделать выбор из списка. Например, вы можете запросить пользователя сделать выбор из списка файлов, принтеров, видов поверхностей или фруктов, в зависимости от п
рироды программы. Блоки списка объединяются типом объекта TListBox. TListBox определяет методы реакции для их применения по четырем направлениям: создание блоков списка, изменение списка элементов, просмотр списка элементов и определение выбранного польз
ователем элемента.
Конструирование и создание блоков списка
Конструктор Init в TListBox берет родительское окно, ID, и размеры X, Y, W и H управления:
LB1:=New(PListBox, Init(@Self, id_LB1, 20, 20, 340, 100));
TListBox вызывает TControl.Init, который задает управлению стиль ws_Child или ws_Visible. Затем он добавляет стиль lbs_Standard. lbs_Standard является комбинацией lbs_Notify (для приема информационных сообщений), ws_VScroll (для вертикальной линейки прок
рутки), lbs_Sort (для сортирования списка элементов по алфавиту) и ws_Border (для обозначения границ). Если вы хотите использовать другой стиль блока списка, вы можете модифицировать поле TListBox Attr.Style. Например, если вам нужен блок списка с неотсо
ртированными элементами, используйте следующий код:
LB1:=New(PListBox, Init(@Self, id_LB1, 20, 20, 340, 100));
LB1^.Attr.Style:=LB1^.Attr.Style and not lbs_Sort;
или
LB1:=New(PListBox, Init(@Self, id_LB1, 20, 20, 340, 100));
LB1^.Attr.Style:=ws_Child or ws_Visible or ibs_Notify or ws_VScroll
 or ws_Border;
В качестве дочерних окон объекты управления блока списка автоматически создаются их родительскими окнами.
Модификация блоков списка
После создания блока списка нужно заполнить его список элементами, которые должны быть строками. Позднее вы можете захотеть добавить или исключить некоторые элементы, или полностью очистить список. Для добавления или заполнения элементами списка нужно вы
звать метод блока списка AddString:
LB1^.AddString('Item 1');
LB1^.AddString('Item 2');
LB1^.AddString('Item 3');
LB1^.AddString('Item 4');
LB1^.AddString('Item 5');
LB1^.AddString('Item 6');
Если AddString закончится неудачно, он возвратит отрицательное значение.
Блок списка хранит список строк, который больше похож на массив строк, т.к. они оба хранят свои элементы по индексам. Если бы LB1 был массивом, то 'Item 1' хранился бы в LB1[0]. Элемент 'Item 2' хранился бы в LB1[1], 'Item3' в LB1[2] и т.д. Каждый раз пр
и вызове AddString заданная строка добавляется к списку, по умолчанию в алфавитном порядке, или в конец списка, если стиль исключает lbs_Sort.
Независимо от того, отсортирован или нет блок списка, можно вставить новый элемент по заданному индексу с помощью InsertString:
LB1^.InsertString('Item 1.5', 1);
Это приведет к сдвигу на одну позицию всех элементов списка, индекс которых больше или равен 1. Семь только что рассмотренных вызовов метода создадут в результате следующий список:
----------------------------
Индекс         Элемент
----------------------------
0              'Item 1'
1              'Item 1.5'
2              'Item 2'
3              'Item 3'
4              'Item 4'
5              'Item 5'
6              'Item 6'
----------------------------
Рис.12.2. Заполненный блок списка
Вставка новой строки с индексом -1 помещает строку в конец списка.
Для удаления элемента вызывается DeleteString. Следующий вызов метода удаляет строку с индексом 1 ('Item 1.5') и перемещает все строки с индексом большим 1 на одну позицию вверх:
LB1^.DeleteString(1);
И, наконец, ClearList удаляет все строки из блока списка:
LB1^.ClearList;
Запросы в блоках списка
Есть три метода, которые вы можете вызывать для получения информации относительно списка, содержащегося в объекте блока списка. GetCount возвращает число элементов списка. GetString берет строку, расположенную в списке по индексу, заданному целым аргумен
том. Аргумент PChar указывает на буфер, принимающий строку. GetString кроме того возвращает целое, представляющее длину строки. GetString просто возвращает длину строки заданного индекса, но не передает саму строку.
Выбор из блока списка
Пользователь может делать с блоком списка лишь ограниченное число действий: просматривать список прокручиванием, остановившись на одном из элементов делать простое или двойное нажатие. Когда имеет место какое-либо действие пользователя над блоком списка,
 Windows посылает информационное сообщение блока списка к родительскому окну блока списка. Обычно, вы будете определять в типе родительского окна метод, основанный на дочернем ID для обработки сообщений каждого из управлений родителя.
Каждое информационное сообщение блока списка (lbn) содержит информационный код блока списка (целую константу) в Msg.lParamHi для задания природы действия. В следующей таблице показаны наиболее часто используемые коды lbn:
     Таблица 12.2. Информационные сообщения блока списка
----------------------------------------------------------------
wParam         Действие
----------------------------------------------------------------
lbn_SelChange  Отдельным нажатием кнопки на мыши была выбрана
               опция.
lbn_DblClk     Двойным нажатием кнопки на мыши была выбрана
               опция.
lbn_SetFocus   Пользователь привлек внимание к блоку списка
               простым или двойным нажатием, либо клавишей Tab.
               Предшествует lbn_SelChange.
----------------------------------------------------------------
Приведем пример метода родительского окна по обработке сообщений блока списка:
procedure TLBoxWindow.HandleLB1Msg(var Msg: TMessage);
var
 Idx: Integer;
 ItemText: string[10]
begin
 if Msg.lParamHi=lbn_SelChange then
 begin
  Idx:=LB1^.GetSelIndex;
  if LB1^.GetStringLenIdx)<11 then
   begin
    LB1^.GetSelString(@ItemText, 10);
    MessageBox(HWindow, @ItemText, 'You selected:', mb_OK);
   end;
 end;
 else DefWndProc(Msg);
end;
пользователь делает выбор, если Msg.lParamHi совпадает с константой lbn_SelChange. Если это так, то берется длина выбранной строки, проверяется, что она помещается в строку из 10 символов, и выбранная строка показывается в блоке сообщения (см. Рис.12.3).

Рис.12.3. Реакция на выбор пользователем элемента блока списка
Выбранным элементом можно манипулировать четырьмя методами TListBox: GetSekString, GetSelIndex, SetSelString и SetSelIndex. Методы Get берут строку и индекс выбранной строки. Методы Set обходят пользователя и форсируют выбор конкретного элемента, задание
м строки или индекса. Это вызывает его отображение, если он в данный момент не виден.
Пример программы: LBoxTest
Программа LBoxTest это полная программа, которая создает окно с блоком списка. После запуска приложения появляется головное окно с блоком списка. Когда пользователь выбирает элемент блока списка, появляется диалог с выбранным элементом. Обратите внимание
 на взаимоотношения между объектом окна и объектом блока списка. Блок списка это не просто дочернее окно головного окна, головное окно владеет им как полем объекта. LB1 это одно из полей объекта головного окна и оно содержит объект блока списка.
Полный текст программы содержится в файле LBOXTEST.PAS на ваших дистрибутивный дискетах.
Статическое управление
Статические управления это обычно неизменяемые модули текста или простые изображения, которые могут появляться на экране в окне или диалоге. Пользователь не взаимодействует со статическими управлениями, хотя программа и может изменять их текст. Рис.12.4 
показывает множество стилей статического управления и их соответствующих констант стиля Windows.
Рис.12.4. Статические управления
Конструирование статического управления
Пользователь никогда не взаимодействует непосредственно со статическими управлениями, поэтому приложение будет очень редко, если вообще будет, принимать управляющие информационные сообщения относительно статического управления. Следовательно, большинство
 статических управлений может быть сконструировано с ID ресурса -1 или некоторым другим неиспользуемым числом. Для них для всех можно использовать одно значение.
Кроме обычных параметров Init управления, TStatic.Init имеет один дополнительный параметр, длина текста, который устанавливает максимальную длину текста, который может поместиться в управление. Текст должен заканчиваться пустым символом, поэтому в действ
ительности число отображаемых символом на единицу меньше заданной в конструкторе длины текста.
Конструктор Init в TStatic конструирует новый объект статического управления.
Stat1:=New(Static, Init(@Self, id_ST1, '&Text', 20, 50, 200,
 24, 6));
Часто вы не манипулируете статическими управлениями после их создания. Поэтому, часто бывает не нужно выделять поле объекта для хранения объекта статического управления и бывает достаточно временной переменной:
TempStat:=New(Static, Init(@Self, id_ST1, '&Text', 20, 50, 200,
 24, 6));
Init воспроизводит статическое управление со стилем ss_Left (выравнивание слева), и ws_Child и ws_Visible. Для изменения стиля нужно манипулировать полем Attr.Style:
Stat1^.Attr.Style:=Stat1^.Attr.Style and (not ss_Left) or
 ss_Center;
В статическом управлении есть опция подчеркивания одного или нескольких символов в строке текста. Реализация и действие этого эффекта аналогичны подчеркиванию первого символа в выборе меню: Insert и & должны непосредственно предшествовать символу в строк
е, который будет подчеркиваться. Например, для подчеркивания T в слове 'Text' нужно в послать строку "&Text' в вызов Init. Если в строке вам нужно использовать &, используйте статический стиль Windows ss_NoPrefix (см. Рис.12.4).
Запросы статического управления
Для уточнения текущего текста, который хранится в статическом управлении, используется метод GetText.
Модификация статического управления
Для изменения текста статического управления TStatic имеет два метода. SetText устанавливает статический текст, передаваемый аргументом PChar. Clear удаляет статический текст. Однако, вы не можете сменить текст статического управления, созданный со стиле
м ss_Simple.
Пример: приложение StatTest
Программа StatTest создает статическое тестовое приложение, показанное на Рис.12.4. Обратите внимание на то, что метки ('Default Static' и 'ss_Simple') есть статистические управления, также как и 'Sample Text', черные и серые прямоугольники.
Полный текст программы в файле STATTEST.PAS содержится на ваших дистрибутивных дискетах.
Управление нажатием клавиш
Кнопки нажатия (иногда называемые "командными кнопками") используются для выполнения определенных задач при каждом их нажатии. Есть два стиля кнопок нажатия, оба они имеют тип TButton. Эти два стиля bs_PushButton и DefPushButton. Кнопки нажатия по умолча
нию аналогичны кнопкам нажатия, но имеют жирную рамку и обычно используются для индикации реакции пользователя по умолчанию. На Рис.12.5 показан пример программы Windows, в которой используются обычные кнопки нажатия и кнопки нажатия по умолчанию.
Рис.12.5. Программа Windows, использующая кнопки
Конструктор Init в TButton берет родительское окно, ID управления, строку текста типа PChar, местоположение и размер кнопки, и булевский флаг, IsDefaultButton, который показывает, будет ли данная кнопка обычной или кнопкой нажатия по умолчанию. Кнопки на
жатия по умолчанию имеют темную рамку и активизируются при нажатии клавиши Enter.
Push1:=New(PButton, Init(@Self, id_Push1, 'Test Button', 38, 48,
 316, 24, False));
Реакции на клавишные сообщения
Когда пользователь нажимает кнопку, родительское окно кнопки принимает сообщение, основанное на родительском ID. Если объект родительского окна воспринимает сообщение, он может отреагировать на эти события выводом блока диалога, записыванием файла или др
угим контролируемым программой действием. Для организации реакции на сообщения кнопок нужно определить основанный на дочернем ID метод для обработки каждой кнопки. Например, следующий метод IDBut1 обрабатывает реакцию на нажатие пользователем кнопки. Еди
нственный информационный код, определенный в Windows для кнопок нажатия это bn_Clicked, поэтому информационный код не нужно проверять.
TTestWindow=object(TWindow)
 But1: PButton;
 procedure IDBut1( var Msg: TMessage); virtual id_First + idBut1;
 ...
end;
procedure TestWindow.IDBut1(var Msg: TMessage);
begin
 MessageBox(HWindow, 'Clicked', 'The Button was:' mb_OK)
end;
Блоки проверки и клавиши выбора
Тип TCheckBox происходит от TButton и тип TRadioButton происходит от TCheckBox. Блоки проверки обычно используются для предоставления пользователю выбора одного из двух возможных вариантов. Пользователь может проверить или не проверять управление, или ос
тавить его так, как оно установлено. Если имеется группа блоков проверки, то может проверяться не один, а несколько. Например, вы можете использовать блок проверки для выбора трех шрифтов для их загрузки в приложение. Клавиши выбора, с другой стороны, ис
пользуются для выбора одного из нескольких взаимоисключающих вариантов. Например, кнопка выбора может использоваться для выбора шрифта для конкретного символа. Иногда мы будем ссылаться на блоки проверки и клавиши выбора как на блоки выбора.
Важным аспектом при рассмотрении блоков выбора является их состояние. При отображении на экране блок выбора проверяется или не проверяется. Когда пользователь нажимает блок выбора, это рассматривается как событие и результатом его будет сообщение Windows
. Как и для других управлений эти сообщения воспринимаются родительским окном блока выбора с соответствующей реакцией на них. Однако, вы можете сделать производный типы от TCheckBox и TRadioButton для выполнения ими некоторых действий при нажатии. Если в
аш тип определяет метод для nf_First+bn_Clicked, то он сначала должен вызывать метод реакции BNClicked, а уже затем выполнять любые дополнительные действия.
Конструирование блоков проверки и клавиш выбора
Конструктор Init для блоков проверки и клавиш выбора берет ID управления, текст, местоположение, размер и AGroup. AGroup это указатель на объект блока группы (см. "Блоки групп"), который используется для логического объединения блоков проверки или клавиш
 выбора. Если значение AGroup есть nil, то блок выбора не является частью какой-либо логической группы.
GroupBox1:=New(PGroupBox, Init(@Self, id_GB1, 'A Group Box', 38,
 102, 176, 108));
ChBox1:=New(PCheckBox, Init(@Self, id_Check1, 'Check Box Text',
 235, 12, 150, 26, GroupBox1));
Блоки проверки по умолчанию инициализируются со стилем  bs_AutoCheckBox, а кнопки выбора имеют стиль bs_AutoRadioButton. В соответствии с этими стилями только одна клавиша выбора в группе может проверяться в каждый момент времени. Если одна клавиша прове
ряется, то другие автоматически остаются непроверенными.
Если вы переопределяете стили объектов блоков проверки или клавиш выбора как "неавтоматические", то тогда уже вы отвечаете за их проверку или непроверку в ответ на произведенные пользователем нажатия. Например:
ChBox1^.Attr.Style:=ChBox1^.Attr.Style and not bs_AutiCheckBox or
 bs_CheckBox;
Запрос состояния блока проверки
Запрос к блоку выбора это один из способов выяснения его состояния и организации реакции на него. Кнопки выбора и блоки проверки имеют два состояния: проверенные и непроверенные. Для получения состояния блока выбора используется метод GetCheck типа TChec
kBox:
MyState:=Check1^.GetCheck;
Возвращаемое GetCheck значение можно сравнить с заданными константами bf_Unchecked, bf_Checked и bf_Grayed для определения состояния блока.
Модификация состояния блока выбора
Похоже на то, что изменение состояния блока выбора (проверен/непроверен) это скорее задача для пользователя вашей программы, а не для вас. Но в некоторых случаях вашей программе нужно направить управления через блок выбора. Одна из таких ситуаций состоит
 в том, что вам нужно, чтобы управление состоянием блока выбора отобразило ранее выбранные и сохраненные опции. Тип TCheckBox определяет четыре метода для модификации состояния блока проверки: Check, Uncheck, Toggle и в самом общем случае SetCheck.
Check форсированно устанавливает состояние блока проверки как проверен:
Check^.Check;
Uncheck форсированно устанавливает состояние блока проверки как непроверен:
Check^.Uncheck;
Toggle меняет состояние блока проверки с проверен на непроверен и наоборот. Для кнопки с тремя состояниями Toggle меняет непроверенный блок на проверенный, проверенный на серый, а серый на непроверенный.
CheckBox1^.Toggle;
SetCheck предоставляет вам полный контроль над состоянием блока проверки:
Check1^.SetCheck(0);     {Клавиша отмены проверки}
Check1^.SetCheck(1);     {Клавиша проверки}
Если эти методы используются для кнопок выбора, ObjectWinodws гарантирует проверку только одной кнопки из группы, если кнопки объединены в группу.
Блоки групп
В своей простейшей форме блок группы представляет собой статический прямоугольник с меткой, который обычно объединяет другие управления. Конструктор Init блока группы берет родительское окно, ID, текст, местоположение и размер:
GroupBox1:=New(PGroupBox, Init(@Self, id_GB1, 'A Group Box', 38,
 102, 176, 108));
Поскольку блок группы визуально связывает группу других управлений, он может логически связывать группу блоков выбора (блоков проверки или клавиш выбора). Логическая группа автоматически выполняет характеристики непроверки блоков автоматического выбора с
тиля.
Для своего добавления в группу, нужно при конструировании блока выбора указать указатель на блок группы.
Реакция на сообщения блока группы
Когда происходит событие, которое может сменить выбор блока группы (например, нажатие пользователем кнопки или вызов Check), родительское окно блока группы принимает сообщение, основанное на дочернем ID. Родитель воспринимает сообщение, используя сумму i
d_First и ID блока группы. Это позволяет вам определить методы для каждой группы вместо их задания для каждого блока выбора в группе.
Для определения управления в группе, на которое было оказано воздействие, вы можете прочитать текущее состояние каждого управления.
Пример программы: BtnTest
BtnTest это полная программа, которая создает окно с кнопкой нажатия, блоком проверки, кнопкой выбора и блоком группы управлений. После запуска приложения появляется головное окно с управлениями. Когда пользователь нажимает на управление, приложение реаг
ирует на это различными способами. См. Рис.12.6.
Рис.12.6. Окно с различными кнопками
Полный текст программы содержится в файле BTNTEST.PAS на ваших дистрибутивных дискетах.
Линейки прокрутки
Линейки прокрутки являются важнейшим механизмом изменения обзора пользователем окна приложения, блока списка или комбинированного блока. Однако, может возникнуть ситуация, когда нужна отдельная линейка прокрутки для выполнения некоторой специализированно
й задачи (например, управление температурой в программе термостата или цветом в программе рисования). Когда нужна отдельная специализированная линейка прокрутки используются объекты TScrollBar. Рис.12.7 показывает типичное использование объекта TScrollBa
r.
Рис.12.7. Объект линейки прокрутки
Конструирование линеек прокрутки
Конструктор Init линейки прокрутки берет родительское окно, ID, позицию (X и Y), ширину и высоту, и булевский флаг, определяющий будет ли линейка прокрутки иметь горизонтальное положение. Если для вертикальной линейки прокрутки задана ширина ноль, то она
 будет сконструирована со стандартной шириной, как для блока списка. Аналогично для нулевой высоты горизонтальной линейки прокрутки. Данный код:
ThermScroll:=New(PScrollBar, Init(@Self, id_ThermScroll, 20, 170,
 340, 0, True));
создает горизонтальную линейку прокрутки стандартной высоты, как это показано на Рис.12.7. Init конструирует линейки прокрутки со стилями ws_Child, ws_Visible и sbs_Horz или sbs_Vert для горизонтальной или вертикальной линейки прокрутки соответственно. В
ы можете задать дополнительные стили (например, sbs_TopAlign), сменив поле линейки прокрутки Attr.Style.
На Рис.12.8 показано множество объектов линейки прокрутки.
Рис.12.8. Окно с множеством линеек прокрутки
Один из атрибутов линейки прокрутки, инициализируемый при ее конструировании, это диапазон. Диапазон линейки прокрутки это набор всевозможных положений указателя. Указатель линейки прокрутки это подвижный прямоугольник, который пользователь может перемещ
ать по ней. Каждой позиции соответствует целое число. Родительское окно использует эту целую величину, позицию, для установки и запроса по линейке прокрутки. После конструирования объекта линейки прокрутки его диапазон устанавливается от 1 до 100. Положе
нию указателя в "самой верхней" позиции (вершина вертикальной линейки прокрутки или крайнее левое положение горизонтальной линейки прокрутки) соответствует позиция 1. "Самой нижней" позиции указателя соответствует позиция 100. Для установки иного диапазо
на нужно использовать метод SetRange, описанный в разделе "Модификация линеек прокрутки".
Два других атрибута объекта линейки прокрутки это его приращение по строкам и страницам. Приращение по строкам, установленное в 1, это расстояние в единицах диапазона, на которое переместится указатель при нажатии пользователем стрелок на линейке прокрут
ки. Приращение по страницам, установленное в 10, это расстояние в единицах диапазона, на которое переместится указатель при нажатии пользователем в области прокрутки. Эти значения можно изменить непосредственным манипулированием полями объекта TScrollBar
, LineSize и PageSize.
Запросы в линейках прокрутки
TScrollBar определяет два метода запросов в линейке прокрутки: GetRange и GetPosition. Метод GetRange это процедура, использующая два целых переменных аргумента. Процедура заносит в эти целые верхнюю и нижнюю позиции из диапазона линейки прокрутки. Этот 
метод очень удобен, когда нужно чтобы ваша программа переместила указатель в его верхнюю или нижнюю позицию.
GetPosition это функция, которая возвращает в виде целой величины позицию указателя. Ваша программа очень часто будет запрашивать диапазон и позицию и сравнивать их.
Модификация линеек прокрутки
Модификация линеек прокрутки это скорее работа для пользователя вашей программы, и часто это действительно так. Однако, ваша программа также может модифицировать линейку прокрутки. 
SetRange это процедура, которая берет два целых аргумента, наименьшую и наибольшую позицию диапазона. По умолчанию новая линейка прокрутки имеет диапазон от 1 до 100. Вы можете изменить этот диапазон для наилучшего расположения управлений линейки прокрут
ки. Например, линейка прокрутки в приложении для термостата может иметь диапазон от 32 до 120 градусов Фаренгейта. Нужно обязательно вызвать SetRange после создания вашего объекта линейки прокрутки:
procedure TParentWindowType.SetupWindow;
begin
 TWindow.SetupWindow;
 ThermScroll^.SetRange(32, 120);
end;
SetPosition это процедура, которая берет один целый аргумент, позицию, в которую нужно переместить указатель линейки прокрутки. В рассмотренном ранее приложении для термостата, ваша программа может непосредственно установить температуру 78 градусов:
ThermScroll^.SetPosition(78);
Третий метод DeltaPos передвигает позицию указателя линейки прокрутки вверх (налево) или вниз (направо) на величину, заданную целым аргументом. Положительная целая величина перемещает указатель вниз (направо). Отрицательная целая величина перемещает его 
вверх (налево). Например, для уменьшения температуры термостата на 5 градусов используется:
ThermScroll^.DeltaPos(-5);
Реакция на сообщения линеек прокрутки
При работе линейки прокрутки ее родительское окно получает от нее информационные сообщения. Если нужно, чтобы ваше окно реагировало на сообщения прокрутки, реакция на информационные сообщения должна быть обычной, путем определения методов реакции, основа
нных на дочерних ID. Однако, информационные сообщения линейки прокрутки несколько отличаются от других информационных сообщений управления. Они основаны на сообщениях Windows wm_HScroll и wm_VScroll, а не wm_Command. Единственное отличие, на которое нужн
о обратить внимание состоит в том, что коды информации линейки прокрутки записаны в Msg.wParam, а не в Msg.lParamHi. Чаще всего встречаются коды sb_LineUp, sb_LineDown, sb_PageUp, sb_PageDown, sb_ThumbPosition и sb_ThumbTrack. Наиболее часто вы будете ре
агировать на каждое событие проверкой новой позиции линейки прокрутки и организацией соответствующего действия. В данном случае вы можете игнорировать информационный код. Например,
procedure TestWindow.HandleThermScrollMsg(var Msg: TMessage);
var
 NewPos: Integer;
begin
 NewPos:=ThermScroll^.GetPosition;
 {Обработка с помощью NewPos.}
end;
Часто альтернатива состоит в том, чтобы не реагировать на  протягивание указателя до тех пор, пока пользователь не выберет его нового местоположения. В этом случае нужно реагировать на сообщение с кодом sb_ThumbTrack.
procedure TestWindow.HandleThermScrollMsg(var Msg: TMessage);
var
 NewPos: Integer;
begin
 if Msg.wParam <> sb_ThumbTrack
 then begin
  NewPos:=ThermScroll^.GetPosition;
  {Do some processing based on NewPos.}
 end;
end;
Иногда может потребоваться, чтобы объект линейки прокрутки сам реагировал на информационные сообщения линейки прокрутки, при этом конкретная реакция поведения должна быть встроена в объект линейки прокрутки. Для программирования объекта линейки прокрутки
, который непосредственно реагировал бы на его информационные сообщения, нужно определить для его типа метод реакции, основанный на информации. В качестве идентификатора заголовка метода нужно использовать сумму nf_First и информационного кода линейки пр
окрутки. Для этого создадим новый тип, производный от TScrollBar:
SpecializedSBar=object(TScrollBar)
 procedure SBTop(var Msg: TMessage); virtual nf_First+ sb_Top;
end;
procedure TSpecializedSBar.SBTop(var Msg: TMessaage);
begin
 TScrollBar.SBTop(Msg);
 {specialized haandling of scroll bar going to top}
 Msg.Result:=1;
end;
Если вы не хотите, чтобы родительское окно линейки прокрутки воспринимало информационное сообщение после его обработки линейкой прокрутки, установите результат сообщения (Msg.Result) равным 1. Если вы не установите такой результат, родительское окно лине
йки прокрутки может выполнить дополнительную обработку сообщения.
Обратите внимание на то, что метод TSpecializedSBar.SBTop сначала вызывает TScrollBar.SBTop. Этот метод отвечает за физическое изменение позиции линейки прокрутки. TScrollBar имеет методы SBLineUp, SBLineDown, SBPageUP, SBPageDown, SBThumbPosition, SBThu
mbTruck, SBTop и SBBottom для обработки сообщений: (nf_First+)sb_LineUp, sb_LineDown, sb_PageUP, sb_PageDown, sb_ThumbPosition, sb_ThumbTruck, sb_Top и sb_Bottom, соответственно. Если вы хотите добавить некоторые дополнительные черты поведения, сначала в
ызывайте унаследованный специализированный метод линейки прокрутки. Если вы его не вызовете, то ваш метод будет отвечать за сдвиг линейки прокрутки.  
Пример: SBarTest
Программа SBarTest создает приложение для термостата, показанное на Рис.12.7.
Полный текст программы содержится в файле SBARTEST.PAS на ваших дистрибутивных дискетах.



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