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



 

Часть 11

Глава 10. Объекты окна
Материал данной главы поясняет как создавать, отображать и заполнять окна приложения. В ObjectWindows тип объекта TWindow служит шаблоном, определяющим основное поведение головного окна программы и его всплывающих окон, если они есть. Хотя объекты TWindo
w и самые общие окна, этот тип определяет протокол открытия и закрытия окон, поведение дочерних окон и обработку командных сообщений.
TWindow имеет три производных типа: TMDIWindow, TControl и TEditWindow. Типы MDI используются в приложениях ObjectWindows, которые отвечают стандарту интерфейса нескольких документов Windows. Рассмотрение MDI и этих типов содержится в Главе 13. TControl 
определяет управления (например, кнопки и блоки списков) и рассматривается в Главе 12. Более часто вы будете создавать новые типы окна, производные от TWindow.
Данная глава рассматривает типы TWindow и TEditWindow и содержит пример регистрации нового класса Windows.
Тип TWindow
Как минимум, приложение ObjectWindows должно иметь головное окно, которое отображается на экране при запуске приложения.  Пример TestApp из Главы 8, "Объекты приложения", является примером минимальной программы ObjectWindows. Головное окно программы Obje
ctWindows обычно является объектом типа TWindow, или более часто производным типом, определенным в программе. Многие приложения имеют другие окна, которые обычно являются дочерними окнами головного окна. Эти дополнительные окна также являются объектами т
ипа TWindow или (обычно) производного от TWindow типа. Например, программа рисования может определять тип TPaintWindow для головного окна и тип TZoomWindow для другого окна, на котором показывается увеличенное изображение. В этом случае и TPaintWindow и 
TZoomWindow есть производные от TWindow типы. В хорошо разработанном приложении ZoomWindow вероятно будет специализированной версией TPaintWindow и реализовано как производная TPaintWindow (и косвенно от TWindow).
Инициализация и создание объектов окна
Подобно объектам диалога и управления, объекты окна являются объектами интерфейса, которые связаны с элементами визуального интерфейса. Если говорить более точно, то они представляют элементы окна, соединенные через хранимый в поле HWindow регулятор, уна
следованный от TWindowObject. Поскольку объект окна состоит из двух частей, его создание состоит из двух этапов: инициализация объекта и создание визуального элемента.
Инициализация объектов окна
Типичное приложение Windows имеет много окон различного типа: раскрывающиеся или всплывающие, ограниченные рамками, прокручивающиеся и снабженные заголовками и т.д. Эти атрибуты стиля, наряду с заголовком и меню окна, устанавливаются при инициализации об
ъекта окна и используются при создании элемента окна.
Атрибуты создания объекта окна (например, стиль, заголовок и меню) хранятся в определенном ObjectWindows типе записи TWindowAttr. Каждый объект окна хранится в записи TWindowAttr в его поле Attr. TWindowAttr имеет следующие поля:
     Таблица 10.1. Поля атрибутов окна
----------------------------------------------------------------
Поле      Использование
----------------------------------------------------------------
Title     PChar для хранение строки-заголовка
Style     Longint для хранения комбинированной константы стиля
Menu      Регулятор к ресурсу меню (HMenu)
X         Integer, представляющее начальное горизонтальное
          местоположение окна. Это горизонтальная координата на
          экране верхнего левого угла окна.
Y         Integer, представляющее начальное вертикальное
          местоположение окна. Это вертикальная координата на
          экране верхнего левого угла окна.
W         Integer, представляющее начальную ширину окна в экранных
          координатах.
H         Integer, представляющее начальную высоту окна в экранных
          координатах.
----------------------------------------------------------------
Рис.10.1. Атрибуты окна
Инициализация окна представляет собой процесс создания объекта окна ObjectWindows путем вызова конструктора Init.
Window1:=New(PWindow, Init(nil, 'Title of Window 1'));
Window2:=New(PNewWindowType, Init(nil, 'Title of Window 2'));
Init создает новый объект окна и устанавливает поле Title в Attr равным переданному аргументу PChar. По умолчанию он устанавливает Style равным ws_OverlappedWindow or ws_Visible если данное окно есть головное окно приложения (только ws_Visible в противно
м случае), а X, Y, W и H равным cw_UseDefault. Результатом этого будет перекрывающееся окно средних размеров. Это стандартный способ задать размеры нового головного окна. Первый аргумент в Init вызывает объект родительского окна. Его значение nil если мы
 имеем дело с головным окном (не имеющим родителей).
