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



 

Часть 7

Глава 6. Всплывающие окна
Теперь вы готовы добавить завершающий штрих к вашей программе ObjectWindows, систему подсказок. Систему подсказок можно рассматривать как программу внутри программы, к которой можно моментально обратиться. Одно из преимуществ программ Windows состоит в т
ом, что несмотря на множество самых различных окон, многие действия можно унифицировать. Добавление системы подсказок к MyProgram покажет, как разрабатывать программы ObjectWindows на модульном принципе, повышая степень повторного использования решений и
 облегчая обслуживание программ.
Шаг 10: Всплывающее окно подсказки
На Шаге 8 вы добавили меню Help к головному окну MyProgram. Если выбрать этот вариант из меню, то появится пустое окно, объект типа TWindow. В данном разделе мы заменим это пустое окно на полезное окно подсказок, которое использует некоторые элементы сис
темы управления Windows, обеспечиваемые ObjectWindows: блоки списков, линейки прокрутки, управление редактированием и статикой, кнопки и комбинированные блоки. В процессе своей разработки система подсказок будет определена как модуль, требующий незначите
льных изменений для своего использования в других ваших программах. На Рис.6.1 показана законченная система подсказок, которая дает краткие описания каждого из элементов управления, поддерживаемых ObjectWindows.
Рис.6.1. Система подсказок MyProgram
Использование модулей с ObjectWindows
Модуль Turbo Pascal служит очень удобным механизмом для хранения определений объектов или групп связанных объектов. Это особенно важно для программирования в среде Windows, поскольку вы наверняка пожелаете повторно использовать окна (объекты окон в Objec
tWindows) из одного приложения в другом. Здесь вы построите вашу систему подсказок как тип объекта с именем THelpWindow и сохраните его определение в модуле с именем HelpWind.
Модификация головной программы
В MyProgram требуется внести только два изменения:
- Добавить модуль HelpWind к оператору uses.
- Удалить весь код, устанавливающий атрибуты HelpWind из   TMyWindowHelp. Этот код будет теперь находится в THelpWindow.Init.
Теперь, когда пользователь выбирает элемент меню Help, MyProgram отреагирует на это воспроизведением THelpWindow. Это значит, что нужно определить тип THelpWindow. Вы сделаете это в модуле HelpWind.
Создание модуля
Модуль HelpWind будет только определять интерфейс и реализовывать тип THelpWindow. Однажды созданный, этот модуль может быть использован любой другой программой ObjectWindows. Это будет модуль окна. Приведем формат этого модуля (пропуски будут заполнены 
позднее):
unit HelpWind;
Interface
uses Strings, WinTypes, WinProcs, Wobjects;
const
 id_LB1=201;
 id_BN1=202;
 id_BN2=203;
 id_EC1=204;
 id_ST1=205;
type
 PHelpWindow=^HelpWindow;
 THelpWindow=object(TWindow)
  LB1: PListBox;
  EC1: PEdit;
  constructor Init(AParent: PWindowsObject; ATitle: PChar);
  procedure SetupWindow; virtual;
  procedure IDLB1(var Msg: TMessage); virtual id_First+id_LB1;
  procedure IDBN1(var Msg: TMessage); virtual id_First+id_BN1;
  procedure IDBN2(var Msg: TMessage); virtual id_First+id_BN2;
  procedure FillEdit(SelStringPtr: PChar); virtual;
end;
Implementation
constructor THelpWindow.Init(Aparent: PWindowsObject; ATitle: PChar);
begin
 ...
end;
procedure THelpWindow.SetupWindow;
begin
 ...
end;
procedure THelpWindow.IDLB1(var Msg: TMessage);
var
 ...
begin
 ...
end;
procedure THelpWindow.IDBN1(var Msg: TMessage);
var
 ...
begin
 ...
end;
procedure THelpWindow.IDBN2(var Msg: TMessage);
var
 ...
begin
 ...
end;
procedure THelpWindow.FillEdit(SelStringPtr: PChar);
var
 ...
begin
 ...
end;
end.
Поскольку приложение ObjectWindows содержит HelpWind в списке оператора uses, оно может инициализировать тип THelpWindow, определяя переменные типа PHelpWindow.
Дополнительное управление окном
На Шаге 8 вы узнали, что имеется два типа дочерних окон: зависимые и независимые. В том разделе мы добавили к головному окну два типа независимых дочерних окон: диалоги и всплывающие окна. Теперь вы добавите зависимое дочернее окно с именем control (упра
вление). Родительским окном для этого управления будет окно подсказок. Следует помнить о том, что окно подсказок это независимое дочернее окно, а родительским окном для него служит головное окно вашего приложения. Следовательно, ваше окно подсказок будет
 одновременно и дочерним и родительским окном. Это допускается и даже необходимо для приложения Windows любой сложности.
