Глава 10. Объекты окон
Объекты окон (или оконные объекты) - это интерфейсные объек-
ты, предназначенные для облегчения работы с окнами. В данной гла-
ве поясняется, как создавать и заполнять окна приложения. Это
предусматривает следующие задачи:
* Инициализацию оконных объектов.
* Установку атрибутов создания.
* Создание экранных элементов окна.
* Установку атрибутов регистрации.
* Использование специализированных окон.
* Прокрутку окон.
Что такое объекты окон?
-----------------------------------------------------------------
Термин "объект окна" относится к любому интерфейсному объек-
ту, представляющему окно, а в Windows это почти все, что выводит-
ся на экран. В качестве шаблона определения большей части фунда-
ментального поведения основного окна и любого всплывающего окна
приложения ObjectWindows использует тип TWindow.
Окна, которые не являются окнами
-----------------------------------------------------------------
TWindow имеет три типа-потомка: TMDIWindow, TControl и
TEditWindow, так что все они также являются оконными объектами,
хотя на самом деле это не окна в полном смысле слова. Типы MDI
используются в приложениях ObjectWindows, которые соответствуют
стандарту многодокументального интерфейса Windows. Об MDI и этих
типах рассказывается в Главе 14. TControl определяет управляющие
элементы, такие как командные кнопки и блоки списков (см. Главу
12). Чаще всего новые оконные типы являются производными от
TWindow.
Эта глава охватывает типы TWindow и TEditWindow и содержит
примеры регистрации новых классов окон.
Где найти объекты окон
-----------------------------------------------------------------
Каждое приложение Windows имеет основное окно. Это окно мо-
жет выводиться в виде пиктограммы или не выводиться снова (скры-
тое окно), но существует всегда. Приложения ObjectWindows не яв-
ляются исключением: они должны иметь основное окно, представлен-
ное оконным объектом.
Примером минимальной программы ObjectWindows ("скелета"
программы) является TestApp в Главе 8. Основное окно программы
ObjectWindows является обычно экземпляром TWindow или определяе-
мого в программе наследующего типа. Многие приложения имеют дру-
гие окна, которые обычно являются дочерними окнами основного ок-
на. Эти дополнительные окна также являются экземплярами TWindow
или одного из его потомков.
Например, графическая программа может определять для своего
основного окна тип TPaintWindow, а для окна, показывающего графи-
ческий рисунок - тип TZoomWindow. В этом случае TPaintWindow и
TZoomWindow являются наследниками TWindow.
Инициализация объектов окон
-----------------------------------------------------------------
Оконные объекты представляют элементы окна, связанные через
описатели, сохраненные в наследуемом из TWindowsObject поле
HWindow. Так как объект окна имеет две части, его создание требу-
ет двух шагов: инициализации объекта и создания визуального эле-
мента.
Инициализация окна - это процесс создания оконного объекта
ObjectWindows путем вызова конструктора Init:
Window1 := New(PWindow,Init(nil, 'Заголовок окна 1'));
Window2 := New(PNewWindowType,Init(nil,'Заголовок окна 2'));
Init создает новый оконный объект и устанавливает поле Title
в Attr в передаваемый аргумент PChar. Первый аргумент вызова Init
- это оконный объект порождающего окна. Если окно является основ-
ным окном (не имеющим порождающего окна), то это nil.
Установка атрибутов создания
-----------------------------------------------------------------
Типичное приложение Windows имеет много различных типов
окон: перекрывающиеся или всплывающие, окна с рамкой, прокручива-
емые окна, окна с заголовком и др. Эти атрибуты стилей, а также
заголовок и меню окна задаются при инициализации оконного объекта
и используются при создании элементов окна.
Атрибуты создания оконного объекта, такие как стиль, заголо-
вок и меню, записываются в поле Attr объекта - записи типа
TWindowAttr. TWindowAttr содержит следующие поля:
Атрибуты создания окна Таблица 10.1
+------------+--------------+-----------------------------------+
| Поле | Тип | Использование |
+------------+--------------+-----------------------------------|
| Title | PChar | Строка заголовка. |
| | | |
| Style | Longint | Комбинированная константа стиля. |
| | | |
| Menu | HMenu | Описатель ресурса меню. |
| | | |
| X | Integer | Горизонтальная координата экрана|
| | | верхнего левого угла окна. |
| | | |
| Y | Integer | Вертикальная координата экрана|
| | | верхнего левого угла окна. |
| | | |
| W | Integer | Начальная ширина окна в координа-|
| | | тах экрана. |
| | | |
| H | Integer | Начальная высота окна в координа-|
| | | тах экрана. |
| | | |
+------------+--------------+-----------------------------------+
^################################################################
#(0,0)###########################################################
#####(X,Y)#######################################################
#####v###########################################################
#####+---------------------------------------+--+--+--###########
#####| XXXXXXXXXXXXXXXX Title XXXXXXXXXXXXXX| | | ^###########
#####+---------------------------------------+--+--| |###########
#####| Menu | |###########
#####+---------------------------------------------| |###########
#####| | |###########
#####| | |###########
#####| | H###########
#####| | |###########
#####| | |###########
#####| | |###########
#####| | |###########
#####| | |###########
#####| | v###########
#####+---------------------------------------------+--###########
#####|<------------------W------------------------>|#############
#################################################################
#################################################################
Рис. 10.1 Атрибуты окна.
Используемые по умолчанию атрибуты окна
-----------------------------------------------------------------
По умолчанию TWindow.Init устанавливает Attr.Style в
ws_Visible. Если окно является основным окном приложения, то
Style равно ws_OverlappedWindow or ws_Visible.
Menu по умолчанию устанавливается в 0. Это означает, что ме-
ню не определено.
X, Y, W и H устанавливаются в cw_UseDefault, что дает в ре-
зультате перекрывающееся окно удовлетворительного размера. Когда
создается окно, не являющееся основным, значения X, Y, W и H вы
обычно устанавливаете сами.
Переопределение используемых по умолчанию атрибутов
-----------------------------------------------------------------
При создании новых оконных типов, производных от TWindow, вы
обычно определяете новый конструктор Init (особенно если хотите
получить атрибут создания, отличных от используемого по умолча-
нию). Если вы хотите переопределить Init, то можете заново задать
атрибуты объекта, непосредственно изменяя поле Attr после вызова
Init.
Если вы переопределили Init, убедитесь, что первое, что он
делает - это вызов наследуемого метода TWindow.Init, устанавлива-
ющего используемые по умолчанию атрибуты. Затем вы можете изме-
нить по своему выбору любой из атрибутов. Например, типичное окно
может определять конструктор Init, который устанавливает атрибут
Menu:
constructor TWindowType.Init(AParent: PWindowsObject;
ATitle: PChar);
begin
inherited Init(AParent, ATitle);
Attr.Menu := LoadMenu(HInstance, 'TheMenu');
AChildWindow := New(PChildWindowType, Init(@Self,
'Заголовок дочернего окна'));
List1 := New(PListBox, Init(@Self, id_ListBox,
201, 20, 20, 180, 80));
.
.
.
end;
Атрибуты порожденного окна
-----------------------------------------------------------------
Конструктор TWindowType отвечает за построение его дочерних
объектов, таких как всплывающие окна и блоки списка. Тип порож-
денного окна, в свою очередь, может устанавливать атрибуты в сво-
ем собственном конструкторе Init:
constructor TChilwWindowType.Init(AParent: PWindowsObject;
ATitle: PChar);
begin
inherited Init(AParent, ATitle);
with Attr do
begin
Style := Style or ws_PopupWindow or ws_Caption;
X := 100; Y := 100; W := 300; H := 300;
end;
end;
В качестве альтернативы вы можете не определять потомка
типа окна, а сначала построить объект окна, а затем переустано-
вить его атрибуты (все это в конструкторе Init порождающего ок-
на):
constructor TWindowType.Init(AParent: PWindowsObject;
ATitle: PChar);
begin
inherited Init(AParent, ATitle);
Attr.Menu := LoadMenu(HInstance, 'TheMenu');
AChildWindow := New(PChildWindowType, Init(@Self,
'Заголовок дочернего окна'));
with Attr do
begin
Style := Style or ws_PopupWindow or ws_Caption;
X := 100; Y := 100; W := 300; H := 300;
end;
.
.
.
end;
Создание элементов окна
-----------------------------------------------------------------
После построения оконного объекта вам нужно сообщить
Windows, что требуется создать связанные с объектом элементы эк-
рана. Это делается с помощью вызова MakeWindow объекта приложения
и передачи ему в качестве параметра указателя на объект окна.
if Application^.MakeWindow(AWindow) <> nil then
{ успешное создание }
else { неуспешное создание }
MakeWindow вызывает два важных метода: ValidWindow и Create.
ValidWindow проверяет успешность построение объекта окна, прове-
ряя поле Status. Если по каким-либо причинам конструктор завер-
шился неуспешно, то MakeWindow возвращает nil. При успешном вы-
полнении конструктора MakeWindow переходит на метод Create окон-
ного объекта.
Create - это метод, который фактически сообщает Windows о
создании элемента экрана. Если Create завершается неудачно,
MakeWindow возвращает nil. В противном случае возвращается указа-
тель на оконный объект. Для работы с элементом экрана Create так-
же устанавливает поле HWindow.
Хотя этот метод фактически создает элемент экрана, вы обычно
не можете вызывать Create явно. Основное окно приложения автома-
тически создается при запуске программы методом
TApplication.InitInstance.
Все прочие окна приложения являются дочерними окнами, прямо
или косвенно порождаемыми основным окном, а дочерние окна созда-
ются обычно в методе SetupWindow или в его порождающих оконных
объектах, либо с помощью MakeWindow динамически на этапе выполне-
ния.
Примечание: Дочерние окна и SetupWindow описываются в
Главе 9 "Интерфейсный объекты".
В общем случае порождающие окна обычно вызывают для своих
дочерних окон методы Init и MakeWindow. Атрибуты оконного объекта
обычно устанавливаются их методами объекта порождающего окна.
Поскольку основное окно приложения не имеет порождающего окна,
объект приложения строит и создает его при запуске приложения.
Задание атрибутов регистрации
-----------------------------------------------------------------
В ходе инициализации оконного объекта путем заполнения поля
объекта Attr вы можете установить несколько атрибутов окна, такие
как его стиль, расположение и меню. Эти атрибуты используются для
создания соответствующего оконного элемента, поэтому они называ-
ются атрибутами создания.
Другие атрибуты, включая фоновый цвет, пиктограмму представ-
ления и курсора "мыши", более тесно связаны с данным типом окон-
ного объекта и не могут изменяться в ходе работы программы. Эти
присущие окну атрибуты называются атрибутами регистрации, так как
они устанавливаются при регистрации класса окна в Windows.
Классы окон
-----------------------------------------------------------------
С каждым типом оконного объекта связан список атрибутов ре-
гистрации, которые называются классом окна. Список атрибутов ре-
гистрации во многом напоминает список атрибутов создания, запи-
санных в поле записи Attr объекта окна. Однако, атрибуты регист-
рации сохраняются в записи с именем TWndClass, который определя-
ется и поддерживается Windows.
Процесс связи класса окна с типом оконного объекта называет-
ся регистрацией класса окна. ObjectWindows автоматизирует процесс
регистрации. Таким образом, если вы хотите изменить какую-либо из
используемых по умолчанию характеристик объекта, то можете не
беспокоиться о классе регистрации окна.
Поля записи TWndClass и их типы перечислены в следующей таб-
лице:
Атрибуты регистрации окна Таблица 10.2
+-------------------------+-------------------+-----------------+
| Характеристика | Поле | Тип |
+-------------------------+-------------------+-----------------|
| стиль класса | style | Word |
| пиктограмма | hIcon | HIcon |
| курсор | hCursor | HCursor |
| фоновый цвет | hbrBackground | HBrush |
| меню по умолчанию | lpszMenuName | PChar |
+-------------------------+-------------------+-----------------+
Поля стиля класса
Это поле стиля отличается от атрибута стиля окна (ws_), за-
даваемого при инициализации окна, поскольку задает поведение,
присущее операциям окна (в отличие от их визуального представле-
ния). Это поле может заполняться комбинацией констант стиля
(cs_).
Например, cs_HRedraw приводит к повторному отображению окна
при изменении его размера по горизонтали; cs_DoubleClk позволяет
окну получать сообщения о двойном нажатии кнопки "мыши";
cs_NoClose предотвращает выбор параметра Close меню Control, а
cs_ParentDC дает окну контекст дисплея порождающего окна.
Поле пиктограммы
Это поле содержит описатель пиктограммы, которое использует-
ся для представления окна в его минимизированном состоянии. Обыч-
но для представления основного окна программы выбирается ресурс
пиктограммы.
Поле курсора
Поле hCursor содержит описатель курсора, который использует-
ся для представления указателя "мыши" при позиционировании его в
окне.
Поле фонового цвета
Это поле задает фоновый цвет окна. Для большинства приложе-
ний используется стандартный назначаемый по умолчанию цвет окна,
который может устанавливаться пользователем в управляющей панели.
Однако вы можете путем установки этого поля в описатель физичес-
кой кисти подставить конкретный цвет. Либо вы можете установить
любое из значений цветов Windows, такие как color_ActiveCaption.
К любому значению цвета всегда добавляйте 1.
Поле используемого по умолчанию меню
Это поле указывает на имя ресурса меню, которое служит ис-
пользуемым по умолчанию меню для данного класса. Например, если
вы определите тип EditWindow, который всегда имеет стандартное
меню редактирования, то можете задать здесь это меню. Это устра-
нит необходимость задания меню в методе Init. Если данный ресурс
меню имеет идентификатор 'MyMenu', вы можете установить это поле
следующим образом:
AWndClass.IpszMenuName := 'MyMenu';
Используемые по умолчанию атрибуты регистрации
-----------------------------------------------------------------
Тип TWindow определяет класс окна 'TurboWindow' с пустой
пиктограммой, курсором-стрелкой и стандартным цветом окна. Ис-
пользуемый по умолчанию класс ObjectWindows (TurboWindow) имеет
следующие атрибуты:
* стиль: cs_HRedraw or cs_VRedraw (повторное отображение
после каждого изменения размера);
* пиктограмма: idi_Application (пустой прямоугольник);
* курсор: idc_Arrow (стандартная стрелка Windows);
* фоновый цвет: HBrush(color_Window + 1);
* меню по умолчанию: nil.
Регистрация нового класса
-----------------------------------------------------------------
Чтобы изменить атрибут регистрации, такой как курсор или
пиктограмму, вам нужно написать два метода - GetClassName и
GetWindowClass - и определить новый класс окна. Каждый раз, когда
вы изменяете атрибуты регистрации, вам нужно изменить имя класса.
Если класс регистрации с данным именем уже зарегистрирован в
Windows, другие классы с тем же именем класса регистрироваться не
будут - они получат атрибуты уже зарегистрированного класса.
Изменение имени класса
-----------------------------------------------------------------
GetClassName - это функция, которая возвращает имя (PChar)
класса окна. TWindow.GetClassName возвращает 'TurboWindow', имя
используемого по умолчанию класса окна. TWindow.GetClassName
возвращает 'TurboWindow' - имя используемого по умолчанию класса
окна:
function TWindow.GetClassName: PChar;
begin
GetClassName := 'TurboWindow';
end;
Чтобы определить тип объекта окна с именем IBeamWindow, ко-
торый использует вместо стандартной стрелки I-образный курсор,
переопределите наследуемый метод следующим образом:
function TBeamWindow.GetClassName: PChar;
begin
GetClassName := 'IBeamWindow';
end;
Примечание: Имя класса не обязательно должно соответс-
твовать имени объектного типа.
Имя класса должно быть уникальным.
Определение новых атрибутов регистрации
-----------------------------------------------------------------
Чтобы отклониться от стандартных характеристик, вы должны
заполнить поля записи TWndClass с различными данными в методе
GetWindowClass.
GetWindowClass воспринимает в качестве аргумента-переменной
запись TWndClass и заполняет ее поля новыми атрибутами регистра-
ции. Когда вы определяете новый метод GetWindowClass, вам следует
всегда сначала для установки значений по умолчанию вызывать нас-
ледуемый метод TWindow.GetWindowClass, а затем устанавливать по-
ля, которые вы хотите изменить.
Например, в поле hCursor хранится описатель ресурса курсора.
Для IBeamWindow определяется метод GetWindowClass:
procedure IBeamWindow.GetWindowClass(var AWndClass:
TWndClass);
begin
inherited GetWindowClass(AWndClass);
AWndClass.hCursor := LoadCursor(0, idc_IBeam);
end;
Примечание: idc_Beam - это константа, представляющая
один из курсоров Windows.
Кроме окон, диалоговым окнам (не диалоговым блокам) необхо-
димо регистрировать классы окна (см. Главу 11). Диалоговым блокам
и управляющим элементам классы окон не требуются.
Использование специализированных окон
-----------------------------------------------------------------
ObjectWindows предусматривает два потомка TWindow, являющих-
ся специализированными окнами для редактирования текста. Объект-
ный тип TEditWindow обеспечивает простой текстовый редактор, не
обладающий возможностями чтения из файла или записи в него. Тип
TFileWindow, наследующий из TEditWindow, обеспечивает текстовый
редактор с возможностями чтения/записи файлов.
Эти объекты можно использовать непосредственно как стандарт-
ные компоненты ваших приложений. Вы можете также построить произ-
водные от них типы и создать свои собственные специализированные
редакторы. Программы или модули, использующие окна редактирования
или файловые окна, должны включать в свой оператор uses модуль
OStdWnds.
Использование окон редактирования
-----------------------------------------------------------------
Окно редактирования - это окно с управляющим элементом ре-
дактирования, заполняющим его область клиента. TEditWindow.Init
инициализирует поле Editor окна редактирования, чтобы оно указы-
вало на управляющий элемент объекта редактирования.
TEditWindow.SetupWindow устанавливает размеры управляющего эле-
мента редактирования в соответствии с областью клиента окна и
создает экранный управляющий элемент редактирования.
Метод WMSize обеспечивает изменение размера управляющего
элемента редактирования при изменении размера его окна. Метод
WMSetFocus обеспечивает, что управляющий элемент редактирования
получает фокус ввода при получении окном сообщения wm_SetFocus.
Показанная ниже программа EditWindowTester использует окно
редактирования, чтобы пользователь мог редактировать текст для
простой (нефункциональной) электронной почты.
+-----------------------------------------------------------+-+-+
|#=#XXXXXXXXXXXXXXXXXXXXEdit Window TesterXXXXXXXXXXXXXXXXXX|^|v|
+-----------------------------------------------------------+-+-|
| Edit Text |
+---------------------------------------------------------------|
| Кого это может касаться: |
| |
| Я хотел бы зарегистрировать жалобу по поводу попугая, которого|
| я купил в вашем магазине полгода назад. Он умер. |
| +-----------------------------------+ |
| Брюс |#=#@@@@@@Передано сообщение@@@@@@@@| |
| +-----------------------------------| |
| | | |
| | 6 строк послано | |
| | +------------+ | |
| | |####OK######| | |
| | +------------+ | |
| +-----------------------------------+ |
| |
+---------------------------------------------------------------+
Рис. 10.2 Окно редактирования.
program EditWindowTester;
{$R EWNDTEST.RES}
uses ODialogs, WinTypes, WinProcs, Strings, OStdWnds;
const cm_sendText = 399;
type
TestApplication = object(TApplication)
procedure InitMainWindow; virtual;
end;
PMyEditWindow = ^MyEditWindow;
MyEditWindow = object(TEditWindow)
constructor Init(AParent: PWindowsObject;
ATitle: PChar);
procedure CMSendText(var Msg: TMessage); virtual
cm_First + cm_SendText;
end;
constructor MyEditWindow.Init(AParent: PWindowsObject;
Atitle: PChar);
begin
inherited Init(AParent, ATitle);
Attr.Menu := LoadMenu(HInstance, MakeIntResource(102));
end
procedure MyEditWindows.CMSendText(var Msg: TMessage);
var
Lines: Integer;
TestString: string[3];
Text: array[020] of Char;
begin
Lines := Editor^.GetNumLines;
Str(Lines, TextString);
StrCat(Text, ' строк послано');
MessageBox(HWindow, @Text, 'Передано сообщение', mb_Ok);
end;
procedure TestApplication.InitMainWindow;
begin
MainWindow := New(PMyEditWindow, Init(nil,
'Окно редактирования - попробуйте набор и редактирование'));
end;
var TestApp: TestApplication;
begin
TestApp.Init('EditWindowTester');
TestApp.Run;
TestApp.Done;
end.
Использование файловых окон
-----------------------------------------------------------------
Файловое окно - это окно редактирования с дополнительными
возможностями, позволяющими считывать и записывать данные в файл.
TFileWindow.Init воспринимает в качестве аргумента заголовок окна
и устанавливает поле FileDialog таким образом, чтобы оно указыва-
ло на файловый диалоговый объект.
Для работы с файлами TFileWindow имеет четыре метода. Методы
Open, Save и SaveAs для вывода пользователю подсказки с именем
файла используют поле TFileWindow.FileDialog (см. Главу 11). Ме-
тод New дает пользователю возможность отмены, если редактирование
нового файла приведет к потере изменений текущего текста. Чтобы
дать пользователю возможность доступа к этим методам, создайте
свое меню со следующими идентификаторами меню:
Методы и идентификаторы меню файлового окна Таблица 10.3
+---------------------+-----------------------------------------+
| Метод | Идентификатор меню для вызова |
+---------------------+-----------------------------------------|
| New | cm_FileNew |
| Open | cm_FileOpen |
| Save | cm_FileSave |
| SaveAs | cm_FileSaveAs |
+---------------------+-----------------------------------------+
Вы можете использовать файловые окна без модификации как
простые автономные текстовые редакторы. Однако, иногда желательно
создать производные от TFileWindow типы и обеспечить дополнитель-
ные функциональные возможности. Например, можно предусмотреть
средство поиска. Помните, что вы все равно будете иметь доступ к
управляющему элементу редактирования TFileWindow.Editor.
Прокрутка содержимого окон
-----------------------------------------------------------------
В большинстве случаев для прокрутки текущей области просмот-
ра пользователи используют полосы прокрутки вдоль края окна. В
отличие от стандартных управляющих элементов типа полос прокрутки
полосы прокрутки окна являются частью самого окна.
ObjectWindows управляет прокруткой окна, предоставляя каждо-
му оконному объекту поле Scroller, которое может указывать на
объект TScroller. Объект прокрутки TScroller обеспечивает автома-
тизированный способ прокрутки в окнах текста и графики. Кроме то-
го, TScroller может прокручивать окна, когда пользователь переме-
щает "мышь" за область клиента окна (это называется автоматичес-
кой прокруткой и действует даже для окон, которые не имеют полос
прокрутки).
Что такое объект прокрутки?
-----------------------------------------------------------------
TScroller содержит значения, определяющие, насколько должно
прокручивается окно. Эти значения записываются в полях XUnit,
YUnit, XLine, YLine, XRange, YRange, XPage и YPage объекта
TScroller. Поля, начинающиеся с буквы X, представляют горизон-
тальные значения, а начинающиеся с буквы Y - вертикальные.
Единицы прокрутки
Единица прокрутки определяет минимальную величину прокрутки.
Она задается в наименьших единицах устройства (обычно в элементах
изображения, но может зависеть от текущего режима отображения),
на которые вы можете выполнять прокрутку в горизонтальном или
вертикальном направлении. Это значение обычно основывается на ви-
де выводимой на экран информации.
Например, если вы выводите текст с шириной символа 8 элемен-
тов изображения и высотой 15, то в качестве значений XUnit и
YUnit полезно задать, соответственно, 8 и 15.
Строки, страницы и диапазон
Другие атрибуты прокрутки - строка, страница и диапазон -
выражаются в единицах прокрутки. Значения Line (строка) и Page
(страница) - это число единиц, на которые выполняется прокрутка в
ответ на запрос пользователя. Запрос может иметь форму щелчка
кнопкой "мыши" на концах полосы прокрутки (построчная прокрутка).
Щелчок "мышью" в самой полосе прокрутки (но не на маркере полосы
прокрутки) позволяет выполнять постраничную прокрутку. Атрибуты
диапазона (XRange, YRange) представляют общее число единиц, на
которое можно выполнять прокрутку. Обычно этот диапазон определя-
ется на основе размера редактируемого документа.
Типичный объект прокрутки
В качестве примера рассмотрим текстовое окно редактирования.
Если вы хотите вывести на экран текстовый файл, имеющий 400 строк
текста с границей 80 символов и 50 строками на странице, то можно
выбрать следующие значения:
Типичные значения для окна редактирования Таблица 10.4
+-----------------+-------------+-------------------------------+
| Поле | Значение | Смысл |
+-----------------+-------------+-------------------------------|
| XUnit | 8 | ширина символа |
| YUnit | 15 | высота символа |
| XLine, YLine | 1 | 1 единица на строку |
| XPage | 40 | 40 символов по горизонтали на|
| | | страницу |
| YPage | 50 | 50 символов по вертикали на|
| | | страницу |
| XRange | 80 | максимальный горизонтальный|
| | | диапазон |
| YRange | 400 | максимальный вертикальный ди-|
| | | апазон |
+-----------------+-------------+-------------------------------+
Объект TScroller с данными значениями позволяет выполнять
построчную или постраничную прокрутку. С помощью полос прокрутки
или автоматической прокрутки выполняется просмотр всего файла.
Значения по умолчанию
По умолчанию XLine и YLine имеют значение 1, так что без яв-
ной необходимости устанавливать их в другие значения не нужно.
Для установки значений прокрутки на страницу также существует ис-
пользуемая по умолчанию схема, согласно которой страница прокрут-
ки будет соответствовать текущей высоте или ширине области клиен-
та окна (в зависимости от направлений прокрутки). Если вы не хо-
тите переопределить данный механизм, переустанавливать эти значе-
ния не требуется.
Задание для окна объекта прокрутки
-----------------------------------------------------------------
Чтобы задать для окна объект прокрутки, постройте в конс-
трукторе своего оконного объекта объект TScroller и присвойте его
полю Scroller. Вам нужно установить начальный размер единицы и
диапазона, но позднее вы можете их изменить.
При использовании объекта прокрутки для автоматической прок-
рутки полосы прокрутки не требуются, но многие прокручиваемые
окна их имеют. Чтобы добавить в окно полосы прокрутки, добавьте
в поле Attr.Style ws_VScroll, ws_HScroll (или то и другое).
Приведем пример конструктора для текстового окна редактиро-
вания:
constructor TTextWindow.Init(AParent: PWindowsObject;
ATitle: PChar);
begin
inherited Init(AParent, ATitle);
Attr.Style := Attr.Style or ws_VScroll or ws_YScroll;
Scroller := New(PScroller, Init(@Self, 8, 15, 80, 400));
end;
В качестве аргументов TScroller воспринимает прокручиваемое
окно и начальные значения для полей XUnit, YUnit, XRange и YRange
соответственно. Атрибуты строки и страницы получают значения по
умолчанию.
После вывода окна на экран содержимое его области клиента
можно прокручивать вертикально и горизонтально, используя для
этого полосу прокрутки или автоматическую прокрутку. Метод Pant
окна просто рисует на экране графическую информацию, необходимую
для уведомления о прокрутке. Как описывается в конце этого разде-
ла, метод Paint можно оптимизировать для вывода только части ри-
сунка.
Пример прокрутки
-----------------------------------------------------------------
Scroll - это полное приложение с графическим выводом, допус-
кающим прокрутку. Показанная ниже программа рисует последователь-
ность прямоугольников, затем увеличивает их размер, так что вся
картинка не умещается в область клиента окна, отображенного на
обычном экране VGA. С помощью полос прокрутки вы можете просмат-
ривать различные части рисунка или автоматически прокручивать
картинку, удерживая нажатой левую кнопку "мыши" и перемещая ее из
области клиента.
program Scroll;
uses Strings, WinTypes, WinProcs, OWindows;
type
TScrollApp = object(TApplication)
procedure InitMainWindow; virtual;
end;
PScrollWindow = ^TScrollWindow;
TScrollWindow = object(TWindow)
constructor Init(ATitle: PChar);
procedure Paint(PaintDC: HDC;
var PaintInfo: TPaintStruct); virtual;
end;
procedure TScrollApp.InitMainWindow;
begin
MainWindow := New(PScrollWindow, Init('Boxes'));
end;
constructor TScrollWindow.Init(ATitle: PChar);
begin
inherited Init(nil, ATitle);
Attr.Style := Attr.Style or ws_VScroll or ws_HScroll;
Scroller := New(PScroller, Init(@Self, 8, 15, 80, 60));
end;
procedure TScrollWindow.PAint(PaintDC: HDC;
var PaintInfo: TPaintStruct);
var X1, Y1, I: Integer;
begin
for I := 0 to 49 do
begin
X1 := 10 + I*8;
Y1 := 30 + I*5;
Rectangle(PaintDC, X1, Y1, X1 + X1, X1 + Y1 * 2);
end;
end;
var ScrollApp: TScrollApp;
begin
ScrollApp.Init('ScrollApp');
ScrollApp.Run;
ScrollApp.Done:
end.
Запрещение автоматической прокрутки
-----------------------------------------------------------------
Объект TScroller может по умолчанию выполнять автоматическую
прокрутку, но установка поля AutoMode TScroller в значение False
отключает это средство. Окно-владелец может сделать это в конс-
трукторе после построения объекта TScroller:
Scroller := New(PScroller, Init(@Self, 8, 15, 80, 60));
Scroller^.AutoMode :=False;
Если AutoMode равно False, то прокрутка может выполняться
только с помощью полос прокрутки. Полезная особенность автомати-
ческой прокрутки состоит в том, что чем дальше вы сдвинете "мышь"
от области клиента окна, тем быстрее будет происходить прокрутка
окна. В зависимости от удаления мыши приращение прокрутки будет
обратно пропорционально значению параметра строк и прямо пропор-
ционально значению параметра страницы.
Отслеживание полос прокрутки
-----------------------------------------------------------------
В дополнение к автоматической прокрутке, приведенный выше
пример программы будет отслеживать запросы на прокрутку, сдвигая
при нажатой кнопке "мыши" маркер полосы прокрутки. Другими слова-
ми картинка сдвигается уже при нажатой кнопке. Эта особенность
дает действительную обратную связь, и пользователь может сдвигать
нужную часть изображения не отпуская кнопку "мыши".
Однако, в некоторых случаях этот эффект нежелателен. Напри-
мер, если вы просматриваете большой текстовый файл, такое отсле-
живание может замедлить работу, поскольку возникает необходимость
постоянно считывать информацию с диска и отображать порцию текста
для каждого движения "мыши". В такой ситуации лучше отменить этот
эффект:
Scroller^.TrackMode:=False;
Теперь никакой прокрутки не происходит до момента отпускания
кнопки на мыши, и в области клиента будет лишь однократно показа-
на нужная часть картинки.
Модификация единиц прокрутки и диапазона
-----------------------------------------------------------------
В приведенных выше примерах мы предполагали, что к моменту
построения TScroller известны значения единиц и диапазонов. Во
многих случаях эта информация неизвестна или может меняться при
изменении размеров отображаемой информации. В этом случае может
потребоваться установить или изменить значения диапазона (а может
быть и единиц) позднее. Если значения заранее неизвестны, то их
можно задать как 0 в конструкторе TScroller.
Изменение диапазона
Метод SetRange воспринимает два целочисленных аргумента -
число горизонтальных и вертикальных единиц, которые определяют
общий диапазон прокрутки. Метод SetRange должен использоваться
при изменении размеров картинки. Например, при подготовке изобра-
жения картинки шириной 1 0 единиц и высотой 300, данная команда
установит диапазон прокрутки надлежащим образом:
Scroller^.setRange(100, 300);
Изменение единиц прокрутки
Если при инициализации объекта TScroller единицы неизвестны,
то их значения могут быть установлены непосредственно перед прок-
руткой. Например, они могут быть установлены методом окна
SetupWindow:
procedure ScrollWindow.SetupWindow;
begin
TWindow.SetupWindow;
Scroller^.XUnit:=10;
Scroller^.YUnit:=20;
end;
Изменение позиции прокрутки
-----------------------------------------------------------------
Windows с помощью методов ScrollTo и ScrollBy может выпол-
нять принудительную прокрутку. Каждый из них воспринимает два це-
лочисленных аргумента в терминах горизонтальных и вертикальных
единиц прокрутки. Например, если нужно переместиться к левому
верхнему углу картинки, то используется ScrollTo:
Scroller^.ScrollTo(0, 0);
Приведем другой пример. Если картинка имеет длину 400 единиц
в вертикальном направлении, то позицию прокрутки можно перемес-
тить к середине картинки следующим образом:
Scroller^.ScrollTo(0, 200);
Метод ScrollBy может перемещать позицию просмотра на задан-
ное число единиц вверх, вниз, влево или вправо. Отрицательные
значения осуществляют сдвиг к левому верхнему углу, а положитель-
ные - к правому нижнему. Если нужно сместиться на 10 единиц впра-
во и на 20 единиц вниз, то это можно сделать командой:
Scroller^.ScrollBy(10, 20);
Установка размеров страницы
-----------------------------------------------------------------
По умолчанию размер страницы (XPage и YPage) устанавливается
в соответствии с размером области клиента окна. При изменении
размеров окна механизм прокрутки учитывает эту информацию. Метод
окна WMSize вызывает метод прокрутки SetPageSize, который уста-
навливает поля объекта XPage и YPage на основании текущих разме-
ров области клиента окна и значений XUnit и YUnit. Для отмены
этого механизма и непосредственной установки размеров страницы вы
должны переписать унаследованный метод объекта окна WMSize и не
вызывать SetPageSize:
procedure TTestWindow.WMSize(var Msg: TMessage);
begin
DefWndProc(Msg);
end;
Затем вы можете непосредственно установить XPage и YPage в
конструкторе окна (или в производном конструкторе TScroller):
constructor ScrollWindow.Init(AParent:PWindowsObject;
ATitle: PChar);
begin
inherited Init(AParent, ATitle);
Attr.Style:=Attr.Style or ws_VScroll or ws_HScroll;
Scroller:=New(PScroller, Init(@Self, 8, 15, 80, 400));
Scroller^.XPage:=40;
Scroller^.YPage:=100;
end;
Оптимизация методов Paint для прокрутки
-----------------------------------------------------------------
В приведенном выше примере рисуется 50 прямоугольников, но
не делается даже попытки определить, все ли прямоугольники видны
в области клиента окна. Это может привести к излишним усилиям на
дорисовку невидимых изображений. Для оптимизации рисования в окне
методом Paint можно использовать метод TScroller.IsVisibleRect.
Приведенный ниже метод ScrollWindow.Paint использует
IsVisibleRect для определения, нужно ли вызывать функцию Windows
Rectange. Rectange воспринимает аргументы в единицах устройства,
а VisibleRect в единицах прокрутки. С этой целью вершина прямоу-
гольника X1 Y1 и ширина прямоугольника (X2-X1) и его высота
(Y2-Y1) должны быть разделены на соответствующее число единиц до
вызова IsVisibleRect:
procedure TScrollWindow.Paint(PaintDC: HDC; var PaintInfo:
TPaintStruct);
var
X1, Y1, X2, Y2, I: Integer;
begin
for I:=0 to 49 do
begin
X1 := 10 + I * 8;
Y1 := 30 + I * 5;
X2 := X1 + X1;
Y2 := X1 + Y1 * 2;
if Scroller^.IsVisibleRect(X1 div 8,
Y1 div 15, (X2-X1) div 8,
(Y2-Y1) div 15) then
Rectangle(PaintDC, X1, Y1, X2, Y2);
end;
end;
Назад | Содержание | Вперед