Когда вы строите окно нового типа, производного от TWindow, вы можете определить новый конструктор Init, особенно если вам нужны атрибуты создания, отличные от значений по умолчанию. Если вы не хотите переопределять Init, то атрибуты объекта окна можно с
менить непосредственным манипулированием полем объекта Attr сразу же после вызова Init. Если вы переопределяете Init, то первое что нужно сделать, это вызвать унаследованный TWindow.Init, который устанавливает атрибуты по умолчанию. Позднее можно изменит
ь значение любого атрибута. Например, типичный тип окна может определять Init, который устанавливаете атрибут Menu:
constructor AWindowType.Init(AParent: PWindowsObject; ATitle: PChar);
begin
 TWindow.Init(AParent, ATitle);
 Attr.Menu:=LoadMenu(HInstance, PChar(100));
 AChildWindow:=New(PChildWindowType, Init(@Self,'Child Title'));
 List1:=New(PListBox, Init(@Self, id_ListBox, 201, 20, 20, 180,
  80));
 ...
end;
Обратите внимание на то, что в предыдущем примере пример конструктора окна Init отвечает за конструирование объектов его дочернего окна (например, всплывающих окон и блоков списка). В свою очередь тип дочернего окна может изменять атрибуты своего собстве
нного конструктора Init:
constructor ChildWindowType.Init(AParent: PWindowsObject; ATitle:
PChar);
begin TWindow.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;
Атрибут Style может быть один или комбинацией констант стиля окна:
          ws_OverlappedWindow
          ws_PopupWindow
          ws_ChildWindow
          ws_Caption
          ws_Border
          ws_VScroll
Приведенный выше список содержит некоторые популярные константы стиля. Их полный список содержится в "Справочном руководстве по Windows", Глава 1, "Стили и константы Windows".
В качестве альтернативы, если вы не определите производного типа окна, то сначала можно сконструировать объект окна, а уже затем изменить значения его атрибутов, и все это делается с помощью конструктора Init родительского окна:
constructor AWindowType.Init(AParent: PWindowsObject; ATitle: PChar);
begin
 TWindow.Init(AParent, ATitle);
 Attr.Menu:=LoadMenu(HInstance, PChar(100));
 AChildWindow:=New(PChildWindowType, Init(@Self,'Child Title'));
 with AChildWindow^.Attr do
 begin
  Style:=Style or ws_PopupWindow or ws_Caption;
  X:=100; Y:=100; W:=300; H:=300;
 end;
 ...
end;
Создание элементов окна
Создание элементов окна это процесс построения визуальных элементов, связанных с объектом окна. Это выполняется вызовом метода MakeWindow объекта приложения, которое передает объект окна в качестве параметра:
if Application^.MakeWindow(AWindow) <> nil then
 {успешное создание}
else {неуспешное создание}
MakeWindow вызывает два важных метода. Первый, ValidWindow, проверяет, было ли успешным конструирование объекта окна. Если конструирование по каким-либо причинам не удалось, то MakeWindow возвращает nil. Если конструирование прошло успешно, то MakeWindow
 вызывает метод Create объекта окна. Create это метод, который действительно дает инструкцию Windows на создание визуального элемента. Если Create не удался, то MakeWindow возвращает nil. В противном случае он возвращает указатель на объект окна.