Что такое управление ?
Управление это визуальные устройства, которые составляют часть или весь интерфейс пользователя с окном или блоком диалога. Например, кнопки Save и Open блоков диалога являются управлением, также как и комбинированные блоки, используемые для отображения ф
айлов. Головное окно MyProgram не имеет управления, но здесь мы добавим некоторые его элементы к нашему окну подсказок.
Имеется много типов управления, включая блоки списков, линейки прокрутки, управление редактированием и статикой, кнопки и комбинированные блоки. На вашем окне подсказок, изображенном на Рис.6.1, используется блок списка (большой блок в верхней половине о
кна), управление редактированием (большой блок в нижней половине окна), управление статикой (текст "Help Information" - "Справочная Информация"), и две кнопки (Help и Cancel). Линейки прокрутки являются частью и управления редактированием и блока списка,
 но нет объектов линейки прокрутки. Они большей частью используются в качестве необязательной части других управлений и окон и редко появляются в качестве автономных управлений.
Тип TControl в ObjectWindows задает управление для всех управлений в целом и его производные типы обрабатывают каждый тип управления. Например, TListBox определяет объекты блока списка, а TEdit определяет объекты управления редактированием. Надо также ос
ознавать тот факт, что TControl происходит от TWindow. Управления на самом деле являются специализированными окнами. 
Создание управления окном
Хотя действие их и идентично, есть важное программное отличие между управлениями в блоках диалога (например, диалог файла) и управлениями в окнах (например, окно подсказок). Управления блоком диалога задаются в ресурсе диалога. Они не являются объектами 
и владеющие ими блоки диалога полностью отвечают за их работу. Глава 5 показывает, как создавать свои собственные диалоги из ресурсов диалога и как обрабатывать их управления.
Однако, управления окном задаются определениями объектов. Родительское окно контролирует свои управления через богатый набор методов, определенных объектами управления ObjectWindows. Например, для получения элемента текста пользователь сделал выбор в бло
ке списка, вызвав метод GetSelString объекта блока списка. Подобно окну или объекту блока диалога объект управления имеет соответствующий визуальный элемент. Объект управления и его элемент управления компонуются через поле ID объекта управления. Каждое 
управление имеет уникальный ID, который используется его родительским окном для идентификации управления при обработке событий управления, например, нажатие пользователем кнопки на мыши. Для ясности вы должны определить константы для каждого ID
управления:
const
 id_LB1=201;   (ID для блока списка 1)
 id_BN1=202;   (ID для первой клавиши (OK))
 id_BN2=203;   (ID для второй клавиши (Cancel))
 id_EC1=204;   (ID для управления редактированием)
 id_ST1=205;   (ID для статичного текста)
Объекты управления как поля
Иногда бывает очень удобно хранить указатель на объект управления (или другое дочернее окно) как поле в объекте окна. Это необходимо лишь для дочерних окон, которыми в последствии будут манипулировать непосредственно вызовом их методов объекта. Данный сл
учай имеет отличия только для блока списка и управления редактированием. THelpWindow будет хранить каждый из этих объектов управления в отдельном поле. Приведем часть определения объекта THelpWindow:
THelpWindow=object(TWindow)
 LB1: PListBox;
 EC1: PEdit;
 ...
end;
После того, как эти дочерние объекты управления установлены, вы можете манипулировать ими через вызовы методов. Например, можно добавить строку к списку LB1 через вызовы LB1^.AddString. Можно получить доступ к объектам управления для дочерних окон, котор
ые не хранятся в качестве полей, используя ChildList родительского окна, но все же более удобно это делать с полями.
Контроль за управлением
Каждый тип окна, который имеет объекты управления должен определить конструктор, Init, для конструирования его объектов управления. Кроме того, он может переписывать SetupWindow для установки управлений до отображения. Родительское окно (THelpWindow) авт
оматически создает и отображает все свои дочерние окна.
Ниже приведен метод Init окна подсказок. Первое, что он делает, это устанавливает атрибуты своего местоположения и размеры. Поскольку метод Init окна отвечает за установку своих собственных атрибутов создания и поскольку его управления созданы вместе с н
им, вы обязательно должны сконструировать его управления в его Init. Родительское окно (@Self) есть первый параметр в каждом вызове конструктора управления. ID управления есть второй параметр в каждом вызове конструктора управления.
constructor THelpWindow.Init(AParent: PWindowsObject; ATitle: PChar);
var
 TempStat: PStatic;
 TempBtn: PButton;
begin
 TWindow.Init(AParent, ATitle);
 DisableAutoCreate;
 Attr.Style:=ws_PopupWindow or ws_Caption or ws_Visible;
 Attr.X:=100;
 Attr.Y:=100;
 Attr.W:=300;
 Attr.H:=300;
 LB1:=New(PListBox, Init(@Self, id_LB1, 20, 20, 180, 80));
 TempBtn:=New(PButton, Init(@Self, id_BN1, 'Help', 220, 20, 60,
  30, True));
 TempBtn:=New(PButton, Init(@Self, id_BN2, 'Cancel', 220, 70, 60,
  30, False));
 EC1:=New(PEdit, Init(@Self, id_EC1, 'Cancel', 20, 180, 260, 90,
  0, True));
 EC1^.Attr.Style:=EC1^Attr.Style or ws_Border or ws_VScroll;
 TempStat:=New(PStatic, Init(@Self, id_ST1, 'Help Information:',
  20, 160, 160, 20, 0));