Хотя этот метод действительно создает объект окна, вы не будете явно вызывать Create. Головное окно приложения создается автоматически после запуска приложения с помощью TApplication.InitInstance. Все другие окна приложения являются дочерними окнами по о
тношению к головному окну непосредственно или косвенно. Дочерние окна обычно создаются методом SetupWindow их объекта головного окна или динамически, "по ходу дела", с помощью MakeWindow.
Выводы, касающиеся инициализации и создания
При разработке нового типа объекта окна можно переопределить Init для установления атрибутов окна и конструирования объектов дочерних окон, если они есть. (Атрибуты окна могут быть установлены непосредственно, например, в Init родительского окна.) MakeWi
ndow строит визуальный элемент объекта окна вызовом Create, который в свою очередь вызывает метод объекта окна SetupWindow, который автоматически создает дочерние окна.
В общем случае родительские окна обычно вызывают Init и MakeWindow для их дочерних окон. Атрибуты объекта окна обычно устанавливаются его методами или методами объекта его родительского окна. Поскольку головное окно приложения не имеет родительского окна
, объект приложения конструируется и создается при запуске приложения.
Регистрация класса окна
Вы уже узнали, что при инициализации объекта окна вы можете установить атрибуты окна (например, его стиль, местоположение и меню) заполнением поля объекта Attr. Эти атрибуты используются при создании соответствующего элемента окна, поэтому они называются
 атрибутами создания. Однако, имеются и некоторые другие атрибуты (цвет фона, пиктограмма представления и курсор мыши). В качестве иллюстрации этого советуем вам запустить Windows с несколькими разными типами приложений одновременно. По мере перемещения 
курсора мыши от одного приложения к другому он меняется от стрелки (обычный) до жирного креста (для электронных таблиц) и до тонкого перекрестия (для графических программ).
Эти атрибуты принадлежат типу объекта окна и не могут быть изменены в процессе работы программы в отличие от атрибутов создания. Для того, чтобы выделить эти наследуемые атрибуты, мы будем называть их регистрационными атрибутами.
Список регистрационных атрибутов, связанный с каждым типом объекта окна, называется классом окна. Список регистрационных атрибутов очень похож на список атрибутов создания, хранимый в записи Attr в поле объекта окна. Однако, регистрационные атрибуты хран
ятся в записи TWndClass, которая определяется и обслуживается Windows. Процесс связывания класса окна с типом объекта окна называется регистрацией класса окна. ObjectWindows автоматизирует этот процесс регистрации. Следовательно, если вы не изменяете ник
акие характеристики окна по умолчанию, то вам не следует беспокоиться о регистрации класса окна.
Если вы хотите изменить регистрационные атрибуты, например, курсор или пиктограмму, то вам нужно определить новый класс окна путем написания двух методов: GetClassName и GetWindowClass. GetClassName это функция, которая просто возвращает имя (PChar) клас
са окна. TWindow определяет метод GetClassName, который возвращает 'TurboWindow', имя класса окна по умолчанию:
function TWindow.GetClassName: PChar;
begin
 GetClassName:='TurboWindow';
end;
Для определения типа объекта окна с именем IBeamWindow, который использует подобие латинской буквы I вместо стандартной стрелки, нужно переопределить наследуемый метод GetClassName следующим образом:
function IBeamWindow.GetClassName: PChar;
begin
 GetClassName:='IBeamWindow';
end;
Имя класса может совпадать с именем типа объекта, а может и не совпадать. В этом нет никакой разницы.
Метод GetWindowClass берет запись TWndClass в качестве переменного аргумента и заполняет его поля новыми регистрационными атрибутами. Ситуация аналогична определению нового метода Init для установки атрибутов окна, когда сначала вызывался метод TWindow.G
etWindowClass. Затем устанавливаются поля, которые вы хотите изменить. Например, поле hCursor хранит регулятор ресурса курсора. Для IBeamWindow определим следующий метод GetWindowClass:
procedure IBeamWindow.GetWindowClass(var AWndClass: TWndClass);
begin
 TWindow.GetWindowClass(AwndClass);
 AwndClass.hCursor:=LoadCursor(0, idc_IBeam);
end;
idc_Beam это константа, представляющая один из курсоров Windows. На Рис.10.2 показано приложение, которое использует объект IBeamWindow.
Рис.10.2. Программа, которая использует класс IBeamWindow
Кроме обычных окон, окна диалога (но не блоки диалога) требуют зарегистрированных классов окна (См. Главу 5). Блоки диалога и управления не требуют классов окна.
Атрибуты регистрации
Тип TWindow определяет класс окна, 'TurboWindow', с пустой пиктограммой, курсором в виде стрелки и стандартным цветом окна. Для изменения этих характеристик нужно заполнить поля записи TWndClass другими данными в методе GetWindowClass.
В следующей ниже таблице показаны поля характеристик записи TWndClass и их значения по умолчанию так, как они определены в TWindow.GetWindowClass:
Таблица 10.2. Регистрационные атрибуты окна
----------------------------------------------------------------
Характеристика      Поле           Значение по умолчанию
----------------------------------------------------------------
стиль класса        style          cs_HRedraw or cs_VRedraw
пиктограмма         hIcon          LoadIcon(0, idi_Application)
курсор              hCursor        LoadCursor(0, idc_Arrow)
цвет фона           hbrBackground  HBrush(Color_Window+1)
меню по умолчанию   lpszMenuName   nil
----------------------------------------------------------------
Поле стиля класса
Данное поле style отличает от атрибута стиля окна (ws), который вы задавали при инициализации окна, т.к. оно характеризует действие окна, а не его его визуальное проявление. Это поле может быть заполнено одной константой или комбинацией констант стиля кл
асса (cs). Например, cs_Redraw задает режим перерисовки окна при изменении его горизонтальных размеров; cs_NoClose противодействует опции Close меню управления; а cs_ParentDC передает окну родительский контекст дисплея. Полный список констант cs_ содержи
тся в "Справочном руководстве по Windows", Глава 1, "Стили и константы Windows".
Класс TurboWindow определяет класс окна со стилем:
AWndClass.style:=cs_HRedraw or cs_VRedraw;
Поле пиктограммы
Это поле содержит регулятор пиктограммы, которая используется для представления окна в его минимальном состоянии. Обычно вы будете определять ресурс пиктограммы для представления головного окна вашей программы. По умолчанию класс TurboWindow использует п
иктограмму idi_Application, которая представляет собой пустой прямоугольник.
Поле курсора
Поле hIcon содержит регулятор курсора, который используется в качестве указателя мыши при его перемещении по окну. Класс TurboWindow использует стандартную стрелку Windows, idc_Arrow. Имеются некоторые другие виды курсоров:
          idc_IBeam
          idc_Wait
          idc_Cross
Поле цвета фона
Это поле задает цвет фона окна. Для большинства приложений вполне подойдет стандартный цвет окна по умолчанию, который устанавливается пользователем на Панели Управления. Однако, можно задать конкретный цвет, если присвоить этому полю значение регулятора
 физического цвета. В качестве альтернативы можно использовать любое значение цвета Windows, например, color_ActiveCaption. К любому значению цвета нужно всегда добавлять 1.
Поле меню по умолчанию
Это поле указывает имя ресурса меню, которое будет для данного класса меню по умолчанию. Например, если вам нужно определить тип EditWindow, который всегда имеет стандартное меню редактирования, вы можете задать это меню здесь. Это избавит вас от необход
имости задавать меню в методе Init. Если этот ресурс меню имеет ID 101, то данное поле устанавливается следующим образом:
AwndClass.lpszMenuName:=LoadMenu(Hinstance, PChar(101));
Окна редактирования и файлов
ObjectWindows имеет две производные от TWindow, которые являются специализированными окнами для редактирования текста. Тип объекта TEditWindow обеспечивает простой редактор текста, который не может читать и записывать файлы. Производный от TEditWindow ти
п TFileWindow предоставляет текстовый редактор, который позволяет считывать и записывать файл. Эти типы объектов можно использовать непосредственно в качестве стандартных компонент ваших приложений. Кроме того, вы можете вывести из них свой собственный т
ип для создания специализированных редакторов. Использующие окна редактирования или окна файлов программы должны включать модуль StdWnds в их разделе uses.
Окна редактирования
Окно редактирование это окно с полноразмерным управлением редактированием в нем. Конструктор Init в TEditWindow инициализирует поле Editor в TEditWindow для указания на управление редактированием. Метод SetupWindow в TEditWindow задает размеры управления
 редактированием совпадающие с областью клиента окна и создает элемент интерфейса управления редактированием. Метод WMSize следит следит за изменением размеров управления редактированием при изменении размеров окна. Метод WMSetFocus фокусирует управление
 редактированием на вводе при получении окном сообщения wm_SetFocus.