end;
Вслед за созданием окна вызывается THelpWindow.SetupWindow для установки управлений окна. Для добавления элементов в блок списка будут использоваться модификации методов TListBox, например, AddString. Переписывая метод окна SetupWindow нужно быть уверенн
ым в том, что сначала вызывается метод TWindow.SetupWindow, т.к. он создает все дочерние управления.
procedure THelpWindow.SetupWindow;
begin
 TWindow.SetupWindow;
 {Завполнить рамку со списком}
 LB1^.AddString('ListBoxes');
 LB1^.AddString('Buttons');
 LB1^.AddString('Scroll Bars');
 LB1^.AddString('Edit Controls');
 LB1^.AddString('Static Controls');
 LB1^.AddString('Combo Boxes');
 LB1^.SetSelIndex(0);
end;
Использование методов Init и SetupWindow вполне достаточно для получения корректного отображения всех управлений в окне подсказок. Блок списка будет прокручиваться и кнопки нажиматься, но никаких действий производиться не будет. В последующем разделе вы 
определите реакцию на управляющие события.
Реакция на события управления
В данный момент в окне подсказок видны управления, но нажатия кнопок и выбор элементов из блока списка не производят никакого эффекта. Это происходит потому, что мы имеем дело с управляющими событиями. Они очень похожи на события меню, реакцию на которые
 вы  отработали на Шаге 7.
Вы реагировали на события меню определением методов реакции  командных сообщений, и здесь вы сделаете аналогично с сообщениями  управления. Однако, события управления воспроизводят события, основанные на дочерних ID. Для идентификации заголовка метода, о
снованного на дочернем ID нужно использовать сумму ID управления и константы id_First. Для ясности присвоим этим методам реакции на сообщения имена вида IDLB1. Приведем определение типа THelpWindow, показывающее заголовки метода:
THelpWindow=object(TWindow)
 LB1: PListBox;
 EC1: PEdit;
 constructor Init(AParent: PWindowsObject; ATitle: PChar);
 procedure SetupWindow; virtual;
 procedure IDLB1(var Msg: TMessage); virtual id_First+id_LB1;
 procedure IDBN1(var Msg: TMessage); virtual id_First+id_BN1;
 procedure IDBN2(var Msg: TMessage); virtual id_First+id_BN2;
 procedure FillEdit(SelStringPtr: PChar); virtual;
end;
Теперь определим, как THelpWindow следует реагировать на события управления. Когда пользователь выбирает кнопку Cancel (BN2), окно должно закрываться. Т.о. реализация IDBN2 будет самой простой:
          procedure THelpWindow.IDBN2(var Msg: TMessage); 
          begin
               Destroy;
          end;
Однако, когда пользователь выбирает кнопку OK (BN1), MyProgram должна проверять, какой блок списка выбран и заполнить управление редактированием (EC1) соответствующим текстом. Т.о. IDBN1 вызывает GetSelString для блока списка (LB1) для получения текста в
ыбранного элемента списка. Текст передается к методу FillEdit, который вы еще должны написать. Определение FileEdit приводится полностью в конце данного шага.
procedure THelpWindow.IDLB1(var Msg: TMessage); 
var
 selString: array[0..25] of Char;
begin
 LB1^.GetSelString(SelString, 25);
 FileEdit(SelString);
end;
Кроме того, можно отреагировать на сообщение, которое генерируется при двойном нажатии кнопки на мыши, установленной на элементе списка, заполнением текстом управления редактированием. Однако, блок списка может генерировать множество сообщений (называемы
ми информационными сообщениями блока списка) в ответ на нажатие, двойное нажатие, прокрутку и др. Для того, чтобы различать все эти сообщения, вы определите IDLB1 для проверки Mgs.LParamHi, в котором хранится информация от блока списка. Если его значение
 lbn_DblClk, то пользователь осуществил двойное нажатие. Все другие коды вы будете игнорировать, они потом по умолчанию будут обработаны процедурой DefWinProc.
procedure THelpWindow.IDLB1(var Msg: TMessage); 
var
 selString: array[0..25] of Char;
begin
 if Msg.LParamHi=lbn_DblClk then
 begin
  LB1^.GetSelString(SelString, 25);
  FileEdit(SelString);
 end;
 else DefWndProc(Msg);
end;
Объекты управления ObjectWindows обеспечивают множество методов запросов и модификации. Вызов этих методов в ответ на события управления оживит ваши окна, как вы это проделали с окном подсказок.



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