Следующая программа использует окно редактирования для простого (не функционального) приложения электронной почты, позволяя пользователю редактировать текст.
Рис.10.3. Окно редактирования
program EditWindowTester;
{$R EWNDTEST.RES}
uses WObjects, WinTypes, WinProcs, Strings, StdWnds;
const
 cm_SendText=399;
type
TestApplication+object(TApplication)
 procedure InitMainWindow; virtual;
end;
PMyEditWindow=^MyEditWindow)
MyEditWindow=object(TEditWindow)
 constructor Init(AParent: PWindowsObject; ATitle: PChar);
 procedure HandleSend(var Msg: TMessage); virtual cm_First +
  cm_SendText;
end;
constructor MyEditWindowInit(AParent: PWindowsObject; ATitle:
PChar);
begin
 TEditWindow.Init(AParent, ATitle);
 Attr.Menu:=LoadMenu(HInstance, PChar(102));
end;
procedure MyEditWindowHandleSend(var Msg: TMessage);
var
 Lines: Integer;
 TextString: string[3];
 Text: array[0..20] of Char;
begin
 Lines:=Editor^.GetNumLines;
 Str(Lines, TextString);
 StrPCopy(Text, TextString);
 StrCat(Text, 'lines sent');
 MessageBox(HWindow, @Text, 'Message Sent', mb_OK);
end;
{Инициация главного окна TestApplication - EditWindow}
procedure TestApplication.InitMainWindow;
begin
 MainWindow:=New(PMyEditWindow, Init(nil,
  'Edit Window - Try Typing and Editing'));
end;
var
 TestApp: TestApplication;
begin
 TestApp.Init('EditWindowTester');
 TestApp.Run;
 TestApp.Done;
end.
Окна файлов
Окно файла это окно редактирования с дополнительными возможностями считывания и записи файлов. Конструктор Init в TFileWindow берет заголовок окна в качестве аргумента. Он инициализирует поле объекта FileDialog для указания на объект файла диалога. TFile
Dialog имеет четыре метода по манипулированию файлами. Open, Save и SaveAs используют поле файла диалога TFileWindow.FileDialog (см. Главу 5) для запроса у пользователя имени файла. New дает пользователю шанс отменить редактирование, если оно может приве
сти к потере текущего текста. Чтобы пользователь имел доступ ко всем этим методам, нужно создать ваше меню со следующими ID меню:
Таблица 10.3. Методы файла окна и ID меню
----------------------------------------------------------------
Метод          ID меню для вызова
----------------------------------------------------------------
New            cm_FileNew
Open           cm_FileOpen
Save           cm_FileSave
SaveAs         cm_FileSaveAs
----------------------------------------------------------------
Вы можете использовать окна файлов в качестве простых автономных редакторов текста без каких-либо изменений. Однако, иногда вам может потребоваться создать свой собственный тип, производный от TFileWindow, для реализации дополнительных функций. Например,
 вам может потребоваться средство поиска. Помните о том, что у вас все еще есть доступ к управлению редактированием TFileWindow.Editor.
Прокрутка окон
В мире есть вещи, которые иногда больше того, что вы можете видеть через окно. Если это окно есть окно Microsoft Windows, то вам повезло, и вы можете сдвигать его вверх и вниз, влево и вправо, чтобы увидеть дополнительные изображения и текст. В большинст
ве случаев пользователь манипулирует линейками прокрутки на граница области клиента окна, для прокрутки текущего изображения. В отличие от автономных управлений линеек прокрутки, линейки прокрутки окна являются частью самого окна, созданного для окон, ко
нстанты стиля которых включают ws_VScroll (вертикальная линейка прокрутки) или/и ws_HScroll (горизонтальная линейка прокрутки). Механизм, который стоит за прокруткой окна, является объектом с именем прокрутка.
TScroller это объект ObjectWindows, который обеспечивает прокрутку окон, давая автоматический способ прокрутки текста и изображений, помещенных в ваши окна. Кроме того, TScroller прокручивает ваши окна, когда пользователь протягивает мышь вне области кли
ента окна. Это называется авто-прокруткой и имеет место даже для окон, у которых нет линеек прокрутки.
Атрибуты прокрутки
TScroller содержит значения, которые определяют какая часть окна будет просмотрена. Эти значения хранятся в полях объекта TScroller: XUnit, YUnit, XLine, YLine, XPage, YPage, XRange и YRange. Начинающиеся с буквы X поля представляют горизонтальные величи
ны, а с буквы Y - вертикальные.
Единицы прокрутки определяют ее зернистость. Это наименьшее число аппаратных единиц (обычно пикселей окна, но это зависит от установленного режима распределения), на которые можно осуществить сдвиг в вертикальном или горизонтальном направлении. Эта едини
ца обычно основана на виде отображаемой вами информации. Например, если вы отображаете текст, ширина символа которого составляет 8 пикселей, а высота 15, то значения XUnit и YUnit будут 8 и 15 соответственно.
Другие атрибуты прокрутки (строки, страницы и диапазон) обычно выражены в единицах прокрутки. Значения Line и Page это число единиц, на которое нужно сделать прокрутку при запросе пользователя. Запрос обычно производится в форме нажатия стрелки на одном 
из концов линейки прокрутки и приводит к сдвигу изображения в окне на число строк, заданных в полях строк. Нажатие на саму линейку прокрутки (а не на кнопку прокрутки) приводит к сдвигу на одну страницу. И, наконец, атрибуты диапазона представляют общее 
число единиц, которое можно просматривать. Они обычно основаны на размерах пространства окна, например, размерах редактируемого документа.
В качестве примера давайте рассмотрим окно редактирования текста. Если вы желаете рассматривать текстовый файл, в котором 400 строк текста не более чем по 80 символов в строке и 50 строк на листе, то вы можете выбрать следующие значения:
Таблица 10.4. Типичная значения полей окна редактирования
----------------------------------------------------------------
Поле           Величина       Значение
----------------------------------------------------------------
XUnit            8       ширина символа
YUnit           15       высота символа
XLine, YLine     1       1 единица на строке
XPage           40       40 символов на горизонтальной странице
YPage           50       50 строк на вертикальной странице
XRange          80       максимальный горизонтальный диапазон
YRange         400       максимальный вертикальный диапазон
----------------------------------------------------------------
Объект TScroller с этими значениями позволяет делать прокрутку на одну строку или страницу за один шаг. Файл можно просматривать с помощью линеек прокрутки или авто-прокрутки. 
Значение строки по умолчанию равно 1, поэтому нет необходимости его устанавливать, если не требуется другое значение. Кроме того, имеется схема, которая по умолчанию устанавливает единицы страницы в зависимости от текущего размера окна. Поэтому прокрутка
 "страницы" будет менять текущую область клиента в ширину или в высоту, в зависимости от направления прокрутки. Нет необходимости устанавливать значение страницы, если вы не желаете менять этот механизм.
Задание прокрутки собственного окна
Для организации прокрутки вашего окна сконструируем объект TScroller в конструкторе вашего окна и запишем объект в поле объекта окна Scroller. Делая это вы можете установить размеры единиц и диапазон, если они известны. Несмотря на то, что линейки прокру
тки не требуются для использования прокрутки (режим авто-прокрутки), многие окна их имеют. Для добавления их к окну нужно просто добавить к полю окна Attr.Style в его конструкторе ws_HSclroll и/или ws_VScroll. Приведем пример конструктора для окна редакт
ирования текста:
constructor TScrollWindow.Init(AParent:PWindowsObject; ATitle:
PChar);
begin
 TWindow.Init(AParent, ATitle);
 Attr.Style:=Attr.Style or ws_VScroll or ws_HScroll;
 Scroller:=New(PScroller, Init(@Self, 8, 15, 80, 400));
end;
TScroller берет в качестве аргумента прокручиваемое окно и начальные значения полей XUnit, YUnit, XRange и YRange соответственно. Атрибуты строки и страницы будут основываться на их значениях по умолчанию.
После отображения окна содержание его области клиента может быть прокручено вертикально или горизонтально с помощью линеек прокрутки или авто-прокрутки. Метод окна Paint просто рисует графическую информацию без интереса к тому, имеет ли место прокрутка. 
Конечно, неэффективно рисовать большое изображение, когда только маленькая часть его будет видна. В конце данного раздела будет показано, как можно оптимизировать метод Paint, чтобы он рисовал только ту часть изображения, которая отображается.
Пример прокрутки
Давайте проиллюстрируем процесс построения полного приложения, которое рисует графику с возможностью прокрутки. В данном примере будет рисоваться последовательность прямоугольников увеличивающегося размера, так, что результирующая картина не умещается в 
области клиента окна, нарисованного на обычном экране VGA. Для просмотра различных частей изображения можно использовать линейки прокрутки или сдвигать изображение, нажав левую кнопку на мыши в области клиента и переместив курсор мыши вне области клиента
.
Исходный код следующий (это файл SCROLAPP.PAS):
program Scroll;
uses Strings, WinTypes, WinProcs, WObjects;
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;
begin
 MainWindow:=New(PScrollWindow, Init('Boxes'));
end;
constructor TScrollWindow.Init(ATitle: PChar);
begin
 TWindow.Init(nil, ATitle);
 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 обладает возможностью авто-прокрутки, но ее можно отключить, если присвоить значение False полю AutoMode в TScroller. Владелец окна может это сделать в его конструкторе, после конструирования объекта TScroller:
     Scroller:=New(PScroller, Init(@Self, 8, 15, 80, 60));
     Scroller^.AutoMode:=False;
Если это сделать, то прокрутка возможна только с использованием линеек прокрутки. 
Полезная особенность авто-прокрутки состоит в том, что чем дальше вы сдвинете мышь от области клиента окна, тем быстрее будет происходить прокрутка окна. В зависимости от удаления мыши приращение прокрутки будет обратно пропорционально значению параметра
 строк и прямо пропорционально значению параметра страницы. 
В дополнение к авто-прокрутке, приведенный выше пример программы будет отслеживать запросы на прокрутку, сдвигая изображение при нажатой кнопке на мыши.  Другими словами картинка сдвигается уже при нажатой кнопке. Эта особенность дает действительную обра
тную связь и пользователь может сдвигать нужную часть изображения не отпуская кнопку на мыши. Однако, в некоторых случаях этот эффект нежелателен. Например, если вы просматриваете большой текстовый файл, такое отслеживание может замедлить работу, посколь
ку возникает необходимость постоянно считывать информацию с диска и отображать порцию текста для каждого движения мыши. В такой ситуации лучше отменить этот эффект:
     Scroller^.TrackMode:=False;
Теперь никакой прокрутки не происходит до момента отпускания кнопки на мыши и в области клиента будет лишь однократно показана нужная часть картинки.
Модификация единиц прокрутки и диапазона
В приведенных выше примерах мы предполагали, что к моменту конструирования TScroller известны значения единиц и диапазонов. Во многих случаях эта информация неизвестна или может меняться при изменении размеров отображаемой информации. В этом случае может
 потребоваться установить или изменить значения диапазона (а может быть и единиц) позднее. Если значения заранее неизвестны, то их можно задать как nil в конструкторе TScroller.
Метод SetRange берет два целых аргумента, число горизонтальных и вертикальных единиц, которые определяют общий диапазон прокрутки. SetRange должен использоваться при изменении размеров картинки. Например, при подготовке изображения картинки шириной 100 е
диниц и высотой 300, данная команда установит диапазон прокрутки надлежащим образом:
     Scroller^.setRange(100, 300);
Если единицы неизвестны при инициализации объекта TScroller, то их значения могут быть установлены непосредственно пред прокруткой. Например, они могут быть установлены методом окна SetupWindow:
procedure ScrollWindow.SetupWindow;
begin
 TWindow.SetupWindow;
 Scroller^.XUnit:=10;
 Scroller^.YUnit:=20;
end;
Изменение позиции прокрутки
Windows может форсировать прокрутку методами ScrollTo и ScrollBy. Каждый из них берет два целых аргумента в терминах горизонтальных и вертикальных единиц прокрутки. Например, если нужно переместиться к левому верхнему углу картинки, то используется Scrol
lTo:
     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
 TWindow.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;



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