|
Graffiti прокручивает изображение, так что вы
будете видеть другие части рисунка.
B.Pascal 7 & Objects/OW - 124 -
Часть 2. Использование ObjectWindows
Глава 7. Иерархия ObjectWindows
ObjectWindows представляет собой исчерпывающий набор объектов, облегчающий
разработку программ для Microsoft Windows на Паскале. В данной главе вы
найдете обзор иерархии объектов ObjectWindows. В остальных главах данной
части дается детальное описание различных частей иерархии.
Кроме описания иерархии объектов, в данной главе описываются основные принципы
программирования для операционной среды Windows, включая вызов API Windows.
Соглашения Windows
Соглашения по именам ObjectWindows обеспечивают ясность и содержательность
имен.
Имена объектов
Имена всех объектный типов, предусмотренных в ObjectWindows, начинаются
с буквы T. Например, объекты диалоговых окон имеют тип TDialog. Для каждого
определения объектного типа имеется соответствующий ссылочный тип, начинающийся
с P. Например, указатель на TDialogh имеет тип PDialog. В примерах данного
руководства будут создаваться динамические экземпляры объектов, например,
с помощью PDialog позволяет разместить объекты TDialog в динамически распределяемой
области памяти.
Имена методов
Методы реакции на сообщения называются по именам сообщений, на которые они
отвечают, но без подчеркиваний. Например, метод, отвечающий на сообщение
wm_KeyDown будет называться WMKeyDown.
B.Pascal 7 & Objects/OW - 125 -
Обзор объектов
Иерархия объектов
ObjectWindows - это иерархия объектных типов, которые вы можете использовать
для работы с большинством обычных задач в приложении ObjectWindows. Схема
объектов пользовательского интерфейса библиотеки показана на Рис. 7.1. На
Рис. 7.2 представлены объекты иерархии, используемые для управления данными
и проверки их допустимости.
TObject
---------------------------------------------------------
------------------ ------------------ ------------------ |
| TPrintout | | TPrinter | | TWindowsObject | |
------------------ ------------------ ------------------ |
--------------------- | |
------------------ ------------------ ------------- |
| TEditPrintout | | TWindowPrintout| | --------------
------------------ ------------------ | | |
| ------------------ | --------------------------------- | TApplication
| |
| | ------------------ |
------------------ ------------------ --------------
| TDialog | | TWindow | |
------------------ ------------------ ------------------
| | | TScroller |
| | ------------------
| ------------------------------
--------------------------------- |
------------------ ------------------ | |
| TFileDialog | | TInputDialog | | |
------------------ ------------------ | |
--------------------------------- |
--------------------- | |
|TPrinterAbortDialog| -------------- |
--------------------- | | |
| ------------------ |
----------------------- | TPrintDialog | |
------------------ | ------------------ |
|TPrinterSetupDlg| -------------- |
------------------ | |
------------------ |
| TDlgWindow | |
------------------ |
B.Pascal 7 & Objects/OW - 126 -
|
-| ----------------TControl | -----------------TMDIClient | ------------------
|| TMDIWindow | |
-|- ---------------------------TButton | ---------------- ----------------------------------TScrollBar
| ----------------- -- --------| ------------------| | TEditWindow || ------------------
| TCheckBox | ---------- -- | TFileWindow |
-|- ----------------TRadioButton | ---------------- -----------------TStatic
| -----------------|-----------------TEdit | ----------------- ----------|
------------| || || ------------------| | TListBox || ------------------|
|| -------------------- | TComboBox |------------------
TGroupBox |
Модуль OPRINTER: Модуль OWINDOWS: Модуль OSTDDLGS:
TPrinout TWindow TInputDialog
TPtinter TAppication TInputDialog
TEditPrintout TScroller
TWindowPrintout
TPrinterAbortDlg
TPrintDialog
TPrinterSetup
Модуль ODUIALOGS: Модуль OSTDWNDS:
TDialog TEditWindow
TDlgWindow TFileWindow
TButton
TScrollBar
TCheckBox
TRadioButton
TControl
TStatic
TEdit
TListBox
TComboBox
TGroupBox
Рис. 7.1. Иерархия объектных типов ObjectWindows.
B.Pascal 7 & Objects/OW - 127 -
TObject
----------------- --TValidator | | ----------------- -- ---------------
------------------TCollection | | TStream | --------------- ------------------
--------------------TPXPictureValidator| -------------------- -----------------
------------------ |TFilterValidator| |TLookupValidator| | -----------------
------------------ |
TRangeValidator | ---- | ------------------ | |
-------------- |TStringLookupValidator| |------------------------ |--------------------------------------
TMemoryStream | | ----------------- -- TDosStream | | TEmsStream | ---------------
------------------
|-- TBufStream | ---------------
Рис. 7.2 ИерархияМодуль OBJECTS:TObjectTCollectionTSortedCollectionTStrCollectionTStringCollectionTStreamTMemoryStreamTEmsStreamTDosStreamTBufStream
наборов, потоков и проверки допустимости.Модуль VALIDATE:TValidatorTPXPictureValidatorTFilterValidatorTRangeValidatorTLookupValidatorTStrongLookupValidatorБазовый
объект
TObject - это базовый объектный тип, общий предок всех объектов ObjectWindows.
Он определяет рудиментарный конструктор и деструктор. Потоки ObjectWindows
требует, чтобы записанные объекты были потомками TObject.
TApplication
Этот тип определяет поведение, необходимое для всех приложений ObjectWindows.
Каждое приложение ObjectWindows, которое вы пишете, будет определять объектный
тип приложения, производный от
B.Pascal 7 & Objects/OW - 128 -
TApplication. Объекты приложения подробно описываются в Главе 8 "Объекты
приложения".
Интерфейсные объекты
Остальные объекты в иерархии ObjectWindows классифицируются в общем случае
как интерфейсные объекты. Они являются интерфейсными в том смысле, что представляют
элементы и пользовательском интерфейсе Windows и служат интерфейсом между
кодом вашей прикладной программы и операционной средой Windows. Интерфейсные
объекты описываются в Главе 9.
Объекты Windows
Объекты Windows представляются не только знакомыми окнами среды Windows,
но и большинством визуальных инструментов операционной среды, такими как
управляющие элементы.
Объекты диалоговых блоков
Объекты диалоговых блоков (окон) обеспечивают временные окна для обслуживания
специальных функций ввода и вывода. В общем случае они включат в себя текст
и управляющие элемента, такие как командные кнопки, блоки списка и полосы
прокрутки. Об объектах диалоговых блоков подробно рассказывается в Главе
11.
Объекты управляющих элементов
В диалоговых блоках и некоторых окнах управляющие элементы позволяют пользователям
вводить данные и выбирать параметры. Объекты управляющих элементов обеспечивают
согласованные и простые средства для работы со всеми типами управляющих
элементов, определенных в Windows. Объекты управляющих элементов подробно
описываются в Главе 12.
Объекты MDI
Windows реализует стандарт для работы с несколькими документами в рамках
одного окна, которое называется множественным документальным интерфейсом
(MDI). ObjectWindows обеспечивает средства для установки окон MDI и работы
с ними. Объекты MDI подробно описываются в Главе 14.
Объекты проверки допустимости
ObjectWindows содержит полный набор объектов проверки допустимости данных,
которые позволяют проверять допустимость данных, введенных пользователем,
при выходе пользователя из поля или когда пользователь завершает работу
с окном. Проверка допустимости данных описывается в Главе 13.
Объекты принтера
B.Pascal 7 & Objects/OW - 129 -
Для работы с печатью документов или печати содержимого окна ObjectWindows
предусматривает соответствующие объекты. О том, как использовать эти объекты,
рассказывается в Главе 15.
Объекты наборов и потоков
Модуль Object включает в себя многочисленные объекты, реализующие гибкие
структуры данных и потоки, позволяющие считывать и записывать объекты. Наборы
описываются в Главе 19, а потоки - в Главе 20.
B.Pascal 7 & Objects/OW - 130 -
Файлы ObjectWindows
Перечисленные выше типы ObjectWindows реализует в скомпилированных модулях.
В данном разделе кратко описывается содержимое поставляемых модулей. В каждом
приложении ObjectWindows требуется только модуль OWindows.
В данной версии ObjectWindows различные части иерархии объектов разбивают
различные части иерархии объектов по отдельным моделям. Чтобы перекомпилировать
код ObjectWindows более ранних версий, в общем случае нужно изменить все
ссылки на модуль WObjects на OWindows и добавить к программам и модулям,
использующим наборы и потоки или диалоговые блоки, соответственно Objects
и ODialogs.
В данную версию ObjectWindows добавлены также новые модули для печати, проверки
данных, специализированных управляющих элементов Borland и поддержки Windows
3.1.
В Таблице 7.1 перечислены модули, составляющие интерфейс ObjectWindows и
AOPI Windows 3.0. Модули, поддерживающие расширения Windows 3.1, представлены
в Таблице 7.2.
Модули для ObjectWindows и API Windows Таблицы 7.1
Модуль Содержимое
ObjectsOWindowsODialogsOPrinterValidateBWCCOStdDlgsOStdWndsWinTypesWinProcs
Базовый объект TObject, наборы, потоки.Приложения, окна, полосы прокрутки,
окна MDI.Диалоговые блоки, диалоговые окна, управляющие элементы.Печать,
специальные распечатки.Проверка допустимости данных.Специализированные управляющие
элементы фирмыBorland.Диалоговые блоки имен файлов, однострочный ввод.Окна
текстового редактора, окна редактора файлов.Все типы, используемые подпрограммами
APIWindows 3.0, включая записи, стили, сообщений и флаги.Описания процедур
и функций для API Windows 3.0.
B.Pascal 7 & Objects/OW - 131 -
Файлы ресурсов
Модули OStdDlgs, OStdWnds и OPrinter имеют связанные с ними файлы ресурсов.
Ресурс модуля находится в файле с именем, эквивалентным имени модуля, и
расширением .RES. Ресурсы автоматически включаются при использовании соответствующих
модулей, так что программа, которая использует модуль OstdDlgs, будет автоматически
иметь доступ к ресурсам в OSTDDLGS.RES.
Файлы Windows 3.1
Кроме стандартных модулей API Windows 3.0, вы можете писать программы, использующие
преимущества средств, добавленных в версию 3.1 Windows. Каждая из 11 DLL
Windows 3.1 имеет соответствующий модуль:
Модули для доступа к средствам Windows 3.1 Таблица 7.2
Модуль Средство
ComDlgDDTMLDlgsLZExpandMMSystemOLEShellAPIStressToolHelpVerWin31 Общие диалоговые
блоки.Сообщения динамического обмена данными.Константы диалогового блока.Расширения
файла LZ.Расширения мультимедиа.Компоновка и встраивание объектов (OLE).Оболочка
API Windows.Строгая проверка типов.Отладка и другие инструментальные средства.Версии.Расширения
Windows 3.1.
B.Pascal 7 & Objects/OW - 132 -
Взаимодействие с Windows
ObjectWindows избавляет вас от многих утомительных и запутанных частей Windows,
но иногда возникает необходимость в непосредственном взаимодействии с Windows
(например, когда вы хотите переопределить некоторое заданное в Windows поведение
или выйти за рамки того, что инкапсулировано в ObjectWindows).
Существует два способа, с помощью которых вы можете взаимодействовать с
ObjectWindows: вызов ее функций API и получение сообщений. В данном разделе
описываются функции API. Об обработке сообщений рассказывается в Главе 16
"Сообщения Windows".
Функции API Windows
Функциональные возможности Windows заключены в ее около 600 функций. Каждая
функция имеет имя. Взаимодействовать с операционной средой Windows, модифицировать
ее отображение или действие в ответ на ввод пользователя можно с помощью
вызова функций API. Однако с помощью ObjectWindows вы можете создавать окна,
выводить диалоговые блоки и манипулировать управляющими элементами, не вызывая
функций Windows. Как все это работает?
Вызов в ObjectWindows функций API
Методы ObjectWindows вызывают функции API. Но ObjectWindows
- это не дублируемые функциональные возможности; она предоставляет в новом
пакете объектно-ориентированной библиотеки функции Windows, ее прикладной
программный интерфейс (API). Кроме того, ObjectWindows значительно упрощает
задачи спецификации многочисленных параметров, требуемых в функциях Windows.
Часто ObjectWindows автоматически подставляет параметры, такие как описатели
окон и идентификаторы дочерних окон, которые хранятся в интерфейсных объектах
в виде полей.
Например, многие функции Windows для задания окна, с которым они должны
работать, используют описатели окна, и эти функции вызываются обычно из
методов оконного объекта. Объекты содержат в поле HWindow описатель соответствующего
окна и может передавать его, освобождая вас от необходимости каждый раз
задавать описатель. Таким образом, объектные типы ObjectWindows служат объектно-ориентированным
слоем, реализованным с помощью вызовов необъектно-ориентированных функций
API.
B.Pascal 7 & Objects/OW - 133 -
Доступ к функциям API
Чтобы из приложения ObjectWindows обратиться непосредственно к функциям
API, вы должны использовать модуль WinProcs. WinProcs определяет для каждой
функции Windows заголовок процедуры или функции Паскаля, что позволяет вам
вызывать функции Windows как любую подпрограмму на Паскале. Перечень заголовков
этих функций вы можете найти в файле WINPROCS.PAS или в оперативном справочнике
Help.
Константы Windows
Функции Windows требуют от вас передачи в качестве аргументов разнообразных
констант типа Word или Longint. Эти константы представляют стили окна, диалогового
блока или управляющего элемента, а также возвращаемые значение и др. Если
в программе используются данные константы, она становится более читаемой,
обслуживаемой и будет более независимой от изменений в последующих версиях
Windows, чем программы, использующие числа. Определенные в модуле WinTypes
константы описываются в Главе 21 "Справочник по ObjectWindows".
Записи данных Windows
Некоторые функции Windows требуют более сложных структур данных, например,
шрифтов (TLongFont) или классов окон (TWndClass). Windows и ObjectWindows
определяют эти и другие структуры данных. Перечень доступных структур вы
можете найти в оперативном справочнике или в файле WINTYPES.PAS. Структуры,
непосредственно используемые в ObjectWindows, вы можете найти в Главе 21
"Справочник по ObjectWindows".
При использовании ObjectWindows все функции Windows доступны также непосредственно
и могут вызываться в вашей программе (если в ее операторе uses указывается
модуль WinProcs). Например, следующий код для получения окна сообщений вызывает
функцию Windows MessageBox:
Reply := MessageBox(HWindow, 'Хотите сохранить?',
'Файл изменен', mb_YesNo or mb_IconQuestion);
MessageBox возвращает целочисленное значение, указывающее, какое действие
выбрал пользователь для закрытия окна сообщения. Если пользователь щелкнул
"мышью" на командной кнопке Yes (Да), то результат равен определенной
в Windows целочисленной константе id_Yes. Если пользователь щелкнул "мышью"
на командной кнопке No (Нет), то результат равен id_No.
B.Pascal 7 & Objects/OW - 134 -
Комбинирование констант стилей
Функции Windows, позволяющие получить интерфейсные элементы, требуют обычно
некоторого параметра типа Word или Longint. Идентификаторы констант стилей
состоят из двухбуквенного мнемонического префикса, за которым следует подчеркивание
и описательное имя. Например, ws_Popup - это константа стиля окна (ws_ означает
стиль окна - window style").
Примечание: В Windows определены сотни констант стилей, которые перечислены
в Главе 21 "Справочник по ObjectWindows".
Часто эти стили комбинируются для получения другого стиля. Например, в случае
функции MessageBox вы можете передать в качестве параметра стиля mb_YesNo
или mb_IconQuestion. Этот стиль дает окно сообщений с двумя командными кнопками
Yes и No и пикторгаммой вопросительного знака. Поразрядная операция or фактически
комбинирует две константы бит за битом. Полученный в результате стиль представляет
собой комбинацию обоих стилей.
Имейте в виду, что некоторые стили взаимноисключающие. Их комбинирование
может дать непредвиденные или нежелательные результаты.
Типы функций Windows
Ниже перечислены виды функций Windows, которые вы можете использовать в
своих программах ObjectWindows.
Функции интерфейса с администратором Windows
Эти функции выполняют обработку сообщений, манипулируют окнами и диалоговыми
блоками и создают системный вывод. Данная категория включает в себя функции
для меню, курсоров и буфера вырезанного изображения.
Функции интерфейса
с графическими устройствами (GDI)
Эти функции выводят на разнообразные устройства (включая экран и принтер)
текст, графику и битовые массивы. Они не привязаны к конкретному устройству
и являются независимыми от устройства.
Функции интерфейса со служебными функциями системы
Эти функции работают с широким диапазоном системных устройств, включая управление
памятью, взаимодействие с операционной системой, администрирование ресурсов
и коммуникации.
B.Pascal 7 & Objects/OW - 135 -
Функции системного вызова
Windows содержит ряд функций, которые позволяют вам проходить в цикле (или
перечислять) определенные типы элементов в системе Windows. Например, перечислить
шрифты системы и напечатать образец текста, используя каждый из них. Чтобы
использовать такую функцию, вы должны передать указатель на нее (указатель
системной функции), и Windows будет использовать его в процессе перечисления.
Данная функция при итерации по списку характеристик окна, окон, дочерних
окон, шрифтов и т.д. вызывается непосредственно Windows.
Функции Windows, требующие функций системного вызова (или повторного вызова),
включают в себя: EnimChildWindows, EnumClipboardFormats, EnumFonts, EnumMetaFile,
EnumObjects, EnumPops, EnumTaskWindows и EnumWindows.
Функция системного вызова должна быть обычной функцией, а не методов объекта.
Указатель на эту функцию передается в качестве первого параметра (типа TFarProc)
данных методов. Например, если вы определили в Паскале функцию системного
вызова ActOnWindow следующим образом:
function ActOnWindow(TheHandle: HWnd; The Value: Longint):
Integer; far; export;
то можете передать ее в качестве функции системного вызова при
вызове функции Windows EnumWindows:
ReturnValue := EnumWindows(TFarProc(ActOnWindow), ALongint);
Функция системного вызова должна иметь тот же тип возвращаемого значения,
что и вызывающая ее функция Windows. Функция ActOnWindows будет выполнять
некоторое действие с окном, заданным переданным указателем. Параметр TheValue
- это любое значение, выбранное для передачи в вызывающей программе.
Директива компилятора $K+ позволяет автоматически управлять функциями системного
вызова. Если вы не выбираете $K+, то для возврата адреса, по которому будет
выполнять вызов Windows, должны передавать свои функции системного вызова
через функцию API MakeProcInstance.
B.Pascal 7 & Objects/OW - 136 -
Глава 8. Объекты приложения
При разработке приложения ObjectWindows вам нужно сначала определить объект
приложения, производный от типа ObjectWindows TApplication. Этот объект
инкапсулирует следующее поведение приложения ObjectWindows:
* Создание и вывод основного окна приложения.
* Инициализацию первого экземпляра приложения для задач, выполняемых всеми
экземплярами приложения, таких как создание файлов, совместно используемых
всеми экземплярами.
* Инициализацию каждого экземпляра приложения, например,
загрузку таблицы оперативных клавиш.
* Обработку сообщений Windows.
* Закрытие приложения.
Кроме определения объекта приложения вы должны добавить к нему возможность
построения объекта основного окна. Вы имеете также возможность переопределения
используемого по умолчанию поведения инициализированных экземпляров, закрытия
приложения и обработки сообщений Windows.
Минимальные требования
Чтобы ваше программа ObjectWindows стала рабочим приложением Windows, она
должна в своем основном блоке begin..end делать следующее:
- выполнять инициализацию;
- обрабатывать сообщения;
- по требованию завершать работу.
Используемый по умолчанию объект выполняет эти задачи путем вызова трех
его методов: Init, Run и Done. Основной блок любой программы ObjectWindows
содержит обычно эти три метода. Чтобы изменить поведение по умолчанию, методы
нужно переопределить.
Поиск объекта приложения
Когда программа выполняется, ObjectWindows поддерживает глобальную переменную
Application - указатель на объект приложения. Этот указатель позволяет подпрограммам
вне объекта приложения обращаться к его полям и методам. По умолчанию Application
устанавливается в @Self конструктором объекта приложения и в nil дест-
B.Pascal 7 & Objects/OW - 137 -
руктором объекта.
Минимальное приложение
Приведем пример минимального приложения ObjectWindows:
program MinApp;
uses OWindows;
var
MyApp: TApplication; begin
MyApp.Init('TtstApp');
MyApp.Run;
MyApp.Done; end;
MinApp - это абсолютный минимум приложения ObjectWindows. Эта программа
не требует определения других объектов. Обычно вы определяете новый объектные
типы как минимум для приложения и основного окна.
Методы Init, Run и Done
Так как в основном блоке программы ObjectWindows каждый раз используются
одни и те же операторы, вы должны понимать, что делает каждый из них.
Конструктор Init
Первый оператор - это вызов конструктора Init приложения. Этот вызов делает
следующее:
* Строит объект.
* Инициализирует поля данных объекта.
* Устанавливает глобальную переменную Application на объект
(@Self).
* Выполняет два вида инициализации:
- Вызывает InitApplication при отсутствии других выполняемых экземпляров
данного приложения.
- Всегда вызывает InitInstance, устанавливая вызовом InitMainWindow основное
окно.
Когда Init завершает работу, основное окно вашего приложения находится на
экране. В большинстве случаев вам нужно только переопределить InitMainWindow.
B.Pascal 7 & Objects/OW - 138 -
Метод Run
Второй оператор вызывает метод Run приложения, который реализует работу
приложения, вызывая MessageLoop. MessageLoop обрабатывает сообщения от Windows
и выполняет инструкции, которые управляют работой приложения. MessageLoop
- это цикл, который продолжает работу до закрытия приложения.
MessageLoop вызывает несколько методов, обрабатывающих конкретные поступающие
сообщения (см. далее).
Деструктор Done
Done - это деструктор объекта приложения. Перед завершением работы приложения
он освобождает память объекта приложения.
------------------ -------------------
| Init ----->| InitApplication |
------------------ | -------------------
|
| ------------------- ------------------
-->| InitInstance ---->| InitMainWindow |
------------------- ------------------
------------------ -------------------
| Run ----->| MessageLoop |
------------------ -------------------
Done
Рис. 8.1 Вызовы методов, управляющие работой приложения.
Инициализация приложения
Выполнение методов, инициализирующих объект приложения, позволяет вам настроить
части процесса путем переопределения отдельных методов. Один из методов,
требующий переопределения, чтобы приложения получило конкретный смысл -
это InitMainWindow. Вы моете также переопределить InitInstance и InitApplication.
B.Pascal 7 & Objects/OW - 139 -
Инициализация основного окна
Вы должны определить метод InitMainWindow, который строит и инициализирует
объект основного окна и сохраняет его в поле MainWindow объекта приложения.
Ниже показан пример описания объекта приложения и метода InitMainWindow.
Данный метод создает новый экземпляр типа TWindow
ObjectWindows (PWindow - это указатель на тип TWindow). Обычно ваша программа
будет определять для своего основного окна новый оконный тип, а InuitMainWindow
будет использовать этот тип вместо TWindow.
Примечание: Объекты окон подробно описываются в Главе
10.
Следующее простое приложение ObjectWindows объединяет в себе новый тип TMyApplication
и старое приложение MinApp. Оно отличается от MinApp только тем, что основное
окно имеет заголовок:
program TestApp;
uses OWindows;
type
TMyApplication = object(TApplication) procedure InitMainWindow; virtual;
end;
procedure TMyApplication.InitMainWindow;
begin
MainWindow := New(PWindow, Init(nil, 'Основное окно')); end;
var
MyApp: TApplication; begin
MyApp.Init('TestApp');
MyApp.Run;
MyApp.Done; end;
Программа TestApp выводит окно с заголовком 'Основное окно'. Вы можете легко
перемещать это окно и изменять его размер, минимизировать его, восстанавливать
или максимизировать. Закрытие окна завершает приложение. Короче, TestApp
- это полнофункциональный "скелет" приложения, оснащенный только
простейшим основным окном.
B.Pascal 7 & Objects/OW - 140 -
Специальный вывод основного окна
Начальный вывод основного окна управляется переменной CmdShow модуля System.
CmdShow содержит одну из констант sw_ и передается в качестве параметра
функции API Windows ShowWindow, когда приложение создает свое основное окно.
С помощью CmdShow вы легко можете вывести основное окно в нормальном виде
(по умолчанию), распахнутым до размеров полного экрана, минимизированным
в пиктограмму или скрытым. Лучшим местом присваивания значения CmdShow является
конструктор объекта основного окна. Это обеспечивает передачу выбранного
значения при создании элемента экрана.
Инициализация первого экземпляра
Если пользователь запускает приложение в отсутствии уже работающих других
экземпляров этого приложения, вы можете определить для такого первоначального
запуска некоторую обработку. Эта обработка называется инициализацией первого
экземпляра. Если пользователь начинает и завершает ваше приложение, затем
запускает его снова и т.д., каждый экземпляр будет первым экземпляром (поскольку
другие экземпляры в этот момент не выполняются).
Если текущим экземпляром является первый экземпляр, то конструктор Init
вызывает InitApplication. TApplication определяет заместитель метода InitApplication,
который вы можете для выполнения специальной инициализации первого экземпляра
переопределить.
B.Pascal 7 & Objects/OW - 141 -
Например, вы можете модифицировать TestApp таким образом, чтобы о первом
экземпляре сообщалось в заголовке основного окна. Для этого добавьте в тип
приложения TMyApplication булевское поле с именем FirstApp, затем переопределите
метод InitApplication, чтобы он устанавливал FirstApp в True. Наконец, модифицируйте
InitMainWindow для проверки FirstApp и вывода в основном окне приложения
соответствующего заголовка (см. Рис. 8.2).
----------------------------------------------------------
| = Первый экземпляр |^|v|
----------------------------------------------------------
| |
| ----------------------------------------------------------
| | = Дополнительный экземпляр |^|v|
| ----------------------------------------------------------
| | |
| | ----------------------------------------------------------
| | | = Дополнительный экземпляр |^|v|
| | ----------------------------------------------------------
| | | |
| | | |
---| | |
| | |
---| |
| |
----------------------------------------------------------
Рис. 8.2 Новая инициализация приложения.
program TestApp;
uses OWindows;
type
TMyApplication = object(TApplication)
FirstApp: Boolean;
procedure InitMainWindow; virtual;
procedure InitApplication; virtual;
end;
procedure TMyApplication.InitMainWindow;
begin
if FirstApp then
MainWindow := New(PWindow, Init(nil,
'Первый экземпляр'))
else MainWindow := New(PWindow, Init(nil,
'Дополнительный экземпляр'));
end;
procedure TMyApplication.InitApplication;
begin
FirstApp := True;
B.Pascal 7 & Objects/OW - 142 -
end;
var MyApp; TMyApplication;
begin
MyApp.Init('TestApp');
MyApp.Run;
MyApp.Done; end.
Инициализация каждого экземпляра
Пользователь может одновременно выполнять несколько экземпляров ObjectWindows.
Метод InitInstance инициализирует каждый экземпляр приложения. Он должен
инициализировать только само приложение, а не его основное окно. Основное
окно инициализируйте в InitMaionWindow.
InitInstance вызывает InitMainWindow, а затем создает и выводит основное
окно. Для модификации стандартной инициализации приложения (например, для
загрузки таблицы оперативных клавиш) вам нужно только переопределить InitInstance.
Если вы переопределяете для своего приложения InitInstance, убедитесь сначала,
что он вызывает метод InitInstance, наследуемый из TApplication.
Приведем метод InitInstance, который перед выполнением приложения загружает
метод InitInstance. 'MeHotKeys' - это идентификатор ресурса таблицы оперативных
клавиш, определенный в файле ресурса:
procedure TEditApplication.InitInstance;
begin
inherited InitInstance;
HAccTable := LoadAccelerators(HInstance, 'MyHotKeys'); end;
Вы можете также использовать InitInstance для регистрации экземпляра приложения
с внешней DLL (типа Paradox Engine).
B.Pascal 7 & Objects/OW - 143 -
Выполнение приложений
Метод Run вашего приложения вызывает метод MessageLoop, который вызывает
цикл обработки сообщений вашей программы. Во время выполнения вашей программы
в цикле обработки сообщений обрабатываются поступающие от Windows сообщения.
Программы ObjectWindows наследуют цикл MessageLoop, который работает автоматически.
Дополняйте цикл обработки сообщений только специальными диалогами, оперативными
клавишами или обработкой MDI.
Метод MessageLoop для обработки сообщений Windows вызывает три метода. ProcessDlgMsg
работает с безрежимными диалоговыми окнами, ProcessAccels - обрабатывает
оперативные клавиши, а ProcessMDIAccels - оперативные клавиши для приложений
MDI. Для приложений, не использующих командные клавиши или безрежимные диалоговые
окна или не являющихся приложениями MDI MessageLoop можно несколько упростить.
См. методы TApplication в Главе 21.
Закрытие приложений
Вызов деструктора Done в основной программе вашего приложения уничтожает
объект приложения. Однако, перед тем как это происходит, программа должна
прервать цикл обработки сообщения. Это может произойти, когда пользователь
пытается закрыть основное окно приложения. Мы говорим, что это может произойти,
так как ObjectWindows предусматривает механизм изменения поведения приложения
при закрытии: вы можете задавать условия закрытия.
Модификация поведения при закрытии
Все оконные объекты, наследуют булевский метод CanClose, возвращающий по
умолчанию True (что указывает на подтверждение закрытия, то есть TestApp
закрывается немедленно). Для изменения поведения при закрытии вы можете
переопределить методы CanClose приложения или основного типа окна. Если
какие-либо объекты возвращают из CanClose значение False, то приложение
завершиться не может. Обычно вы можете изменить поведение при закрытии объектного
типа основного окна. Например, перед завершением можно убедиться, что приложение
сохранило файлы.
Механизм CanClose
Механизм CanClose дает основному окну, объекту приложения и другим окнам
возможность подготовиться с закрытию или предотвратить его. В итоге объект
приложения должен разрешить закрытие приложения. По умолчанию он проверяет
основное окно. Обычная последовательность закрытия выглядит следующим образом:
1. Windows посылает основному окну приложения сообщение wm_Close.
B.Pascal 7 & Objects/OW - 144 -
2. Объект основного окна вызывает метод CanClose объекта приложения.
3. Объект приложения вызывает метод CanClose.
4. Объект основного окна вызывает метод CanClose для каждого из дочерних
окон и возвращает True только в том случае, если методы CanClose дочерних
окон возвращают True.
Модификация CanClose
Методы CanClose редко возвращают значение False. Вместо этого они должны
выполнять некоторые действия, позволяющие им возвращать True. Метод CanClose
должен возвращать False только в том случае, если он не может выполнить
действий, необходимых для нормального завершения, или пользователь показывает,
что он хочет продолжать выполнение программы.
Например, метод CanClose окна редактора может проверять изменение редактируемого
текста, а затем выводить диалоговое окно с запросом, нужно ли сохранить
текст перед закрытием, и воспринимать ответ Yes (Да), No (Нет) или Cancel
(Отмена). Cancel будет указывать, что пользователь пока не хочет закрывать
приложение, так что CanClose должен возвращать False. CanClose следует также
возвращать False при обнаружении ошибки в сохранении текста, предоставляя
пользователю другую возможность сохранения данных перед закрытием.
Если метод CanClose не переопределяется, тип основного окна наследует его
от TWindowsObject, где CanClose возвращает True после вызовов методов CanClose
дочерних окон. Чтобы модифицировать поведение при закрытии основного окна,
переопределите метод CanClose. Например, для проверки того, что пользователь
собирается закрыть окно, он может проверять открытые файлы.
B.Pascal 7 & Objects/OW - 145 -
Глава 9. Интерфейсные объекты
Объекты, представляющие окна, диалоговые окна и управляющие элементы, называются
интерфейсным объектами. В данной главе обсуждаются общие требования к интерфейсным
объектам и их поведение, а также взаимодействие с реальными окнами, диалоговыми
блоками и выводимыми на экран управляющими элементами.
В этой главе поясняется также взаимосвязь между различными интерфейсными
объектами приложения, а также механизм передачи сообщений Windows.
Примечание: Приводимый здесь материал относится к окнам, диалоговым блокам
и управляющим элементам.
Для чего нужны интерфейсные объекты?
Для чего нужны интерфейсные объекты, если в Windows уже есть окна, диалоговые
блоки и управляющие элементы?
Одна из основных трудностей программирования в Windows - это достаточно
сложная работа с визуальными элементами. Иногда вам нужно послать в окно
сообщение, в другой раз - вызвать функцию API Windows. Для разных типов
элементов экрана соглашения будут различными.
ObjectWindows уменьшает большую часть этих сложностей, предоставляя объекты,
инкапсулирующие элементы экрана и избавляющие вас от необходимости иметь
дело непосредственно с Windows. К тому же они обеспечивают более удобный
интерфейс.
Что делают интерфейсные объекты?
Интерфейсные объекты предоставляют методы для создания, инициализации, управления
и уничтожения соответствующих элементов экрана, и имеют содержащие данные
поля, включая описатель интерфейсного элемента и его порождающего и дочернего
окна. Методы объекта берут на себя многие детали программирования в Windows.
Взаимосвязь объект/элемент во многом аналогична связи файла DOS с переменной
Паскаля. Имея файл, вы можете присвоить файловую переменную, представляющую
физическую структуру фактического файла на диске, а затем работать с этой
файловой переменной. С помощью ObjectWindows вы можете определить объект,
представляющий физическое окно, управляющий элемент или диалоговый блок,
который фактически обслуживается администратором окон Windows. Вы работаете
с объектом, а он берет на себя функции по обслуживанию элемента экрана.
B.Pascal 7 & Objects/OW - 146 -
Общий интерфейсный объект
Все интерфейсные объекты ObjectWindows наследуют из единственного абстрактного
объектного типа TWindowsObject, который определяет поведение, общее для
окна, диалога и объектов управляющих элементов, видоизменяемых и специализируемых
в производных объектных типах TDialog, TWindow и TControl.
В качестве общего предка всех интерфейсных объектов методы TWindowsObject
обеспечивают единообразный способ поддержки взаимосвязи между объектами
и элементами экрана (включая создание и уничтожение объектов), обслуживают
соотношения "родитель-потомок" между интерфейсными объектами и
регистрируют новый классы Windows (см. Главу 10).
Новые типы, производные от TWindowsObject, определяются редко, но он служит
основой объектно-ориентированной модели окон. Он определяет большинство
наследуемых объектами функциональных возможностей, когда вы получаете из
TWindow и TDialog новые типы.
Создание интерфейсных объектов
Задание полного интерфейсного объекта с соответствующими интерфейсными элементами
требует двух шагов:
* Построения объекта.
* Создания элемента экрана.
Первым шагом является вызов конструктора Init, который строит интерфейсный
объект и устанавливает его атрибуты, такие как стиль и меню.
Второй шаг заключается в вызове метода создания окна объекта приложения,
MakeWindow, связывающего интерфейсный объект с новым элементом экрана. Эта
связь поддерживается полем HWindow экрана (описателем окна).
Примечание: Об описателях окон рассказывается в Главе 7 "Иерархия ObjectWindows".
MakeWindow вызывает метод Create объекта, который всегда сообщает Windows
о необходимости создания элемента на экране. Create создает также метод
SetupWindow, который инициализирует интерфейсный объект путем создания,
например, дочерних окон.
B.Pascal 7 & Objects/OW - 147 -
Допустимость описателя окна
Обычно в Windows вновь созданный интерфейсный элемент получает (от Windows)
сообщение wm_Create, на которое требуется ответить инициализацией. Интерфейсный
объект ObjectWindows не будет получать сообщений wm_Create, поэтому не забудьте
определить для инициализации метод SetupWindow.
Если инициализация интерфейсного объекта требует описателя элемента экрана
(например, для вызова функции API Windows), то она не должна вызываться
раньше SetupWindow. То есть, перед вызовом SetupWindow поле HWindow интерфейсного
объекта не является допустимым и использоваться не должно. Если вы хотите
вызывать функцию API или нечто требующее описателя окна, не вызывайте их
в конструкторе Init. Поместите такие вызовы в метод SetupWindow.
|<----HWindow допустим--->|
| |
|<-------------------интерфейсный объект допустим---------->| ----------------------------------------------------------------->
^ ^ ^ ^ ^
| | | | |
Init вызывает | | | |
наследуемый Init | | | |
| | Done |
SetupWindow вызывает наследуемый |
SetupWindow | Done вызывает наследуемый
| метод Done
|
Наследуемый SetupWindow вызывает Create
Рис. 9.1 Когда окно имеет допустимый описатель.
B.Pascal 7 & Objects/OW - 148 -
Видимость на экране
Создание интерфейсного объекта и соответствующего визуального элемента не
обязательно означает, что вы что-то видите на экране. Когда метод Create
указывает Windows на создание элемента экрана, Windows проверяет, включает
ли стиль окна ws_Visible. Если да, то интерфейсный элемент будет выводиться.
В противном случае он будет скрытым.
ws_Visible и другие стили окна обычно устанавливаются или сбрасываются конструктором
Init в поле Attr.Style объекта.
В любой момент после создания элемента экрана вы можете вывести или скрыть
его, вызвав метод Show интерфейсного объекта.
Уничтожение интерфейсных объектов
Как и в случае создания интерфейсный объектов, их уничтожение предполагает
выполнение двух шагов:
* Уничтожение визуального интерфейсного элемента (Destroy).
* Уничтожение интерфейсного объекта (Dispose).
Уничтожением экранного элемента занимается метод Destroy интерфейсного объекта,
который делает следующее: он вызывает функцию Windows DestroyWindow, чтобы
избавиться от элемента экрана, и устанавливает поле HWindow объекта в 0.
Таким образом, проверив указатель, вы можете сообщить, связан ли еще объект
с элементом экрана.
Уничтожить элемент экрана вы можете без уничтожения объекта (если хотите
создавать и выводить его снова).
Примечание: Уничтожение самого окна обычно не требуется. Это делается автоматически
при закрытии окна.
Когда пользователь закрывает на экране окно, ObjectWindows обнаруживает,
что данный элемент экрана уничтожен, устанавливает поле HWindow соответствующего
объекта в 0 и вызывает деструктор объекта Done.
B.Pascal 7 & Objects/OW - 149 -
Связь порождающего и дочернего объектов
В приложении Windows совместная работа элементов экрана (окон, диалоговых
блоков и управляющих элементов) обеспечивается с помощью связей "родитель-потомок".
Порождающие окна управляют своими дочерними окнами, а Windows отслеживает
эти связи. ObjectWindows поддерживает параллельный набор связей между соответствующими
интерфейсными объектами.
Дочернее окно - это элемент экрана (оно не обязано быть окном), который
управляется другим элементом экрана. Например, блоки списка обслуживаются
окном или диалоговым блоком, в котором они выводятся. Они выводятся на экран
только при выводе их порождающих окон. Диалоговые блоки, в свою очередь,
являются дочерними окнами, управляемыми порождающими их окнами.
Когда вы перемещаете или закрываете порождающее окно, дочерние окна автоматически
закрываются, и в некоторых случаях перемещаются в нем. Конечным предком
всех дочерних интерфейсных элементов является основное окно, хотя вы можете
иметь окна и диалоги без порождающих окон.
Порождающими окнами могут быть только диалоговые блоки и окна, но не порождающие
элементы. Дочерним окном может быть любой интерфейсный элемент.
Список дочерних окон
Когда вы строите объект дочернего окна, то можете в качестве параметра конструктора
Init можете задать порождающее окно (пример вы можете найти в Главе 10).
Объект дочернего окна отслеживает свое порождающее окно через указатель
на его поле Parent. Он отслеживает также объекты его дочерних окон, сохраненные
в поле ChildList. Дочернее окно, на которое в данный момент установлен ChildList,
является последним созданным дочерним окном.
B.Pascal 7 & Objects/OW - 150 -
Построение дочерних окон
Как и в случае интерфейсных объектов, объекты дочерних окон создаются в
два этапа (построение объекта и создание элемента экрана). Объекты порожденного
окна следует строить с помощью конструктора Init порождающего окна. Например,
объект окна, наследующий из TWindow и содержащий командную кнопку должен
иметь примерно следующий вид:
constructor TMyWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
TheButton := New(PButton, Init(@Self, id_TheButton,
'Текст кнопки', 20, 10, 100, 25, True));
end;
Обратите внимание на использование указателя Self для связи дочернего объекта
(TheButton) с порождающим (экземпляром TMyWindow). Конструктор интерфейсного
объекта автоматически добавляет к своему списку дочерних окон новые объекты.
Создание дочерних элементов экрана
Когда построен список дочерних элементов интерфейсного объекта, создание
элементов экрана для дочерних окон выполняется автоматически. Создание родительского
окна (через вызов MakeWindow) включает в себя вызов метода SetupWindow порождающего
окна. Одним из наследуемых действий SetupWindow является вызов для каждого
из окон в списке дочерних окон методов SetupWindow.
Примечание: Автоматическое создание можно запретить. См. ниже раздел "Запрещение
автоматического создания".
При создании нового производного объектного типа нужно помнить об инициализации
объекта в SetupWindow после вызова наследуемого метода SetupWindow, например:
procedure TMyCheckBox.SetupWindow;
begin
inherited SetupWindow; сначала по умолчанию
.
.
. выполнить инициализацию объекта
end;
Уничтожение дочерних окон
Вызов деструктора порождающего окна приводит к вызову деструкторов всех
его дочерних окон, так что вашей программе не нужно
B.Pascal 7 & Objects/OW - 151 -
явно вызывать деструкторы дочернего окна. Это же справедливо для
метода CanClose, который возвращает True только после вызова
CanClose для всех его дочерних окон.
Запрещение автоматического создания
Чтобы явно исключить дочернее окно из механизма автоматического создания
и вывода, вызовите после его создания метод DisableAutoCreate. Чтобы явно
добавить в механизм создания и вывода дочернее окно (такое как диалоговый
блок, который при нормальном выводе будет исключен), вызовите после построения
его метод EnableAutoCreate.
Итерация дочерних окон
Иногда желательно написать методы, для реализации функции выполняющие итерации
по каждому дочернему окну данного окна. Например, можно проверить в окне
все кнопки с независимой фиксацией. В этом случае используйте метод TWindowsObject.ForEach:
procedure TMyWindow.CheckAllBoxes;
procedure CheckTheBox(ABox: PWindowsObject); far;
begin
PCheckBox(ABox)^.Check; end;
begin
ForEach(@CheckTheBox); end;
Использование метода ForEach (и аналогичных методов
FirstThat и LastThat) похоже на применение методов с аналогичными названиями
в TCollection. Хотя ObjectWindows не использует наборы для обслуживания
дочерних окон, методы итерации работают аналогично.
Поиск определенного дочернего окна
Иногда желательно иметь методы, выполняющие итерацию по списку окон в поиске
конкретного окна. Например, в окне с несколькими кнопками вам может потребоваться
найти первую установленную кнопку с независимой фиксацией. В этом случае
метод TWindowsObject.FirstThat можно записать так:
function TMyWindow.GetFirstChecked: PWindowsObject;
function IsThisOneChecked(ABox: PWindowsObject): Boolean;
far;
begin
B.Pascal 7 & Objects/OW - 152 -
IsThisOneChecked := (ABox^.GetCheck = bf_Checked); end;
begin
GetFirstChecked := FirstThat(@IsThisOneChecked); end;
B.Pascal 7 & Objects/OW - 153 -
Глава 10. Объекты окон
Объекты окон (или оконные объекты) - это интерфейсные объекты, предназначенные
для облегчения работы с окнами. В данной главе поясняется, как создавать
и заполнять окна приложения. Это предусматривает следующие задачи:
* Инициализацию оконных объектов.
* Установку атрибутов создания.
* Создание экранных элементов окна.
* Установку атрибутов регистрации.
* Использование специализированных окон.
* Прокрутку окон.
Что такое объекты окон?
Термин "объект окна" относится к любому интерфейсному объекту,
представляющему окно, а в Windows это почти все, что выводится на экран.
В качестве шаблона определения большей части фундаментального поведения
основного окна и любого всплывающего окна приложения ObjectWindows использует
тип TWindow.
Окна, которые не являются окнами
TWindow имеет три типа-потомка: TMDIWindow, TControl и TEditWindow, так
что все они также являются оконными объектами, хотя на самом деле это не
окна в полном смысле слова. Типы MDI используются в приложениях ObjectWindows,
которые соответствуют стандарту многодокументального интерфейса Windows.
Об MDI и этих типах рассказывается в Главе 14. TControl определяет управляющие
элементы, такие как командные кнопки и блоки списков (см. Главу
12). Чаще всего новые оконные типы являются производными от TWindow.
Эта глава охватывает типы TWindow и TEditWindow и содержит примеры регистрации
новых классов окон.
B.Pascal 7 & Objects/OW - 154 -
Где найти объекты окон
Каждое приложение 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.
B.Pascal 7 & Objects/OW - 155 -
Установка атрибутов создания
Типичное приложение Windows имеет много различных типов окон: перекрывающиеся
или всплывающие, окна с рамкой, прокручиваемые окна, окна с заголовком и
др. Эти атрибуты стилей, а также заголовок и меню окна задаются при инициализации
оконного объекта и используются при создании элементов окна.
Атрибуты создания оконного объекта, такие как стиль, заголовок и меню, записываются
в поле Attr объекта - записи типа TWindowAttr. TWindowAttr содержит следующие
поля:
Атрибуты создания окна Таблица 10.1
Поле Тип Использование
TitleStyleMenuXYWH PCharLongintHMenuIntegerIntegerIntegerInteger Строка
заголовка.Комбинированная константа стиля.Описатель ресурса меню.Горизонтальная
координата экранаверхнего левого угла окна.Вертикальная координата экранаверхнего
левого угла окна.Начальная ширина окна в координа-тах экрана.Начальная высота
окна в координа-тах экрана.
B.Pascal 7 & Objects/OW - 156 -
^
(0,0)
(X,Y)
v
-------------------------------------------------
| Title | | | ^
----------------------------------------------- |
| 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 вы обычно устанавливаете сами.
B.Pascal 7 & Objects/OW - 157 -
Переопределение используемых по умолчанию атрибутов
При создании новых оконных типов, производных от 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 порождающего ок-
B.Pascal 7 & Objects/OW - 158 -
на):
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 динамически
на этапе выполне-
B.Pascal 7 & Objects/OW - 159 -
ния.
Примечание: Дочерние окна и SetupWindow описываются в Главе 9 "Интерфейсный
объекты".
В общем случае порождающие окна обычно вызывают для своих дочерних окон
методы Init и MakeWindow. Атрибуты оконного объекта обычно устанавливаются
их методами объекта порождающего окна. Поскольку основное окно приложения
не имеет порождающего окна, объект приложения строит и создает его при запуске
приложения.
Задание атрибутов регистрации
В ходе инициализации оконного объекта путем заполнения поля объекта Attr
вы можете установить несколько атрибутов окна, такие как его стиль, расположение
и меню. Эти атрибуты используются для создания соответствующего оконного
элемента, поэтому они называются атрибутами создания.
Другие атрибуты, включая фоновый цвет, пиктограмму представления и курсора
"мыши", более тесно связаны с данным типом оконного объекта и
не могут изменяться в ходе работы программы. Эти присущие окну атрибуты
называются атрибутами регистрации, так как они устанавливаются при регистрации
класса окна в Windows.
B.Pascal 7 & Objects/OW - 160 -
Классы окон
С каждым типом оконного объекта связан список атрибутов регистрации, которые
называются классом окна. Список атрибутов регистрации во многом напоминает
список атрибутов создания, записанных в поле записи Attr объекта окна. Однако,
атрибуты регистрации сохраняются в записи с именем TWndClass, который определяется
и поддерживается Windows.
Процесс связи класса окна с типом оконного объекта называется регистрацией
класса окна. ObjectWindows автоматизирует процесс регистрации. Таким образом,
если вы хотите изменить какую-либо из используемых по умолчанию характеристик
объекта, то можете не беспокоиться о классе регистрации окна.
Поля записи TWndClass и их типы перечислены в следующей таблице:
Атрибуты регистрации окна Таблица 10.2
Характеристика Поле Тип
стиль классапиктограммакурсорфоновый цветменю по умолчанию stylehIconhCursorhbrBackgroundlpszMenuName
WordHIconHCursorHBrushPChar
Поля стиля класса
Это поле стиля отличается от атрибута стиля окна (ws_), задаваемого при
инициализации окна, поскольку задает поведение, присущее операциям окна
(в отличие от их визуального представления). Это поле может заполняться
комбинацией констант стиля (cs_).
Например, cs_HRedraw приводит к повторному отображению окна при изменении
его размера по горизонтали; cs_DoubleClk позволяет окну получать сообщения
о двойном нажатии кнопки "мыши"; cs_NoClose предотвращает выбор
параметра Close меню Control, а cs_ParentDC дает окну контекст дисплея порождающего
окна.
Поле пиктограммы
Это поле содержит описатель пиктограммы, которое используется для представления
окна в его минимизированном состоянии. Обычно для представления основного
окна программы выбирается ресурс пиктограммы.
Поле курсора
B.Pascal 7 & Objects/OW - 161 -
Поле hCursor содержит описатель курсора, который используется для представления
указателя "мыши" при позиционировании его в окне.
Поле фонового цвета
Это поле задает фоновый цвет окна. Для большинства приложений используется
стандартный назначаемый по умолчанию цвет окна, который может устанавливаться
пользователем в управляющей панели. Однако вы можете путем установки этого
поля в описатель физической кисти подставить конкретный цвет. Либо вы можете
установить любое из значений цветов Windows, такие как color_ActiveCaption.
К любому значению цвета всегда добавляйте 1.
Поле используемого по умолчанию меню
Это поле указывает на имя ресурса меню, которое служит используемым по умолчанию
меню для данного класса. Например, если вы определите тип EditWindow, который
всегда имеет стандартное меню редактирования, то можете задать здесь это
меню. Это устранит необходимость задания меню в методе Init. Если данный
ресурс меню имеет идентификатор 'MyMenu', вы можете установить это поле
следующим образом:
AWndClass.IpszMenuName := 'MyMenu';
B.Pascal 7 & Objects/OW - 162 -
Используемые по умолчанию атрибуты регистрации
Тип TWindow определяет класс окна 'TurboWindow' с пустой пиктограммой, курсором-стрелкой
и стандартным цветом окна. Используемый по умолчанию класс ObjectWindows
(TurboWindow) имеет следующие атрибуты:
* стиль: cs_HRedraw or cs_VRedraw (повторное отображение
после каждого изменения размера);
* пиктограмма: idi_Application (пустой прямоугольник);
* курсор: idc_Arrow (стандартная стрелка Windows);
* фоновый цвет: HBrush(color_Window + 1);
* меню по умолчанию: nil.
Регистрация нового класса
Чтобы изменить атрибут регистрации, такой как курсор или пиктограмму, вам
нужно написать два метода - GetClassName и GetWindowClass - и определить
новый класс окна. Каждый раз, когда вы изменяете атрибуты регистрации, вам
нужно изменить имя класса. Если класс регистрации с данным именем уже зарегистрирован
в Windows, другие классы с тем же именем класса регистрироваться не будут
- они получат атрибуты уже зарегистрированного класса.
B.Pascal 7 & Objects/OW - 163 -
Изменение имени класса
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 - это константа, представляющая
B.Pascal 7 & Objects/OW - 164 -
один из курсоров Windows.
Кроме окон, диалоговым окнам (не диалоговым блокам) необходимо регистрировать
классы окна (см. Главу 11). Диалоговым блокам и управляющим элементам классы
окон не требуются.
B.Pascal 7 & Objects/OW - 165 -
Использование специализированных окон
ObjectWindows предусматривает два потомка TWindow, являющихся специализированными
окнами для редактирования текста. Объектный тип TEditWindow обеспечивает
простой текстовый редактор, не обладающий возможностями чтения из файла
или записи в него. Тип TFileWindow, наследующий из TEditWindow, обеспечивает
текстовый редактор с возможностями чтения/записи файлов.
Эти объекты можно использовать непосредственно как стандартные компоненты
ваших приложений. Вы можете также построить производные от них типы и создать
свои собственные специализированные редакторы. Программы или модули, использующие
окна редактирования или файловые окна, должны включать в свой оператор uses
модуль OStdWnds.
Использование окон редактирования
Окно редактирования - это окно с управляющим элементом редактирования, заполняющим
его область клиента. TEditWindow.Init инициализирует поле Editor окна редактирования,
чтобы оно указывало на управляющий элемент объекта редактирования. TEditWindow.SetupWindow
устанавливает размеры управляющего элемента редактирования в соответствии
с областью клиента окна и создает экранный управляющий элемент редактирования.
Метод WMSize обеспечивает изменение размера управляющего элемента редактирования
при изменении размера его окна. Метод WMSetFocus обеспечивает, что управляющий
элемент редактирования получает фокус ввода при получении окном сообщения
wm_SetFocus.
B.Pascal 7 & Objects/OW - 166 -
Показанная ниже программа EditWindowTester использует окно редактирования,
чтобы пользователь мог редактировать текст для простой (нефункциональной)
электронной почты.
Edit Window Tester
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);
B.Pascal 7 & Objects/OW - 167 -
var
Lines: Integer;
TestString: string[3];
Text: array[0..20] 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 таким
образом, чтобы оно указывало на файловый диалоговый объект.
B.Pascal 7 & Objects/OW - 168 -
Для работы с файлами TFileWindow имеет четыре метода. Методы Open, Save
и SaveAs для вывода пользователю подсказки с именем файла используют поле
TFileWindow.FileDialog (см. Главу 11). Метод New дает пользователю возможность
отмены, если редактирование нового файла приведет к потере изменений текущего
текста. Чтобы дать пользователю возможность доступа к этим методам, создайте
свое меню со следующими идентификаторами меню:
Методы и идентификаторы меню файлового окна Таблица 10.3
Метод Идентификатор меню для вызова
NewOpenSaveSaveAs cmcmcmcm FileNewFileOpenFileSaveFileSaveAs
Вы можете использовать файловые окна без модификации как простые автономные
текстовые редакторы. Однако, иногда желательно создать производные от
TFileWindow типы и обеспечить дополнительные функциональные возможности.
Например, можно предусмотреть средство поиска. Помните, что вы все равно
будете иметь доступ к управляющему элементу редактирования TFileWindow.Editor.
Прокрутка содержимого окон
В большинстве случаев для прокрутки текущей области просмотра пользователи
используют полосы прокрутки вдоль края окна. В отличие от стандартных
управляющих элементов типа полос прокрутки полосы прокрутки окна являются
частью самого окна.
ObjectWindows управляет прокруткой окна, предоставляя каждому оконному
объекту поле Scroller, которое может указывать на объект TScroller. Объект
прокрутки TScroller обеспечивает автоматизированный способ прокрутки в
окнах текста и графики. Кроме того, TScroller может прокручивать окна,
когда пользователь перемещает "мышь" за область клиента окна
(это называется автоматической прокруткой и действует даже для окон, которые
не имеют полос прокрутки).
B.Pascal 7 & Objects/OW - 169 -
Что такое объект прокрутки?
TScroller содержит значения, определяющие, насколько должно прокручивается
окно. Эти значения записываются в полях XUnit, YUnit, XLine, YLine, XRange,
YRange, XPage и YPage объекта TScroller. Поля, начинающиеся с буквы X,
представляют горизонтальные значения, а начинающиеся с буквы Y - вертикальные.
Единицы прокрутки
Единица прокрутки определяет минимальную величину прокрутки. Она задается
в наименьших единицах устройства (обычно в элементах изображения, но может
зависеть от текущего режима отображения), на которые вы можете выполнять
прокрутку в горизонтальном или вертикальном направлении. Это значение
обычно основывается на виде выводимой на экран информации.
Например, если вы выводите текст с шириной символа 8 элементов изображения
и высотой 15, то в качестве значений XUnit и YUnit полезно задать, соответственно,
8 и 15.
Строки, страницы и диапазон
Другие атрибуты прокрутки - строка, страница и диапазон - выражаются в
единицах прокрутки. Значения Line (строка) и Page (страница) - это число
единиц, на которые выполняется прокрутка в ответ на запрос пользователя.
Запрос может иметь форму щелчка кнопкой "мыши" на концах полосы
прокрутки (построчная прокрутка). Щелчок "мышью" в самой полосе
прокрутки (но не на маркере полосы прокрутки) позволяет выполнять постраничную
прокрутку. Атрибуты диапазона (XRange, YRange) представляют общее число
единиц, на которое можно выполнять прокрутку. Обычно этот диапазон определяется
на основе размера редактируемого документа.
B.Pascal 7 & Objects/OW - 170 -
Типичный объект прокрутки
В качестве примера рассмотрим текстовое окно редактирования. Если вы хотите
вывести на экран текстовый файл, имеющий 400 строк текста с границей 80
символов и 50 строками на странице, то можно выбрать следующие значения:
Типичные значения для окна редактирования Таблица 10.4
Поле Значение Смысл
XUnitYUnitXLine, YLineXPageYPageXRangeYRange 8151405080400 ширина символавысота
символа1 единица на строку40 символов по горизонтали на страницу50 символов
по вертикали на страницумаксимальный горизонтальныйдиапазонмаксимальный
вертикальный ди-апазон
Объект TScroller с данными значениями позволяет выполнять построчную или
постраничную прокрутку. С помощью полос прокрутки или автоматической прокрутки
выполняется просмотр всего файла.
Значения по умолчанию
По умолчанию XLine и YLine имеют значение 1, так что без явной необходимости
устанавливать их в другие значения не нужно. Для установки значений прокрутки
на страницу также существует используемая по умолчанию схема, согласно
которой страница прокрутки будет соответствовать текущей высоте или ширине
области клиента окна (в зависимости от направлений прокрутки). Если вы
не хотите переопределить данный механизм, переустанавливать эти значения
не требуется.
B.Pascal 7 & Objects/OW - 171 -
Задание для окна объекта прокрутки
Чтобы задать для окна объект прокрутки, постройте в конструкторе своего
оконного объекта объект 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;
B.Pascal 7 & Objects/OW - 172 -
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.
B.Pascal 7 & Objects/OW - 173 -
Запрещение автоматической прокрутки
Объект TScroller может по умолчанию выполнять автоматическую прокрутку,
но установка поля AutoMode TScroller в значение False отключает это средство.
Окно-владелец может сделать это в конструкторе после построения объекта
TScroller:
Scroller := New(PScroller, Init(@Self, 8, 15, 80, 60));
Scroller^.AutoMode :=False;
Если AutoMode равно False, то прокрутка может выполняться только с помощью
полос прокрутки. Полезная особенность автоматической прокрутки состоит
в том, что чем дальше вы сдвинете "мышь" от области клиента
окна, тем быстрее будет происходить прокрутка окна. В зависимости от удаления
мыши приращение прокрутки будет обратно пропорционально значению параметра
строк и прямо пропорционально значению параметра страницы.
Отслеживание полос прокрутки
В дополнение к автоматической прокрутке, приведенный выше пример программы
будет отслеживать запросы на прокрутку, сдвигая при нажатой кнопке "мыши"
маркер полосы прокрутки. Другими словами картинка сдвигается уже при нажатой
кнопке. Эта особенность дает действительную обратную связь, и пользователь
может сдвигать нужную часть изображения не отпуская кнопку "мыши".
Однако, в некоторых случаях этот эффект нежелателен. Например, если вы
просматриваете большой текстовый файл, такое отслеживание может замедлить
работу, поскольку возникает необходимость постоянно считывать информацию
с диска и отображать порцию текста для каждого движения "мыши".
В такой ситуации лучше отменить этот эффект:
Scroller^.TrackMode:=False;
Теперь никакой прокрутки не происходит до момента отпускания кнопки на
мыши, и в области клиента будет лишь однократно показана нужная часть
картинки.
B.Pascal 7 & Objects/OW - 174 -
Модификация единиц прокрутки и диапазона
В приведенных выше примерах мы предполагали, что к моменту построения
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);
B.Pascal 7 & Objects/OW - 175 -
Метод 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) и его высота
B.Pascal 7 & Objects/OW - 176 -
(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;
B.Pascal 7 & Objects/OW - 177 -
Глава 11. Объекты диалоговых блоков
Блоки диалога, или просто диалоги, являются интерфейсными объектами, инкапсулирующими
поведение диалоговых блоков. Это дочерние окнам, которые обычно выводятся
для выполнения специфических задач (например, конфигурирования принтера
или организации ввода текста). Объект TDialog обеспечивает инициализацию,
создание и исполнение всех типов блоков диалога. Для каждого типа диалога
вашего приложения, как и в случае оконных объектов, вы можете определить
производные от TDialog диалоговые блоки.
ObjectWindows всегда предоставляет два типа диалогов наиболее общего типа,
ввод текста и диалог файла. Кроме того, в ObjectWindows имеется тип TDlgWindow,
который позволяет вам создавать диалоги, поведение которых более похоже
на окно.
Данная глава охватывает следующие темы:
* Использование объектов диалоговых блоков.
* Работа с управляющими элементами в диалоговых блоках.
* Связь объектов с управляющими элементами.
* Связь окон с ресурсами.
Использование объектов диалоговых блоков
Использование объектов диалоговых блоков аналогично использованию объектов
всплывающего окна. Диалоги являются дочерними окнами своего порождающего
окна. Для простых диалоговых блоков, которые появляются на короткое время,
вся обработка диалога может быть выполнена одним методом объекта порождающего
окна. Диалог может быть сконструирован, выполнен и удален в одном методе,
и нет необходимости хранить диалог в поле объекта. Для более сложных диалогов
может потребоваться записать диалоговый блок в поле оконного объекта вашего
диалогового блока.
Подобно всплывающим окнам и управляющим элементам, диалоговые блоки являются
дочерними окнами и при конструировании добавляются к списку ChildList
порождающих окон.
Использование объекта диалогового блока предусматривает следующие шаги:
* Построение объекта.
* Выполнение диалогового окна.
* Закрытие диалогового окна.
B.Pascal 7 & Objects/OW - 178 -
Построение объекта
Диалоговые блоки конструируются и специфицируются с помощью описания ресурса,
создаваемого вне программы. Ресурс диалогового окна описывает внешний
вид и размещение управляющих элементов, таких как кнопок, блоков списка,
областей редактирования и текстовых строк. Он описывает только внешний
вид диалогового блока и не касается его поведения - за это отвечает прикладная
программа.
Каждый ресурс диалогового блока имеет идентификатор, который может быть
номером идентификатора (Word) или строкой (PChar). Этот идентификатор
позволяет объекту диалогового блока задавать, какой ресурс используется
для определения его внешнего вида.
Вызов конструктора
Чтобы построить объект диалогового блока, вызовите конструктор Init. Init
воспринимает в качестве своих параметров указатель на порождающее окно
и параметр типа PChar, представляющий имя ресурса диалога:
ADlg:=New(PSampleDialog, Init(@Self, 'EMPLOYEEINFO'));
Если идентификатор задается номером, его требуется привести с помощью
MakeIntResource к PChar:
Dlg := New(PSampleDialog, Init(@Self, PChar(120)));
Так как диалоговые блоки обычно строятся внутри метода оконного объекта,
порождающее окно почти всегда задается как Self. Объекты диалоговых блоков,
не создаваемые оконными объектами, должны иметь в качестве порождающего
Applicartion^.MainWindow (поскольку это единственный оконный объект, всегда
присутствующий в каждой программе ObjectWindows).
Выполнение диалоговых блоков
Выполнение диалогов аналогично созданию и отображению окна. Однако, поскольку
диалоги обычно появляются на более короткий отрезок времени, некоторые
этапы могут быть сокращены. Это в значительной степени зависит от того,
будет ли диалоговый блок отображаться как режимный или безрежимный.
B.Pascal 7 & Objects/OW - 179 -
Режимные и безрежимные диалоговые блоки
Режимные диалоговые блоки являются наиболее общими блоками диалога. Аналогично
генерируемым функцией MessageBox блокам сообщений, режимные диалоги отображаются
для специфических целей на короткий отрезок времени. Слово "режимный"
означает, что пока отображается диалог, пользователь не может выбрать
или использовать его порождающее окно. Пользователь должен воспользоваться
диалогом и выбрать командную кнопку OK или Cancel для прекращения диалога
и возвращению к работе с программой. Режимный диалог как бы "замораживает"
выполнение оставшейся части программы.
Безрежимный диалоговый блок не приостанавливает выполнения программы.
Как и оконный объект, он может создаваться и выполняться в одном шаге
с помощью MakeWindow:
Application^.MakeWindow(ADlg);
В любое момент вы можете считать данные из диалогового окна (если объект
диалогового блока еще существует). Чаще всего это выполняется в методе
OK, который вызывается при активизации пользователем командной кнопки
OK.
Выполнения режимных диалоговых блоков
В случае режимных диалоговых блоков лучше всего, вероятно, строить, выполнять
и уничтожать все объекты в одном методе (как показано в примерах данной
главы). Таким образом, при каждом выводе диалогового блока это будет новый
объект.
Объекты приложения имеют режимный эквивалент MakeWindow, который называется
ExecDialog. Аналогично MakeWindows, ExecDialog проверяет допустимость
передаваемого объекта диалогового блока (то есть успешность выполнения
конструктора объекта и отсутствие ситуации нехватки памяти), а затем выполняет
диалоговый блок, делая его модальным.
ExecDialog возвращает целочисленное значение, указывающее, что пользователь
закрывает диалоговое окно. Возвращаемое значение
- это идентификатор задействованного пользователем управляющего элемента,
такой как id_Ok для командной кнопки OK или id_Cancel для командной кнопки
Cancel. После завершения выполнения диалогового окна ExecDialog уничтожает
объект диалогового окна.
Таким образом, с помощью одного вызова метода ExecDialog вы можете создать,
вывести на экран и завершить диалоговый блок.
ADlg := New(PSampleDialog, Init(@Self, 'RESOURCEID'));
ReturnValue := Application^.ExecDialog(ADlg); if ReturnValue = id_OK then
кодирование для выборки данных и обработки диалога
B.Pascal 7 & Objects/OW - 180 -
else
if ReturnValue = id_Cancel then нажата Cancel
Выполнение безрежимных диалоговых блоков
Безрежимные диалоги похожи на всплывающие окна и управляющие элементы.
Основная причина, по которой вы не можете удалять безрежимными диалогами
сразу же после их отработки (в отличие от режимных), состоит в том, что
вы заранее не знаете, когда пользователь закроет блок диалога. (Помните
о том, что в режимных диалогах метод ExecDialog не возвращает значения
до закрытия диалога.) Следовательно лучше всего конструировать безрежимные
диалоги в конструкторе его порождающего окна и хранить в поле порождающего
объекта.
В отличие от окон и объектов управления, используемых в качестве дочерних
окон, диалоги автоматически не отображаются при выводе их порождающих
окон.
constructor ParentWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
TWindow.Init(AParent, ATitle);
ADlg := New(PSampleDialog, Init(@Self, 'EMPLOYEEINFO')); end;
Затем, каждый раз, когда вы хотите отобразить диалог, создайте и выведите
его:
begin
Application^.MakeWindow(ADlg) end;
И, наконец, отдельный объект диалога будет автоматически удаляться при
закрытии его порождающего окна.
Работа с безрежимными диалоговыми блоками
Диалоговые блоки отличаются от других дочерних окон, таких как всплывающие
окна и управляющие элементы, тем, что они за время существования своего
порождающего окна создаются и уничтожаются многократно и редко выводятся
на экран и уничтожаются вместе с порождающим окном. Обычно программа создает
диалоговый блок в ответ на выбор меню, щелчок кнопкой "мыши",
ошибку или другое событие.
Таким образом, нужно убедиться, что вы не строите объекты диалоговых блоков
снова и снова, не уничтожая их. Помните о том, что все построенные диалоговые
объекты автоматически включаются в списки дочерних окон их порождающих
окон.
B.Pascal 7 & Objects/OW - 181 -
Примечание: К режимным диалоговым блокам это не относится, так как они
автоматически уничтожаются при закрытии.
Завершение диалогов
Каждый блок диалога должен иметь способ его закрытия пользователем. Чаще
всего это кнопки OK и/или Cancel. Потомки TDialog автоматически отреагируют
на нажатие одной из этих кнопок вызовом метода EndDlg, который заканчивает
диалог. Вы можете разработать новые средства завершения диалога, если
только они приводят к вызову EndDlg. Для изменения поведения при закрытии
вы можете переопределить методы OK и Cancel.
Например, вы можете переопределить метод OK таким образом, что введенные
данные будут копироваться в буфер, который находится вне объекта блока
диалога. Если ввод был осуществлен некорректно, вы можете вывести блок
сообщения или сгенерировать звуковой сигнал. Если ввод был сделан верно,
вы можете вызвать EdnDlg. Переданное в EndDlg значение становится возвращаемым
значением ExecDialog.
Как и в случае оконных объектов, объект диалога вызывает CanClose до закрытия
блока диалога, как это имело место для объектов окна. Вы можете переписать
CanClose для учета условий закрытия, как для блока диалога, который проверяет
ввод пользователя. При переписывании CanClose нужно быть уверенным в том,
что вызывается унаследованный от него метод, т.к. он вызывает методы CanClose
дочерних окон.
B.Pascal 7 & Objects/OW - 182 -
Работа с управляющими элементами
Все блоки диалога, кроме самых простейших, имеют (как дочерние окна) несколько
управляющих элементов (например, управления редактированием, блоки списка
и командные кнопки). Обратите внимание на то, что эти управляющие элементы
являются не объектами управляющих элементов, а только управляющими интерфейсными
элементами, без методов и полей объекта. Эта глава кроме того показывает
альтернативные методы, позволяющие связывать объекты управления с элементами
управления диалоговых блоков с использованием InitResource.
Примечание: Использование управляющих объектов в окне (но не блоков диалога)
показано в Главе 12.
Между объектом диалога и его элементами управления имеется двухсторонняя
связь (можно сказать диалог). С одной стороны диалогу нужно манипулировать
его управляющими элементами, например, для заполнения блока списка. С
другой стороны ему нужно обрабатывать и реагировать на сгенерированные
сообщения управляющих событий, например, когда пользователь выбирает элемент
блока списка.
Взаимодействие с управляющим элементом
Windows определят набор сообщений управляющих элементов, которые посылаются
от приложения к Windows. Например, имеются следующие сообщения блока списка:
lb_GetText, lb_GetCurSel и lb_AddString. Сообщения управляющих элементов
задают специфическое управление и несут с собой информацию в аргументах
wParam и lParam. Каждый управляющий элемент в ресурсе диалога имеет номер
идентификатора, который вы используете для задания управляющего элемента,
принимающего сообщение. Для посылки сообщения управляющему элементу нужно
вызвать метод TDialg SendDlgItemMsg. Например, данный метод заполнит блок
списка диалога элементами текста путем посылки сообщения lb_AddString:
procedure TestDialog.FillListBox(var Msg: TMessage);
var
TextItem: PChar; begin
TextItem := 'Item 1';
SendDlgItemMsg(id_LB1, lb_AddString, 0, Longint(TextItem)); end;
где id_LB1 есть константа, равная ID блока списка.
Если вам потребуется описатель одного из управляющих элементов диалога,
его можно получить методом GetItemHandle:
GetItemHandle(id_LB1);
Реакция на сообщения управляющих элементов
Когда пользователь выбирает управляющий элемент, например, "нажимает"
командную кнопку или делает выбор в блоке списка, диалоговым блоком управляющего
элемента порождающего окна принимается специальное сообщение, основанное
на дочернем окне и называемое управляющим сообщением (сообщение управляющего
элемента). Определим метод реакции на сообщение, основанное на дочернем
идентификаторе, в порождающем типе диалога для каждого дочернего управляющего
элемента:
TTestDialog = object(TDialog)
procedure HandleBN1Msg(var Msg: TMessage); virtual
id_First + id_BN1;
procedure HandleListBox(var Msg: TMessage); virtual
id_First + id_LB1;
end;
В данном примере id_BN1 - это идентификатор кнопки управляющего элемента,
а id_LB1 - это идентификатор блока списка. Щелчок "мышью" на
командной кнопке даст сообщение, посылаемое в диалоговый блок. Объект
диалогового блока реагирует через динамический метод с индексом, основанным
на идентификаторе кнопки IDBN1.
Примечание: Уведомляющие сообщения подробно поясняются в Главе 16 "Сообщения
Windows"
Каждое управляющее информационное сообщение поступает с кодом уведомления
- целочисленной константой, которая идентифицирует произведенное действие.
Например, результатом выбора элемента из блока списка будет сообщение
с кодом lbn_SelChange, где lbn_ - уведомление блока списка (List Box Notification).
Нажатие кнопки "мыши" дает сообщение bn_Clicked. Ввод в управляющем
элементе редактированием приводит к сообщению с кодом en_Changed. Имеются
коды уведомления для блоков списка, управляющих элементов редактированием,
комбинированных блоков и командных кнопок. Код уведомления передается
в Msg.lParamHi сообщения. Для восприятия управляющих информационных сообщений
напишем метод реакции для типа диалога, обрабатывающий важные коды уведомления:
procedure TestDialog.HandleLB1Msg(var Msg: TMesage);
begin
case Msg.lParamHi of
lbn_SelChange: изменение порядка выбора ;
lbn_DblClk: выбор с помощью двойного щелчка ;
end;
end;
Управляющие элементы, имеющие соответствующие объекты, могут отвечать
на уведомления сами. См. Главу 16.
Пример связи
В файле с текстом программы DIALTEST.PAS, основное окно име-
B.Pascal 7 & Objects/OW - 184 -
ет режимный диалог, определенный типом диалога TTestDialog. Эта
программа обеспечивает двухстороннюю связь между объектом диалога
и его управляющими элементами. Два метода - IDBN1 и IDLB1 - являются методами
реакции, основанными на дочерних идентификаторах, и вызываются при выборе
пользователем управляющих элементов (дочерних окон). Например, при выборе
пользователем кнопки диалога BN1 ('Fill List Box') вызывается метод IDBN1.
Аналогично, когда пользователь делает выбор в блоке списка, вызывается
IDLB1. С другой стороны, для заполнения блока списка элементами текста
код метода IDBN1 посылает в диалог управляющее сообщение, lb_AddString,
используя метод диалога SendDlgItemMsg,
Эта программа также показывает как путем создания нового типа диалога
и связывания его с ресурсом диалога в вызове конструктора Init метода
TestWindow.RunDialog создаются новые диалоги. Полный текст программы вы
можете найти на дистрибутивных дисках.
Ассоциирование объектов управляющих элементов
До этого момента мы имели дело с реакцией блоков диалога на управляющие
информационные сообщения, которая использовала методы реакции, основанные
на дочерних идентификаторах. Однако, иногда более предпочтительно, чтобы
управляющий элемент сам реагировал на сообщение. Например, вам может потребоваться
управляющий элемент редактирования, который позволяет вводить только цифры,
или командная кнопка, которая меняет стиль при своем "нажатии".
Это можно реализовать с помощью объектов управляющих элементов в окнах
(см. Главу 12). Однако, чтобы это имело место для управляющих элементов
диалога, созданного с файлом ресурса, вам нужно использовать для конструирования
объекта другой конструктор.
При организации связей вы создаете объект управляющего элемента для представления
управляющего объекта диалога. Этот объект управления дает вам гибкость
в реакции на управляющие сообщения. Он дает вам возможность использования
набор методов объектов управляющих элементов, описанных в Главе 12.
Для связи объекта с управляющим элементом определите сначала объект управляющего
элемента. Он должен быть создан в конструкторе диалога. Однако, вместо
того, чтобы использовать конструктор Init, как это показано в Главе 12,
следует использовать InitResource, который берет в качестве параметров
порождающее окно и идентификатор управляющего элемента (из ресурса диалога).
Это приводит к вызову методов реакции на сообщения объектов управляющих
элементов вместо обработки элементов по умолчанию. Для этого нужно определить
новый тип объекта, производный от предусмотренного типа управляющего элемента.
Обратите внимание, что в отличие от задания оконного объек-
B.Pascal 7 & Objects/OW - 185 -
та, которое предполагает два шага (Init и MakeWindow), поскольку
управляющий элемент уже существует, связь объекта с управляющим
элементов выполняется за один шаг: он загружается из диалогового
ресурса. Вам нужно только сообщить InitResource, какой управляющий элемент
из ресурса вы хотите связать с объектом, используя идентификатор управляющего
элемента.
Использование диалоговых окон
Основная разница между диалоговыми блоками и окнами состоит в том, что
диалог имеет соответствующий ресурс и задает тип и расположение своих
управляющих элементов. Но окно также может иметь управляющие элементы.
Одним из подходов размещения управляющих элементов в окне является использование
объектов управляющих элементов (как показано в Главе 12). Другой подход
- это слияние возможностей диалоговых блоков и окон, как это делается
в объектном типе TDlgWindow, что позволяет получить гибридный объект,
называемый диалоговым окном. Второй подход предусматривает более удобный
способ построения и управления многими управляющими элементами в окне.
Кроме того, он предлагает для диалоговых блоков более гибкие средства
окон.
TDglWindow является потомком TDialog и наследует его методы, такие как
Execute, Create, Ok и EndDlg. Как и диалоговые блоки, диалоговые окна
имеют соответствующий ресурс диалогового блока. С другой стороны, как
и окна, диалоговые окна имеют соответствующий класс окон, определяющий
среди всего прочего пиктограмму, курсор и меню. Из-за связи с оконным
классом в потомке TDlgWindow следует переопределять методы GetClassName
и GetWindowClass. Этот класс должен быть тем же, что и перечисленный в
диалоговом ресурсе.
В большинстве случаев вы будете выполнять диалоговые окна как и другие
окна или безрежимные диалоговые окна с помощью методов Create и Show,
а не метода Execute.
В тех случаях, когда основное окно должно содержать много сложных управляющих
элементов, хорошим использованием диалоговых окон является основное окно
приложения. Например, программа-калькулятор может иметь в качестве основного
окна диалоговое окно, где кнопки калькулятора заданы как управляющие элементы
диалогового ресурса. Это позволило бы вывести в основном окне также меню,
пиктограмму и курсор.
B.Pascal 7 & Objects/OW - 186 -
Использование предопределенных диалоговых окон
Для выполнения двух типов общих функций ObjectWindows предусматривает
стандартные диалоговые блоки. Одно их них, окно диалогового блока, выводит
пользователю однострочную подсказку. Другое, файловое диалоговое окно,
позволяет пользователю задать имя файла и каталог для открытия или сохранения
файла.
Использование диалоговых блоков ввода
Диалоговые блоки ввода - это простые объекты диалоговых блоков, определяемых
типом TInputDialog, которые выводят пользователю подсказку со строкой
текста.
Вы можете запускать диалоги ввода как режимные или безрежимные диалоговые
блоки, но обычно вы будете выполнять их как режимные. С объектом диалога
ввода связан ресурс диалога ввода. Он находится в файле ObjectWindows
OSTDDLGS.RES.
Примечание: Использование модуля StdDlgs автоматически включает ресурсы
в OSTDDLGS.RES.
Каждый раз при конструировании диалога ввода с использованием метода Init,
вы задаете для диалога заголовок, подсказку и текст по умолчанию. Покажем
вызов конструктора Init объекта диалога ввода:
var SomeText: array[0..79] of Char;
begin
AnInputDlg.Init(@Self, 'Caption', 'Prompt', SomeText,
SizeOf(SomeText))
.
.
.
end;
B.Pascal 7 & Objects/OW - 187 -
В данном примере EditText - это текстовый буфер, который заполняется вводом
пользователя, когда он "нажимает" кнопку OK. Когда пользователь
"нажимает" кнопку OK или клавишу Enter, строка введенного в
диалоге ввода текста автоматически передается в массив символов, который
хранит текст по умолчанию. В данном примере конструируется и отображается
блок диалога и считывается текст:
procedure TSampleWindow.Test(var Msg: TMessage);
var
EditText: array[0..255] of Char; begin
EditText:='Frank Borland';
if ExecDialog(New(PInputDialog, Init(@Self, 'Data Entry',
'Введите имя:', EditText, SizeOf(EditText)))) = id_OK then
MessageBox(HWindow, EditText, 'Имя =', mb_OK); else MessageBox(HWindow,
EditText,
'Имя пока имеет значение:',mb_OK); end;
B.Pascal 7 & Objects/OW - 188 -
Файловые диалоговые блоки
Файловые диалоговые блоки являются другим типом диалогов, поставляемых
с ObjectWindows в типе TFileDialog. Файловый диалоговый блок следует использовать
каждый раз, когда вы желаете побудить пользователя ввести имя файла, например
в функциях File Open и File Save во всех приложениях. См. Рис. 11.1.
File Open
-------------------- ------------Имя файла: | *.pas | | OK | --------------------
------------
Каталог: a:\ | Cancel |
Файлы: Каталоги:
|collect3.pas |^| |[-a-] |^||collect4.pas --- |[-c-] ---|diatest.pas |
| |[-f-] | ||edittest.pas | | |[-g-] | ||ewndtest.pas | | |[-h-] | ||helpwind.pas
| | |[-i-] | ||lboxtest.pas | | |[-j-] | ||mditest.pas --- |[-k-] ---|paltest.pas
|v| |[-w-] |v|
Рис. 11.1 Файловый диалоговый блок.
В большинстве случаев файловые диалоговые блоки выполняются как режимные.
С объектом файлового диалога связан ресурс файлового диалогового блока,
имеющийся в ObjectWindows в файле OSTDDLGS.RES. Использование модуля OStdDlgs
автоматически включает файл ресурса.
B.Pascal 7 & Objects/OW - 189 -
Инициализация файлового диалогового блока
TFileDialog определяет конструктор Init, который позволяет задать маску
файла и буфер для считывания имени файла. Маска файла (такая как '*.TXT')
ограничивает файлы, перечисляемые в комбинированном блока (аналогично
тому, как это делается в команде DOS DIR *.TXT). Имя файла и маска передаются
в записи типа TFileDlgRec. Приведем пример вызова файлового диалогового
блока Init:
var
FileRec: TFileDlgRec;
IsOpen: Boolean; begin
StrCopy(FileRec.Name, 'TEST1.TXT');
StrCopy(FileRec.Mask, 'C:\*.TXT');
IsOpen := True;
AFileDlg.Init(@Self, FileRec, IsOpen);
.
.
.
end;
Последний параметр указывает, будет ли диалог диалогом открытия или сохранения
(как описывается в следующем разделе).
Выполнение файловых диалоговых блоков
Существует два вида файловых диалоговых блоков: диалоговый блок открытия
файла и диалоговый блок сохранения файла. Они различаются текстом кнопки
в правом верхнем углу диалогового окна. В зависимости от того, запрашивает
пользователь открытие или сохранение файла, на командной кнопке будет
написано Open или Save. Когда вы вызовите ExecDialog, то получите тип
диалогового блока, заданных в конструкторе IsOpen параметром типа Boolean.
Если файловый диалоговый блок строится с IsOpen, установленным в True,
то диалоговый блок будет работать как диалоговый блок открытия файла.
Если он строится с IsOpen, установленным в False, то файловый диалоговый
блок будет блоком сохранения файла.
B.Pascal 7 & Objects/OW - 190 -
Дополнительным средством файлового диалогового блока
ObjectWindows является то, что он выводит пользователю подсказку, хочет
ли пользователь сохранить файл с именем уже существующего файла (см. Рис.
11.2). В другой раз вы можете запросить пользователя, хочет ли он открыть
новый файл или очистить текущий текст без сохранения. Поскольку это должно
происходить перед выводом файлового диалогового блока, то не является
частью поведения этого блока. В примере программы Steps в первой части
данного руководства перед загрузкой рисунка из файла проверяется метод
CanClose его основного окна.
File exists Overwrite it?
C:\TEMP\NICELINE.PTS------------ ------------| Yes | | No |------------
------------
Рис. 11.2 Предупреждение пользователя о перезаписи существующих файлов.
File exists! Overwrite it? - файл существует, затереть его?
Приведем пример типичного использования диалогового окна:
procedure TMyWindow.OpenSelectedFile;
var FileRec: TFileDlgRec;
begin
StrCopy(FileRec.Name, 'HEDGEHOG.PAS');
StrCopy(FileRec.Mask, '*.PAS'); if ExecDialog(New(PFileDialog,
Init(@Self, FileRec, True))) = id_Ok then begin
Assign(AFile, StrPas(FileRec.Name));
.
.
.
end;
end;
B.Pascal 7 & Objects/OW - 191 -
Глава 12. Объекты управляющих элементов
Windows предусматривает ряд стандартных интерфейсных элементов, называемых
управляющими элементами. Управляющие элементы - это специальные окна с
некоторым предопределенным поведением. ObjectWindows обеспечивает интерфейсные
объекты для стандартных управляющих элементов Windows, так что вы можете
использовать эти интерфейсные элементы в своих приложениях. Интерфейсные
объекты для управляющих элементов называются объектами управляющих элементов
или просто управляющими объектами.
Примечание: Об интерфейсных объектах рассказывается в Главе 9.
Данная глава охватывает следующие темы:
* Задачи, общие для всех управляющих объектов:
- построение и уничтожение объектов управляющих элементов;
- взаимодействие с другими управляющими объектами.
* Установка и чтение значений управляющих элементов.
* Использование специализированных управляющих элементов.
Кроме того, в данной главе подробно описывается использование каждого
интерфейсного объекта для стандартных управляющих элементов Windows.
Где можно использовать объекты управляющих элементов?
Управляющие элементы - это специализированные окна, которые позволяют
пользователю предопределенным образом задавать или выбирать данные. Чаще
всего управляющие элементы содержатся в диалоговом блоке. Диалоговый блок
управляет их определением с помощью ресурса диалогового блока, так что
вам не потребуется часто использовать в них объекты. Режимные диалоговые
блоки не располагают способами взаимодействия с управляющим объектом,
поэтому в диалоговых блоках объекты управляющих элементов используются
обычно для установки и считывания значений управляющих элементов с помощью
передачи. Передача для объектов управляющих элементов в диалоговых блоках
и в окнах выполняется одинаково (как описывается ниже в этой главе).
Примечание: Диалоговые блоки и их управляющие элементы описываются в Главе
11 "Объекты диалоговых блоков".
Возможно вы захотите использовать управляющие элементы в окнах, поэтому
в данной главе описывается использование управляющих элементов вне диалоговых
блоков. Следующая таблица описывает уп-
B.Pascal 7 & Objects/OW - 192 -
равляющие элементы Windows, поддерживаемые типами объектов
ObjectWindows:
Управляющие элементы Windows,
поддерживаемые в ObjectWindows Таблица 12.1
Управляющий элемент Тип объекта Использование
блок списка TListBox Прокручиваемый список элементов, из которых можно
сделать выбор.
полосапрокрутки TScrollBar Полоса прокрутки, аналогичная тем, которые
выводятся в прокручиваемых окнах и блоках списка.
"нажимаемая"кнопка TButton Кнопка для "нажатия" со
связанным с ней текстом.
кнопка снезависимойфиксацией TCheckBox Состоящая из блока кнопка, которая
может выбираться или нет, со связанным текстом.
кнопка сзависимойфиксацией TRadioButton Кнопка, которая может выбираться
или нет. Обычно используется во взаимоисключающих группах.
блок группы TGroupBox Статический прямоугольник с текстом в левом верхнем
углу.
управляющийэлементредактирования TEdit Поле для ввода текста пользователем.
статическийуправляющийэлемент TStatic Фрагмент отображаемого текста который
не может быть изменен пользователем.
Комбинированный блок TComboBox Комбинация блока списка и управляющего
элемента редактирования.
B.Pascal 7 & Objects/OW - 193 -
------------------------------------ Командная строка: | |
------------------------------------
^
- редактируемый упрвляющий элемент
------------ ------------
| OK | | Cancel | <- командные кнопки
------------ ------------
< >
^
полоса прокрутки --
------------------
|collect3.pas |^| <- блок списка
|collect4.pas ---
|diatest.pas | |
|edittest.pas | | ------------------
|ewndtest.pas | | | *.txt |
|helpwind.pas | | --------------------
|lboxtest.pas | | |netlect3.txt |^|
|mditest.pas --- |netlect4.txt ---
|paltest.pas |v| |diatext.txt | |
------------------ |readtxt.txt | |
|vwndtext.txt | |
комбинированный блок -> |whelpwnd.txt | |
|wboxtext.txt | |
|ydrtest.txt ---
|xaltesx.txt |v|
------------------
Рис. 12.1 Стандартные управляющие элементы Windows.
B.Pascal 7 & Objects/OW - 194 -
Что такое объекты управляющих элементов?
Для Windows управляющие элементы - это просто специализированные виды
окон. В ObjectWindows тип TControl является потомком типа TWindow, так
что большинство объектов управляющих элементов можно использовать как
все другие оконные объекты. Объекты управляющих элементов по способу их
создания и уничтожения и способу их поведения (как дочерние окна) аналогичны
оконным объектам. Однако они отличаются от других окон способом реакции
на сообщения. Например, методы Paint объектов управляющих элементов запрещены.
Windows берет на себя функции по отображению своих стандартных управляющих
элементов.
Может оказаться, что перечисленные в приведенной выше таблице управляющие
элементы отвечают всем потребностям вашего приложения. Однако могут возникать
случаи, когда требуется определить наследующие типы управляющих элементов.
Например, вы можете создать специализированный блок списка TFontListBox,
производный от TListBox, содержащий имена всех доступных вашему приложению
шрифтов и автоматически выводящих их при создании нового экземпляра объекта.
Тип TControl, как и TWindowsObject, является абстрактным объектным типом.
Вы можете создать экземпляры его потомков -
TListBox, TButton и другие - но не можете создать экземпляр TControl.
Заметим, что вам, возможно, никогда не потребуется создавать новый объектный
тип, наследующий непосредственно из TControl. TControl инкапсулирует свойства
и стандартные управляющие элементы, о которых уже знает Windows. Создание
специализированных управляющих элементов описывается в данной главе ниже.
Построение и уничтожение объектов управляющих элементов
Обычно в объекта порождающего окна для каждого из дочерних окон определяется
поле данных. Независимо от того, какой вид объектов вы используете, для
каждого из них вы можете выполнить несколько задач:
* Построение объекта управляющего элемента.
* Вывод управляющего элемента.
* Уничтожение управляющего элемента.
B.Pascal 7 & Objects/OW - 195 -
Построение объекта управляющего элемента
Построение управляющих элементов отличается от построения любых других
дочерних окон. Обычно конструктор порождающего окна вызывает конструкторы
всех его дочерних окон. Однако в случае управляющих элементов не просто
создается связь "родитель - потомок", но устанавливается также
связь "окно - управляющий элемент". Это очень важно, поскольку
кроме обычных связей между предком и потомком управляющие элементы взаимодействуют
с порождающими окнами особыми способами (через уведомления).
Примечание: Уведомления описываются в Главе 16 "Сообщения Windows".
Чтобы построить и инициализировать объект управляющего элемента, нужно
сделать следующее:
* добавить в объект порождающего окна поле (не обязательно);
* вызвать конструктор объекта управляющего элемента;
* изменить атрибуты управляющего элемента;
* инициализировать управляющий элемент в SetupWindows.
Вызов конструкторов объектов управляющих элементов
В то время как обычный конструктор объекта дочернего окна имеет только
два параметра (порождающее окно и строку заголовка), конструктор управляющего
объекта имеет их не менее шести. Объект блока списка имеет наиболее простой
из всех управляющих элементов конструктор, который требует задания только
шести параметров:
- объекта порождающего окна;
- идентификатора управляющего элемента;
- координату x верхнего левого угла;
- координату y верхнего левого угла;
- ширину;
- высоту.
TListBox.Init описывается следующим образом:
constructor TListBox.Init(AParent: PWindowsObject;
AnID: Integer; X, Y, W, H: Integer);
Все объекты управляющих элементов ObjectWindows (кроме TMDIClient) требуют
не менее 6 параметров. Большинство из них воспринимают также параметр,
задающий текст управляющего элемента.
Присваивание полям объекта
Часто при построении управляющего элемента в окне желательно
B.Pascal 7 & Objects/OW - 196 -
сохранять указатель на управляющий элемент в поле оконного объекта. Например,
чтобы добавить в окно, определенное типом TSampleWindow блок списка, вы
можете задать в поле TSampleWindow поле TheList и присвоить ему блок списка:
constructor SampleWindow.Init(AParent: PWindowsObject; ATitle: PChar);
begin
inherited Init(AParent, ATitle);
TheList := New(PListBox,
Init(@Self, id_LB1, 20, 20, 100, 80)); end;
Порождающие окна автоматически поддерживают список своих дочерних окон,
включая управляющие элементы. Однако удобнее манипулировать управляющими
объектами, когда имеются соответствующие поля объекта. Управляющие элементы,
с которыми часто работать не требуется (такие как статический текст или
групповые блоки) могут не иметь соответствующих полей.
При наличии поля объекта построение объекта управляющего элемента не представляет
труда. Например, чтобы добавить в TSampleWindow групповой блок, нужно
сделать следующее:
constructor SampleWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
TempGroupBox := New(PListBox,
Init(@Self, id_LB1, 'Group name',
140, 20, 100, 80)); end;
B.Pascal 7 & Objects/OW - 197 -
Изменение атрибутов объекта управляющего элемента
Все управляющие объекты, кроме TMDIClient, получает от вызова TControl.Init
используемые по умолчанию стили ws_Child и ws_Visible. Если вы хотите
изменить стиль управляющего элемента, то можно изменить поле Attr.Style
(как это описывается для окон в Главе 10). Каждый тип управляющего элемента
имеет также другие стили, определяющие его конкретные характеристики.
Инициализация управляющего элемента
Экранный элемент управляющего объекта автоматически создается методом
SetupWindow, наследуемым объектом порождающего окна. Убедитесь, что при
создании новых производных типов окон вы вызываете наследуемый метод SetupWindow
перед любой другой инициализацией окна.
При необходимости методом SetupWindow порождающего окна также устанавливаются
и заполняются управляющие элементы. Приведем пример типичного метода SetupWindow:
procedure TSampleWindows.SetupWindow;
begin
inherited SetupWindow; создает дочерние управляющие
элементы
добавляет элементы в список
TheList^.AddString('Элемент 1');
TheList^.AddString('Элемент 2'); end;
Заметим, что инициализация управляющего элемента, такая как добавление
строк в блок списка, должна выполняться в SetupWindow, а не в конструкторе.
Вызов такого метода как TListBox.AddString приводит к передаче сообщений
экранному управляющему элементу. Так как экранный элемент до вызова наследуемого
метода SetupWindow не создается, попытки инициализации управляющих элементов
до этого момента завершится неудачно.
B.Pascal 7 & Objects/OW - 198 -
Сохранение управляющих элементов
Для вывода на экран управляющих элементов нет необходимости вызывать метод
Show. Как дочерние окна, они автоматически выводятся на экран и повторно
отображаются вместе с порождающим окном. Однако, вы можете использовать
Show для сокрытия или вывода управляющих элементов по запросу.
Уничтожение управляющих элементов
Порождающее окно отвечает за уничтожение управляющих элементов. Экранный
управляющий элемент автоматически уничтожается вместе с элементом порожденного
окна, когда пользователь закрывает окно или приложение. Деструктор порождающего
окна автоматически уничтожает все дочерние объекты.
Связь с управляющими элементами
Связь между оконным объектом и его управляющими объектами в некотором
смысле аналогичны взаимодействию между объектом диалогового блока и его
управляющими элементами. Как и диалоговому блоку, окну требуется механизм
для работы с его управляющими элементами и для ответа на управляющие события,
такие как выбор в блоке списка.
Работа с управляющими элементами окна
Диалоговые окна работают с их управляющими элементами путем передачи им
сообщений с помощью метода SendDlgItemMsg с константой управляющего сообщения
(такой как lb_AddString) в качестве параметра (см. Главу 11). Объекты
управляющих элементов сильно упрощают этот процесс путем использования
методов (таких как TListBox.AddString) для непосредственной работы с управляющими
элементами на экране.
Когда объекты управляющих элементов окна имеют соответствующие поля объекта,
то вызвать управляющие методы достаточно просто:
TheListBox^.AddString('Scotts Valley');
B.Pascal 7 & Objects/OW - 199 -
Реакция на управляющие элементы
Реакция на взаимодействие с пользователем с помощью управляющих элементов
несколько более сложна, чем просто вызов методов объектов управляющих
элементов. Чтобы узнать, как отвечать на сообщения управляющих элементов,
см. раздел "Команды, уведомления и идентификаторы управляющих элементов"
в Главе 16.
Действие, аналогичное диалоговому блоку
Диалоговый блок с управляющими элементами позволяет пользователю с помощью
клавиши Tab циклически перемещаться по всем элементам диалогового блока.
Он может также использовать клавиши стрелок для выбора в групповом блоке
кнопок с зависимой фиксацией. Чтобы эмулировать этот клавиатурный интерфейс
для окон с управляющими элементами, вызовите для оконного объекта в его
конструкторе метод EnableKBHandler объекта TWindowsObject.
Использование конкретных управляющих элементов
Каждый вид управляющих элементов работает в чем-то отлично от других.
В данном разделе вы можете найти конкретную информацию о том, как использовать
объекты для каждого из стандартных управляющих элементов Windows.
Использование блока списка
Использование блока списка - это простейший способ запросить пользователя
программы Windows выбрать что-либо из списка. Блоки списка инкапсулируются
объектным типом TListBox. TListBox определяет методы для создания блоков
списка, модификации списка элементов, запроса состояния списка элементов
и поиска выбранного пользователем элемента.
B.Pascal 7 & Objects/OW - 200 -
Построение объектов блока списка
Конструктор Init в TListBox воспринимает только шесть параметров, которые
необходимы всем объектам управляющих элементов. Этими параметрами являются
порождающее окно, идентификатор и размеры управляющего элемента X, Y,
W и H:
LB1 := New(PListBox, Init(@Self, id_LB1, 20, 20, 340, 100));
TListBox получает используемый по умолчанию стиль управляющего элемента
ws_Child or ws_Visible, затем прибавляется lbs_Standard. lbs_Standard
- это комбинация lbs_Notify (для получения уведомляющих сообщений), ws_VScroll
(для получения вертикально полосы прокрутки), lbs_Sort (для сортировки
списка элементов в алфавитном порядке) и ws_Border (для вывода рамки).
Если вы хотите получить другой стиль блока списка, то можете модифицировать
поле Attr.Style в TListBox. Например, для блока списка, не сортирующего
свои элементы, можно использовать следующее:
LB1 := New(PListBox, Init(@Self, id_LB1, 20, 20, 340, 100));
LB1^.Attr.Style := LB1^.Attr.Style and not lbs_Sort;
Модификация блоков списка
После создания блока списка вам нужно заполнить его элементами списка,
который должны представлять собой строки. Позднее вы можете добавить,
вставить или удалить элементы, либо полностью очистить список. Указанные
действия вы можете выполнить с помощью методов, приведенный в следующей
таблице:
Методы модификации блоков списка Таблица 12.2
Выполняемое действие Метод
Добавление элементаВставка нового элементаДобавление элементаУдаление
элементаУдаление каждого элементаВыбор элемента AddStringInsertStringInsertStringDeleteStringClearListSetSellIndex
или SetSelString
Запрос в блоках списка
Существует пять методов, которые вы можете вызвать для получения информации
о списке, содержащейся в объекте блока списка. Эти методы перечислены
в следующей таблице:
Методы запроса блока списка Таблица 12.3
Получаемая информация Вызываемый метод
Число элементов в спискеЭлемент с конкретным индексомДлина конкретного
элементаВыбранный элементИндекс выбранного элемента GetCountGetStringGetStringLenGetSelStringSEgSelIndex
Реакция на блок списка
Методы модификации и запроса блока списка позволяют вам установить значения
или определять в каждый конкретный момент состояние блока списка. Однако,
чтобы знать, что делает пользователь в данный момент с блоком списка,
вам нужно реагировать на уведомляющие сообщения управляющего элемента.
Пользователь может выполнять с блоком списка только следующие действия:
прокрутку списка, щелчок кнопкой "мыши" на элементе списка,
двойной щелчок кнопкой "мыши" на элементе. Когда выполняется
одно из этих действий, Windows посылает порождающему окну блока списка
уведомляющее сообщение блока списка. Обычно метод реакции на уведомление
для обработки сообщений для каждого управляющего элемента порождающего
объекта определяется в порождающем оконном объекте.
Каждое уведомляющее сообщение блока списка содержит в поле lParamHi параметра
Msg код уведомления (константу lbn_), который специфицирует характер действия.
Наиболее общие коды lbn перечислены в следующей таблице:
Информационные сообщения блока списка Таблица 12.2
wParam Действие
lbn_SelChange Отдельным нажатием кнопки "мыши" был выбран элемент.
lbn DblClk Элемент был выбран двойным щелчком кнопки мыши
lbn_SetFocus Пользователь переместил фокус на блок списка простым или
двойным нажатием кнопки "мыши", либо клавишей Tab. Предшествует
lbn_SelChange.
B.Pascal 7 & Objects/OW - 202 -
Приведем пример метода порождающего окна по обработке сообщений блока
списка:
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, 'Вы выбрали:', mb_OK); end;
end;
else DefWndProc(Msg);
end;
Пользователь делает выбор, если Msg.lParamHi совпадает с константой lbn_SelChange.
Если это так, то берется длина выбранной строки, проверяется, что она
помещается в строку из 10 символов, и выбранная строка показывается в
блоке сообщения.
Пример программы: LBoxTest
Программа LBoxTest - это полная программа, которая создает окно с блоком
списка. После запуска приложения появляется основное окно с блоком списка.
Когда пользователь выбирает элемент блока списка, появляется диалог с
выбранным элементом. Обратите внимание на взаимоотношения между объектом
окна и объектом блока списка. Блок списка - это не просто дочернее окно
основного окна, основное окно владеет им как полем объекта. LB1 - это
одно из полей объекта основного окна, и оно содержит объект блока списка.
Полный текст программы содержится в файле LBOXTEST.PAS на ваших дистрибутивный
дискетах.
B.Pascal 7 & Objects/OW - 203 -
Использование статических управляющих элементов
Статические управляющие элементы - это обычно неизменяемые модули текста
или простые изображения, которые могут появляться на экране в окне или
блоке диалога. Пользователь не взаимодействует со статическими управляющими
элементами, хотя программа и может изменять их текст. Рис. 12.2 показывает
множество стилей статического управления и соответствующих констант стиля
Windows.
Static Control Tester
Default Static Sample Textss_Simple Sample Textss_Left Sample Textss_Center
Sample Textss_Right Sample Text
ss_BlackFrame | |
--------------------------------ss_GrayFrame | |
ss_NoPrefix Sample & Text
Рис. 12.2 Стили статических управляющих элементов.
B.Pascal 7 & Objects/OW - 204 -
Построение статических управляющих элементов
Пользователь никогда не взаимодействует непосредственно со статическими
управляющими элементами, поэтому приложение будет очень редко, если вообще
будет, принимать уведомляющие сообщения управляющих элементов относительно
статического управляющего элемента. Следовательно, большинcтво статических
управляющих элементов можно сконструировать с идентификатором ресурса
-1 или некоторым другим неиспользуемым числом.
Конструктор Init в TStatic конструирует новый объект статического управления
и описывается следующим образом:
constructor TStatic.Init(AParent: PWindowsObject;
AnID: Integer; ATitle: PChar;
X, Y, W, H: Integer; ATextLen: Word);
Кроме обычных параметров Init управляющего объекта,
TStatic.Init имеет два дополнительных параметра - текстовую строку ATitle
и максимальную длину текста ATextLen. Текст должен заканчиваться нулевым
символом, поэтому в действительности число отображаемых символов на единицу
меньше заданной в конструкторе длины текста. Типичный вызов для построения
статического управляющего элемента может выглядеть так:
Stat1 := New(Static, Init(@Self, id_ST1, '&Text', 20, 50, 200, 24,
6));
После его создания обращаться к статическому управляющему объекту или
манипулировать им требуется редко, поэтому поле, содержащее статический
управляющий объект, в общем случае присваивать не нужно.
Используемым по умолчанию стилем статического управляющего элемента является
назначенный по умолчанию стиль управляющего элемента, то есть ws_Child
or ws_Visible (выравнивание влево). Чтобы изменить стиль, модифицируйте
поле Attr.Style. Например, чтобы центрировать текст управляющего элемента,
сделайте следующее:
Stat1^.Attr.Style := Stat1^.Attr.Style and (not ss_Left) or ss_Center;
В статическом управляющем элементе есть возможность подчеркивания одного
или нескольких символов в строке текста. Реализация и действие этого эффекта
аналогичны подчеркиванию первого символа в выборе меню: Insert и &
должны непосредственно предшествовать символу в строке, который будет
подчеркиваться. Например, для подчеркивания T в слове 'Text' нужно в вызове
Init строку '&Text'. Если в строке вам нужно использовать &, применяйте
статический стиль Windows ss_NoPrefix (см. Рис. 12.2). Для уточнения текущего
текста, который хранится в статическом управляющем
B.Pascal 7 & Objects/OW - 205 -
элементе, используется метод GetText.
Модификация статического управляющего элемента
Для изменения текста статического управляющего элемента TStatic имеет
два метода. SetText устанавливает статический текст, передаваемый аргументом
PChar. Clear удаляет статический текст. Однако, вы не можете сменить текст
статического управляющего элемента, созданный со стилем ss_Simple.
Опрос статических управляющих элементов
Чтобы считать текст, содержащийся в статическом управляющем элементе,
используйте метод GetText.
Пример программы StatTest
Программа StatTest создает статическое тестовое приложение, показанное
на Рис.12.2. Обратите внимание на то, что метки ('Default Static' и 'ss_Simple')
представляют собой статистические управляющие элементы, также как и 'Sample
Text', черные и серые прямоугольники. Полный текст программы содержится
в файле STATTEST.PAS на ваших дистрибутивных дискетах.
B.Pascal 7 & Objects/OW - 206 -
Использование командных кнопок
Управляющие элементы типа командных кнопок (которые иногда называют "нажимаемыми"
кнопками) выполняют некоторое действие при "нажатии" такой кнопки.
Есть два стиля командных кнопок, и оба они имеют тип TButton. Эти два
стиля - bs_PushButton и DefPushButton. Используемые по умолчанию командные
кнопки аналогичны командным другим кнопкам, но имеют жирную рамку и обычно
используются для указания реакции пользователя по умолчанию. На Рис. 12.3
показан пример программы Windows, в которой используются обычные кнопки
нажатия и командные кнопки по умолчанию.
Hex Calculator
----- ----- ----- ----- -----||D|| | E | | F | | + | | & |----- -----
----- ----- ---------- ----- ----- ----- -----| A | | B | | C | | - |
| | |----- ----- ----- ----- ---------- ----- ----- ----- -----| 7 | |
8 | | 9 | | * | | ^ |----- ----- ----- ----- ---------- ----- ----- -----
-----| 4 | | 5 | | 6 | | / | | < |----- ----- ----- ----- ----------
----- ----- ----- -----| 1 | | 2 | | 3 | | % | | > |----- ----- -----
----- ---------- ----------- ------------| 0 | | Back | | Equals |-----
----------- ------------
Рис. 12.3 Программа Windows, использующая командные кнопки.
B.Pascal 7 & Objects/OW - 207 -
Построение командных кнопок
Кроме обычных 6 параметров, конструктор Init объекта TButton воспринимает
текстовую строку типа PChar, AText и флаг типа Boolean IsDefaultButton,
указывающий, должна ли кнопка быть используемой по умолчанию или обычной
командной кнопкой. Конструктор Init объекта TButton описывается следующим
образом:
constructor TButton.Init(AParent: PWindowsObject;
AnID: Integer; AText: PChar;
X, Y, W, H: Integer; IsDefault: Boolean);
Типичный конструктор для обычной кнопки выглядит так:
Push1 := New(PButton, Init(@Self, id_Push1, 'Test Button',
38, 48, 316, 24, False));
Реакция на командные кнопки
Когда пользователь щелкает на командной кнопке "мышью", порождающее
окно кнопки принимает уведомляющее сообщение. Если объект порождающего
окна перехватывает сообщение, он может отреагировать на эти события выводом
блока диалога, записью файла или другим контролируемым программой действием.
Для организации реакции на сообщения кнопок нужно определить основанный
на дочернем идентификаторе метод для обработки каждой кнопки. Например,
следующий метод IDBut1 обрабатывает реакцию на "нажатие" пользователем
кнопки. Единственный код уведомления, определенный в Windows для командных
кнопок - это bn_Clicked, поэтому код уведомления не нужно проверять.
type
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;
Примечание: Пример использования командных кнопок показывает программа
BtnTest, которую вы можете найти на дистрибутивных дисках.
B.Pascal 7 & Objects/OW - 208 -
Использование блоков выбора
Тип TCheckBox наследует от TButton, а тип TRadioButton - от TCheckBox.
Кнопки с зависимой и независимой фиксацией мы будем иногда кратко называть
блоками выбора.
Кнопки с независимой фиксацией обычно используются для предоставления
пользователю выбора одного из двух возможных вариантов. Пользователь может
установить или не установить управляющий элемент, или оставить его так,
как он установлен. Если имеется группа кнопок с независимой фиксацией,
то может устанавливаться не одна кнопка, а несколько. Например, вы можете
использовать кнопку с независимой фиксацией для выбора трех шрифтов для
их загрузки в приложение.
Кнопки с зависимой фиксацией используются для выбора одного из нескольких
взаимоисключающих вариантов. Например, кнопка с зависимой фиксацией может
использоваться для выбора шрифта для конкретного символа. Когда пользователь
щелкает "мышью" на кнопке с зависимой фиксацией, это событие
приводит к генерации сообщения Windows. Как и в случае других управляющих
элементов, порождающее окно кнопки с независимой фиксацией обычно перехватывает
эти сообщения и выполняет по ним действия.
Однако, вы можете для выполнения ими некоторых действий при нажатии создать
типы, производные от TCheckBox и TRadioButton. Если ваш тип определяет
метод для nf_First + bn_Clicked, то он сначала должен вызывать метод реакции
BNClicked, а уже затем выполнять любые дополнительные действия.
Построение кнопок с зависимой и независимой фиксацией
Кроме обычных 6 параметров, конструктор Init для кнопок с зависимой и
независимой фиксацией воспринимает текстовую строку и указатель на объект
группового блока (см. "Групповые блоки"), который логически
и визуально выделяет кнопки. AGroup - это указатель на объект группового
блока. Если AGroup имеет значение nil, то блок выбора не является частью
какой-либо логической группы. Конструкторы описываются следующим образом:
constructor Init(AParent: PWindowsObject; AnID: Integer;
ATitle: PChar; X, Y, W, H: Integer;
AGroup: PGroupBox);
Для обоих видов блоков выбора синтаксис идентичен. Конструкторы различаются
только присваиваемым стилем, используемым по умолчанию. Типичное использование
конструкторов блока выбора имеет вид:
GroupBox1 := New(PGroupBox, Init(@Self, id_GB1,
'A Group Box', 38, 102, 176, 108));
B.Pascal 7 & Objects/OW - 209 -
ChBox1 := New(PCheckBox, Init(@Self, id_Check1,
'Check Box Text', 235, 12, 150, 26, GroupBox1));
Кнопки с независимой фиксацией по умолчанию инициализируются со стилем
bs_AutoCheckBox, а кнопки с независимой фиксацией имеют стиль bs_AutoRadioButton.
В соответствии с этими стилями в каждый момент времени может выбираться
только одна клавиша выбора в группе. Если одна выбрана, то другие автоматически
остаются невыбранными.
Если вы переопределяете стили объектов кнопок с зависимой или независимой
фиксацией как "неавтоматические", то тогда уже вы отвечаете
за их выбор или не выбор в ответ на произведенные пользователем нажатия.
B.Pascal 7 & Objects/OW - 210 -
Модификация блоков выбора
Модификация (выбор или отмена выбора) блоков выбора выглядит задачей пользователя
программы, а не вашей. Но в некоторых случаях программе требуется явно
управлять состоянием блоков выбора. Одним из таких случаев является вывод
на экран параметров, которые были выбраны и сохранены ранее. Для модификации
состояния кнопки с независимой фиксацией TCheckBox определяет 4 метода:
Методы модификации кнопок с независимой фиксацией Таблица 12.5
Выполняемое действие Вызов метода
Выбор кнопкиОтмена выбора кнопкиПереключение кнопки Check или SetCheck(bf_Chacked)Uncheck
или SetCheck(bf_Unchecked)Toggle
Когда вы используете данные методы с кнопками с зависимой фиксацией, ObjectWindows
обеспечивает выбор в группе только одной кнопки с зависимой фиксацией.
Опрос блоков выбора
Опрос блока выбора - это один из способов выяснения его состояния и организации
реакции на него. Кнопки с зависимой и независимой фиксацией имеют два
состояния: выбранные и невыбранные. Для получения состояния блока выбора
используется метод GetCheck типа TheckBox:
MyState:=Check1^.GetCheck;
Для определения состояния блока возвращаемое GetCheck значение можно сравнить
с заданными константами bf_Unchecked, bf_Checked и bf_Grayed.
Примечание: Использование кнопок обоих видов показано в примере программы
BtnTest на ваших дистрибутивных дисках.
Использование групповых блоков
В своей простейшей форме блок группы представляет собой статический прямоугольник
с меткой, который обычно объединяет другие управляющие элементы.
B.Pascal 7 & Objects/OW - 211 -
Построение групповых блоков
Конструктор Init группового блока кроме обычных 6 параметров воспринимает
текстовую строку метки группы.
constructor TGroupBoxInit(AParent: PWindowsObject;
AnID: Integer;
AText: PChar; X, Y, W, H: Integer);
Типичное использование конструктора группового блока может быть следующим:
GroupBox1 := New(PGroupBox, Init(@Self, id_GB1, 'A Group Box',
38, 102, 176, 108));
Группирование управляющих элементов
Поскольку блок группы визуально связывает группу других управляющих элементов,
он может логически связывать группу блоков выбора (кнопок с зависимой
и независимой фиксацией). Логическая группа автоматически отменяет выбор
характеристик блоков выбора "автоматического" стиля.
Для добавления в группу, нужно при конструировании блока выбора указать
указатель на блок группы. Например, чтобы добавить в окно группу кнопок
с независимой фиксацией, в оконный объект и его конструктор можно включить
следующее:
type
TSomeWindow = object(TWindow)
Group: PGroupBox;
FirstCheck, SecondCheck: PCheckBox: constructor Init(AParent: PWindowsObject,
ATitle: PChar); end;
constructor TSomeWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
Group := New(PCheckBox, Init(@Self, id_TheGroup,
'Various boxes', 10, 01, 100, 50));
FirstCheck := New(PCheckBox, Init(@Self, id_FirstCheck,
'One', 15, 20, 90, 10, Group));
SecondCheck := New(PCheckBox, Init(@Self, id_SecondCheck,
'Two', 15, 20, 90, 10, Group));
end;
B.Pascal 7 & Objects/OW - 212 -
Заметим, что передаваемый блоку выбора параметр группы - это указатель
на объект блока группы, а не идентификатор группового управляющего элемента
(как в API Windows). Использование указателя позволяет вам строить объекты
перед созданием методом SetupWindows порождающего окна экранных элементов.
B.Pascal 7 & Objects/OW - 213 -
Реакция на групповые блоки
Когда происходит событие, которое может изменить выбор блока группы (например,
"нажатие" пользователем кнопки или вызов программой метода Check),
порождающее окно блока группы принимает сообщение, основанное на дочернем
идентификаторе. Порождающий объект воспринимает сообщение, используя сумму
id_First и идентификатора группового блока. Это позволяет вам определить
методы для каждой группы вместо их задания для каждого блока выбора в
группе.
Для определения управляющего элемента в группе, на который было оказано
воздействие, вы можете прочитать текущее состояние каждого управляющего
элемента.
Пример программы: BtnTest
BtnTest - это полная программа, которая создает окно с командной кнопкой,
кнопками с зависимой и независимой фиксацией и блоком группы управляющих
элементов. После запуска приложения появляется основное окно с управляющими
элементами. Когда пользователь "нажимает" на управляющий элемент,
приложение реагирует на это различными способами. См. Рис. 12.4.
Примечание: Полный текст программы содержится в файле BTNTEST.PAS на ваших
дистрибутивных дискетах.
Button Tester
| X | Текст кнопки с независимой фиксацией
--Групповой блок--------------------------------| ( ) Кнопка с зависимой
фиксацией 1 || (*) Кнопка с зависимой фиксацией 2 |
-----------------------------------------------------------------
Рис. 12.4 Окно с различными видами кнопок.
B.Pascal 7 & Objects/OW - 214 -
Использование полос прокрутки
Полосы прокрутки являются важнейшим механизмом изменения обзора пользователем
окна приложения, блока списка или комбинированного блока. Однако, может
возникнуть ситуация, когда нужна отдельная полоса прокрутки для выполнения
некоторой специализированной задачи (например, управление температурой
в программе термостата или цветом в программе рисования). Когда нужна
отдельная специализированная полоса прокрутки, используются объекты TScrollBar.
Рис. 12.5 показывает типичное использование объекта TSсrollBar.
Thermostat
68 градусов
|< | | >|
Рис. 12.5 Объект полосы прокрутки.
Построение полос прокрутки
Кроме обычных 6 параметров управляющего объекта, конструктор Init полосы
прокрутки воспринимает флаг типа Boolean, указывающий, является ли полоса
прокрутки горизонтальной. Приведем описание конструктора полосы прокрутки:
constructor TScrollBarInit(AParent: PWindowsObject;
AnID: Integer; X, Y, W, H: Integer;
IsHScrollBar: Boolean);
Если вы зададите нулевую ширину вертикальной полосы прокрутки, Windows
присвоит ей стандартную ширину (аналогичную полосе прокрутки блока списка).
То же самое касается задания нулевой высоты горизонтальной полосы прокрутки.
Вызов:
ThermScroll := New(PScrollBar, Init(@Self, id_ThermScroll,
20, 170, 340, 0, True));
создает горизонтальную полосу прокрутки стандартной высоты, как
это показано на Рис. 12.5. Init конструирует полосы прокрутки со
стилями ws_Child, ws_Visible и sbs_Horz или sbs_Vert для горизонтальной
или вертикальной полосы прокрутки соответственно. Разно-
B.Pascal 7 & Objects/OW - 215 -
образные полосы прокрутки показаны на Рис. 12.6.
Scroll Bar Tester
---- ---------|/\|------------------------------- |^||/ | ---- | \| ---|\
| | | | /| | |------| |------------------------------- | || | | || | |
|| | ------- |v||\/| ---
Рис. 12.6 Окно с разнообразными полосами прокрутки.
Управление диапазоном полосы прокрутки
Один из атрибутов полосы прокрутки, инициализируемый при ее конструировании,
это диапазон. Диапазон полосы прокрутки - это набор всевозможных положений
указателя (маркера полосы прокрутки). Маркер полосы прокрутки - это подвижный
прямоугольник, который пользователь может перемещать по ней. Каждой позиции
соответствует целое число. Порождающее окно использует эту целую величину,
позицию, для установки и запроса по полосе прокрутки. После конструирования
объекта полосы прокрутки его диапазон устанавливается от 1 до 100.
Положению маркера в "самой верхней" позиции (вершина вертикальной
полосы прокрутки или крайнее левое положение горизонтальной полосы прокрутки)
соответствует позиция 1. "Самой нижней" позиции маркера соответствует
позиция 100. Для установки иного диапазона нужно использовать метод SetRange,
описанный в разделе "Модификация полосы прокрутки".
B.Pascal 7 & Objects/OW - 216 -
Управление параметрами полосы прокрутки
Два других атрибута объекта полосы прокрутки - это его приращение по строкам
и страницам. Приращение по строкам, установленное в 1, это расстояние
в единицах диапазона, на которое переместится указатель при нажатии пользователем
стрелок на полосе прокрутки. Приращение по страницам, установленное в
10, это расстояние в единицах диапазона, на которое переместится указатель
при нажатии пользователем в области прокрутки. Эти значения можно изменить
непосредственной модификацией полей объекта TScrollBar, LineSize и PageSize.
Опрос полосы прокрутки
TScrollBar определяет два метода опроса полосы прокрутки: GetRange и GetPosition.
Метод GetRange - это процедура, использующая два целочисленных переменных
аргумента. Процедура заносит в эти целые значения верхнюю и нижнюю позиции
из диапазона полосы прокрутки. Этот метод очень удобен, когда нужно, чтобы
ваша программа переместила указатель в его верхнюю или нижнюю позицию.
GetPosition - это функция, которая возвращает в виде целой величины позицию
указателя. Ваша программа очень часто будет запрашивать диапазон и позицию
и сравнивать их.
Модификация полос прокрутки
Модификация полос прокрутки - это скорее работа для пользователя вашей
программы, и часто это действительно так. Однако, ваша программа также
может модифицировать полосу прокрутки. Используемые для этого методы перечислены
в следующей таблице.
Методы модификации полос прокрутки Таблица 12.6
Выполняемое действие Вызываемый метод
Задание диапазона прокруткиУстановка позиции маркераПеремещение позиции
маркера SetRangeSetPositionDeltaPos
SetRange - это процедура, которая воспринимает два целочисленных аргумента,
наименьшую и наибольшую позицию диапазона. По умолчанию новая полоса прокрутки
имеет диапазон от 1 до 100. Вы можете изменить этот диапазон для наилучшего
расположения управляющих элементов полос прокрутки. Например, полоса прокрутки
в приложении для термостата может иметь диапазон от 32 до 120 градусов
Фаренгейта:
ThermScroll^.SetRange(32, 120);
B.Pascal 7 & Objects/OW - 217 -
SetPosition - это процедура, которая воспринимает один целочисленый аргумент
- позицию, в которую нужно переместить указатель полосы прокрутки. В рассмотренном
ранее приложении для термостата, ваша программа может непосредственно
установить температуру 78 градусов:
ThermScroll^.SetPosition(78);
Третий метод DeltaPos передвигает позицию указателя полосы прокрутки вверх
(налево) или вниз (направо) на величину, заданную целым аргументом. Положительная
целая величина перемещает указатель вниз (направо). Отрицательная целая
величина перемещает его вверх (налево). Например, для уменьшения температуры
термостата на 5 градусов используется:
ThermScroll^.DeltaPos(-5);
Реакция на полосы прокрутки
При работе пользователя с полосой прокрутки ее порождающее окно получает
от нее уведомляющие сообщения Windows. Если нужно, чтобы ваше окно реагировало
на сообщения прокрутки, реакция на информационные сообщения должна быть
обычной, путем определения методов реакции, основанных на дочерних идентификаторах.
Однако, уведомляющие сообщения полосы прокрутки несколько отличаются от
других уведомляющих сообщений элемента управления. Они основаны на сообщениях
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;
Часто альтернатива состоит в том, чтобы не реагировать на перемещение
указателя до тех пор, пока пользователь не выберет
B.Pascal 7 & Objects/OW - 218 -
его нового местоположения. В этом случае нужно реагировать на сообщение
с кодом sb_ThumbTrack.
procedure TestWindow.HandleThermScrollMsg(var Msg: TMessage);
var
NewPos: Integer; begin
if Msg.wParam <> sb_ThumbTrack
then begin
NewPos:=ThermScroll^.GetPosition;
некоторая обработка на основе NewPos.
end;
end;
Иногда может потребоваться, чтобы объекты полосы прокрутки сами реагировали
на уведомляющие сообщения полосы прокрутки. При этом конкретная реакция
поведения должна быть встроена в объект полосы прокрутки. Для программирования
объекта полосы прокрутки, который непосредственно реагировал бы на его
информационные сообщения, нужно определить для его типа метод реакции,
основанный на информации. В качестве идентификатора заголовка метода нужно
использовать сумму nf_First и информационного кода полосы прокрутки. Этот
процесс описан в разделе "Уведомляющие сообщения управляющих элементов"
Главы 16.
Пример программы: SBarTest
Программа SBarTest создает приложение для термостата, показанное на Рис.
12.5. Полный текст программы содержится в файле SBARTEST.PAS на ваших
дистрибутивных дискетах.
Использование управляющих элементов редактирования
Управляющие элементы редактирования могут быть описаны, как интерактивные
статические управляющие элементы. Это прямоугольные области (с рамкой
или без) на экране, которые пользователь приложения может заполнять текстом,
изменять или удалять. Управляющий элемент редактирования наиболее удобен
в качестве поля для ввода данных на экране. Они обеспечивают следующие
операции:
- Ввод текста пользователем.
- Динамическое отображение текста приложением.
- Вырезание, копирование и вставка в буфер вырезанного изображения.
- Многострочное редактирование (удобно для текстовых редакторов).
B.Pascal 7 & Objects/OW - 219 -
На Рис. 12.7 показано окно с двумя управляющими элементами редактирования.
Edit Control Tester
Оригинал: Копия:
|Default Text | | > | |DEFAULT.TEXT |
Рис. 12.7 Окно с управляющими элементами редактирования.
B.Pascal 7 & Objects/OW - 220 -
Построение управляющих элементов редактирования
Конструктор Init управляющего элемента редактирования аналогичен конструктору
статического управляющего элемента и воспринимает 6 обычных параметров,
плюс начальная текстовая строка, максимальная длина строки и флаг Multiline
типа Boolean. Конструктор TEdit описывается следующим образом:
constructor TEdit.Init(AParent: PWindowsObject;
AnID: Integer; ATitle: PChar;
X, Y, W, H, ATextLen: Integer; Multiline: Boolean);
По умолчанию управляющий элемент редактирования имеет стили ws_Child,
ws_Visible, es_TabStop, es_Left и es_AutoHScroll. Так как управляющий
элемент должен включать в себя завершающий нулевой символ, параметр длины
текста на самом деле на 1 превышает максимальное число символов, допустимых
в строке редактирования.
Если Multiline имеет значение True, то управление редактированием имеет
стиль es_MultiLine, es_AutoVScroll, ws_VScroll и ws_HScroll. Приведем
типичные конструкторы управляющих элементов редактирования (один для однострочного
элемента, другой - для многострочного):
EC1 := New(PEdit, Init(@Self, id_EC1, 'Default Text', 20, 50,
150, 30, 40, False));
EC2 := New(PEdit, Init(@Self, id_EC2, '', 20, 20, 200, 150,
40, True));
Использование буфера вырезанного изображения и меню Edit
Вы можете передавать текст непосредственно между объектом управляющего
элемента редактирования и буфером вырезанного изображения Windows, используя
для этого вызовы методов. Часто вам бывает нужно предоставить пользователю
доступ к этим методам через меню редактирования. Объект управляющего элемента
редактирования автоматически отреагирует на выбор из меню таких вариантов,
как Edit|Copy и Edit|Undo. TEdit определяет основанные на командах методы
(например, CMEditCopy и CMEditUndo), которые вызываются в ответ на конкретный
выбор (команду) меню в порождающем окне управляющего элемента редактирования.
CMEditCopy вызывает Copy, а CMEditUndo вызывает Undo.
B.Pascal 7 & Objects/OW - 221 -
Следующая таблица содержит список методов, которые вызываются в ответ
на выбор пункта меню:
Управляющие элементы редактирования и меню Edit Таблица 12.7
Операция Метод TEdt Команда меню
Копирование текста в буфер вырезанного изображения. Cut cm_EditCut
Вырезание текста в буфер вырезанного изображения. Copy cm_EditCopy
Вставка текста из буфера вырезанного изображения. Paste cm_EditPaste
Очистка всего элемента редактирования. Clear cm_EditClear
Удаление выделенного текста. DeleteSelection cm_EditDelete
Отмена последнего редактирования. Undo cm_EditUndo
Чтобы добавить в окно меню редактирования, содержащее управляющий элемент
редактирования, определите для окна с помощью команд, перечисленных в
Таблице 12.7, ресурс меню. Никаких новых методов вам писать не нужно.
Имеется также один дополнительный метод в виде булевской функции CanUndo,
который определяет, можно ли отменить последнюю операцию редактирования.
B.Pascal 7 & Objects/OW - 222 -
Опрос управляющих элементов редактирования
Иногда нужно организовать опрос управляющих элементов редактирования для
проверки допустимости введенного текста, записи ввода для его последующего
использования или копирования ввода в другой управляющий элемент. TEdit
поддерживает несколько методов опроса. Многие из опросов управляющих элементов
редактирования и методов модификации возвращают или требуют от вас указать
номер строки или позицию символа в строке. Все эти индексы начинаются
с нуля. Другими словами, первая строка - это нулевая строка, а первый
символ в любой строке это нулевой символ. Самыми важными методами запроса
являются GetText, GetLine, NumLines и LineLength.
Методы опроса управляющих элементов редактирования Таблица12.8
Выполняемое действие Вызываемый метод
Определение изменения текстаСчитывание всего текстаСчитывание строкиПолучение
числа строкПолучение длины данной строкиПолучение индекса выделенного
текстаПолучение диапазона символовПодсчет символов перед строкойПоиск
строки, содержащей индекс IsModifiedGetTextGetLineGetNumLinesGetLineLengthGetSelectionGetSubTextLineIndexGetLineFromProc
Вы можете заметить, что методы запросов TEdit, которые возвращают текст
из управляющего элемента редактирования, сохраняют форматирование текста.
Это важно только для многострочных управляющих элементов редактирования,
которые допускают появление нескольких строк текста. В этом случае возвращаемый
текст, который занимает несколько строк в управляющем элемента редактирования
содержит в конце каждой строки два дополнительных символа: возврат каретки
(#13) и смена строки (#10). Если этот текст снова помещается в управляющий
элемент редактирования, вставляется из буфера вырезанного изображения,
записывается в файл или выводится на принтер, то строки разбиваются так,
как это было в управляющем элемента редактирования.
Следовательно, при использовании метода запроса для получения определенного
числа символов, нужно учитывать эти два символа, которые заканчивают строку.
GetText ищет текст в управляющем элементе редактирования. Он заполняет
строку, на которую указывает переданный аргумент PChar, содержимым управляющего
элемента редактирования, включая перевод строки. Общее число символов
задается вторым параметром. Он возвращает значение False, если управляющий
элемент редактирования пуст, или содержит текста больше, чем помещается
в предоставленную строку. Следующая процедура считывает из управляющего
элемента редактирования строку и выделенный текст:
B.Pascal 7 & Objects/OW - 223 -
procedure TTestWindow.ReturnText(RetText: PChar);
var TheText: array[0..20] of Char;
begin
if EC1^.GetText(@TheText, 20) then
RetText:=@TheText else RetText:=nil;
end;
procedure TTestWindow.ReturnText(RetText: PChar);
var TheText: array[0..20] of Char;
begin
RetText:=nil; with EC^ do
if NumLines >= LineNum then
if LineLength(LineNum) < 11 then
if GetLine(@TheText, 20, LineNum) then
RetText := @TheText; end;
procedure TestWindow.ReturnLineText(RetText: PChar;
LineNum: Integer); var
TheText: array[0..20] of Char; begin
with EC1^ do
begin
GetSelection(SelStart, SelEnd);
GetSubText(TheText, SelStart, SelEnd); end;
RetText := TheText; end;
Модификация управляющих элементов редактирования
Для традиционной программы ввода текста вам может не потребоваться непосредственно
модифицировать управляющий элемент редактирования. Пользователь модифицирует
текст, а программа считывает этот текст методом опроса. Однако, во многих
других случаях использование управляющего элемента редактирования требует,
чтобы ваше приложение явно заменяло, вставляло, удаляло и выбирало текст.
ObjectWindows обеспечивает подобное поведение и кроме того предоставляет
возможность использовать прокрутку управляющего элемента редактирования.
Методы модификации
управляющих элементов редактирования Таблица 12.9
Выполняемое действие Вызываемый метод
| Удаление всего текста | Clear |
| Удаление выделенного текста | DeleteSelection |
B.Pascal 7 & Objects/OW - 224 -
| Удаление диапазона символов | DeleteSubText |
| Удаление строки текста | DeleteLine |
| Вставка текста | Insert |
| Вставка текста из буфера | Paste |
| вырезанного изображения | |
| Замена всего текста | SetText |
| Выделение диапазона текста | SelectRange |
| Прокрутка текста | Scroll |
-----------------------------------------------------------------
Пример программы: EditTest
EditTest - это программа, которая помещает на экран основное окно, которое
будет порождающим для двух управляющих элементов редактирования, двух
статических управляющих элементов и кнопки. Данное окно показано на Рис.
12.7.
Когда пользователь щелкает на командной кнопке кнопкой "мыши",
текст из левого управляющего элемента редактирования (EC1) копируется
в правый управляющий элемент редактирования (EC2). В EC2 текст преобразуется
в буквы верхнего регистра, поскольку оно было построено со стилем es_UpperCase.
Если в C1 никакой текст не выбран, то в EC2 копируется весь текст. Если
в EC1 выбран некоторый текст, то будет скопирован именно он. Меню редактирования
обеспечивает функции редактирования независимо от того, с каким управляющим
элементов редактирования идет работа. Полный файл EDITTEST.PAS и файл
ресурса EDITTEST содержатся на ваших дистрибутивных дискетах.
Использование комбинированных блоков
Управляющий элемент типа комбинированного блока является сочетанием двух
других управляющих элементов: блока списка и управляющего элемента редактирования.
Он служит тем же целям, что и блок списка - позволяет пользователю выбрать
один элемент списка из прокручиваемого списка элементов текста, нажимая
на кнопку "мыши". Управление редактированием, вынесенное в верхнюю
часть блока списка предоставляет иной механизм выбора, позволяя пользователю
ввести текст нужного элемента. Если отображается область списка комбинированного
блока, то автоматически выбирается нужный элемент. Тип TComboBox является
производным от типа TListBox и наследует его методы модификации, опроса
и выбора элементов списка. Кроме того, TComboBox предоставляет методы
по манипулированию списком, находящемся в комбинированном блоке, который
в некоторых случаях может раскрываться по запросу.
B.Pascal 7 & Objects/OW - 225 -
Три типа комбинированных блоков
Имеются три типа комбинированных блоков: простые, раскрывающиеся и раскрывающиеся
со списком. На Рис. 12.8 показан вывод трех типов комбинированных блоков
с блоком списка.
Static Control Tester
Блок списка Простой комбинированный блок ------------------ ----------------------------
|a | | | |b | ---------------------------- |c | |a | |d | |b | |e | |c
| |f | |d | ------------------ ---------------------------Раскрывающийся
комбинированный Комбинированный блок с блок раскрывающимся списком
| || v | |c | v |
Рис. 12.8 Три типа комбинированных блоков и блок списка.
Перечень стилей комбинированного блока Таблица 12.10
Стиль Возможность скрытого списка Соответствие текста списку
ПростойРаскрывающийсяРаскрывающийся со списком нетестьесть нетнетда
С точки зрения пользователя между различными стилями комбинированных блоков
существуют следующие различия:
* Простые комбинированные блоки.
Простой комбинированный блок не может делать область списка скрытой. Его
область редактирования ведет себя аналогично управляющему элементу редактирования.
Пользователь может вводить и редактировать текст, и текст не обязан
B.Pascal 7 & Objects/OW - 226 -
совпадать ни с одним из элементов в списке. При совпадении выбирается
соответствующий элемент списка.
* Раскрывающиеся комбинированные блоки.
Раскрывающиеся комбинированные блоки ведут себя аналогично простым комбинированным
блокам, но с одним исключением. В начальной стадии работы их область списка
не отображается. Она появляется, когда пользователь нажимает стрелку вниз,
расположенную справа от области редактирования. Раскрывающиеся комбинированные
блоки и раскрывающиеся комбинированные блоки списков очень удобны, когда
нужно поместить большое число управляющих элементов в маленькую область.
Когда они не используются, то занимают значительно меньшую площадь, чем
простой комбинированный блок или блок списка.
* Раскрывающиеся комбинированные блоки списка.
Область списка в раскрывающемся комбинированном блоке списка ведет себя
подобно области списка в спускающемся комбинированном блоке - появляется
при необходимости и исчезает, когда не нужна. Эти два типа комбинированных
блоков отличаются поведением их областей редактирования. Раскрывающиеся
области редактирования ведут себя подобно обычным управляющим элементам
редактирования. Раскрывающиеся области редактирования списка ограничиваются
только отображением одного элемента списка. Если редактируемый текст соответcтвует
элементу списка, то никаких дополнительных символов ввести нельзя.
Выбор типа комбинированного блока
Раскрывающиеся комбинированные блоки списка удобно использовать тогда,
когда не допускаются никакие другие варианты, кроме перечисленных в области
списка. Например, при выборе принтера для печати можно выбрать только
принтер, к которому есть доступ в вашей системе.
С другой стороны, раскрывающиеся комбинированные блоки могут воспринимать
выбор, который отличается от приведенных в списке элементов. Раскрывающийся
комбинированный блок можно использовать для выбора файлов на диске при
их открытии или записи. Пользователь может либо просматривать каталоги
в поисках нужного файла, либо ввести полный маршрут и имя файла в области
редактирования, независимо от того, присутствует ли это имя файла в области
списка.
Построение комбинированных блоков
Кроме обычных 6 параметров объектов управляющих элементов конструктор
Init для TComboBox воспринимает в качестве аргументов
B.Pascal 7 & Objects/OW - 227 -
стиль и максимальную длину текста. Конструктор TComboBox описывается следующим
образом:
constructor TComboBox.Init(AParent: PWindowsObject;
AnID: Integer: X, Y, W, H: Integer; AStyle, ATextLen: Word);
Все комбинированные блоки, построенные с помощью Init, имеют стили ws_Child,
ws_Visible, cbs_AutoHScroll, cbs_Sort (отсортированный список), и VScroll
(вертикальная полоса прокрутки). Параметр стиля - это один из стандартных
стилей комбинированных блоков Windows: cbs_Simple, cbs_DropDown или cbs_DropDownList.
Параметр длины текста работает подобно соответствующему параметру управляющего
элемента редактирования, ограничивая число символов, которые можно ввести
в область редактирования комбинированного блока.
Следующие строки приведут к созданию спускающегося комбинированного блока
списка с неотсортированным списком:
CB3: = New(PComboBox, Init(@Self, id_CB3, 190, 160,
150, 100, cbs_DropDownList, 40)); CB3^.Attr.Style:=CB3^.Attr.Style and
(not cbs_Sort);
Модификация комбинированных блоков
TComboBox определяет два метода для демонстрации и сокрытия области списка
в раскрывающихся комбинированных блоках и раскрывающихся комбинированных
блоках списка: ShowList и HideList. Обе эти процедуры не нуждаются в аргументах.
Вызывать эти методы для демонстрации или сокрытия списка, когда пользователь
нажимает стрелку вниз справа от области редактирования, не нужно. В этом
случае работает автоматический механизм комбинированных блоков. Эти методы
полезны только для принудительного вывода или сокрытия списка.
Пример программы: CBoxTest
Программа CBoxTest реализует приложение, показанное на Рис.
12.8. В нем использованы все три типа комбинированных блоков. CB1
- это простой комбинированный блок, CB2 это раскрывающийся комбинированный
блок, а CB3 - это раскрывающийся комбинированный блок списка. Нажатие
кнопок Show и Hide выполняет принудительный вывод и сокрытие правого верхнего
комбинированного блока, CB3, путем вызова методов ShowList и HideList.
Примечание: Полный текст файла CBOXTEST.PAS содержится на ваших дистрибутивных
дискетах.
Установка значений управляющих элементов
B.Pascal 7 & Objects/OW - 228 -
Для управления сложными блоками диалога или окнами с множеством дочерних
окон управляющих элементов вы обычно можете для хранения и выяснения состояния
его управляющих элементов создать производный тип объекта. Состояние управляющего
элемента включает в себя текст управляющего элемента редактирования, положение
полосы прокрутки и установку кнопки с зависимой фиксацией.
Для чего используется буфер передачи?
В качестве альтернативы вы можете не определять производный объект, а
определить соответствующую запись, представляющую состояние управляющих
элементов окна или диалога. Эта запись называется буфером передачи, поскольку
легко передает информацию о состоянии между буфером и набором управляющих
элементов.
Например, ваша программа может иметь режимный блок диалога и после его
закрытия, выделить информацию из буфера передачи относительно состояния
каждого из его управляющих элементов. Следовательно, при повторном вызове
пользователем блока диалога, его управляющие элементы будут выведены в
соответствии с их состоянием перед последним закрытием диалога. Кроме
того, вы можете установить начальное состояние каждого из управляющих
элементов и на основании данных буфера передачи. Вы можете явно передавать
данные в любом направлении в любой момент времени, например, установить
значения управлений равными их предыдущим значениям. Окно или безрежимный
блок диалога с управляющими элементами также могут использовать механизм
передачи для установки или выяснения информации о состоянии в любой момент
времени.
Механизм передачи требует для представления управляющих элементов, для
которых вы будете передавать данные, использования объектов ObjectWindows.
Это означает, что вы должны использовать InitResource для связывания объектов
с управляющими элементами в блоках и окнах диалога.
Примечания: Связь управляющих элементов с управляющими объектами описывается
в Главе 11 "Объекты диалоговых блоков".
Чтобы использовать механизм передачи, вы можете сделать следующее:
* Определить буфер передачи.
* Определить соответствующее окно.
* Передать данные.
Определение буфера передачи
Буфер передачи - это запись с одним полем для каждого управ-
B.Pascal 7 & Objects/OW - 229 -
ляющего элемента, участвующего в передаче. Окно или диалог могут
также иметь управляющие элементы, значения которых не устанавливаются
механизмом передачи. Например, командные кнопки, у которых нет состояния,
не участвуют в передаче. Это же справедливо для групповых блоков.
Для определения буфера передачи нужно определить поле для каждого участвующего
управляющего элемента диалога или окна. Определять поля для каждого управления
диалога или окна не требуется - нужно лишь определить поля для тех из
них, которые будут получать и принимать значения по вашему желанию. Этот
буфер передачи хранит один из каждых типов управляющих элементов, кроме
командной кнопки и блока группы:
type
TSampleTransferRecord = record
Stat1: array[0..TextLen-1] of Char; статический текст
Edit1: array[0..TextLen-1] of Char; текст управляющего элемента редактирования
List1Strings: PStrCollection; строки блока списка
List1Selection: Integer; индекс выбранных строк
ComboStrings: PStrCollection; строки комбинированного блока
ComboSelection: array[0..TextLen-1] of Char; выбранные строки
Check1: Word; проверка состояния блока
Radio1: Word; состояние кнопки с независимой фиксацией Scroll1: ScrollBarTransferRec;
диапазон полосы
прокрутки и т.д.
end;
B.Pascal 7 & Objects/OW - 230 -
В каждом типе управляющего элемента хранится различная информация. Буфер
передачи для каждого стандартного управляющего элемента поясняется в следующей
таблице:
Поля буфера передачи
для каждого типа управляющего элемента Таблица 12.11
Тип управляющего элемента Буфер передачи
Статический Символьный массив размером до максимальной длины текста, плюс
завершающий нулевой символ.
Редактирование Текстовый буфер управляющего элемента редактирования размером
до длины, определенной в текстовом поле TextLen.
Блок списка одиночный выбормножественный выбор Набор строк в списке, плюс
целочислен-ный индекс выделенной строки.Набор строк в списке, плюс запись,
содержащая индексы всех выделенных элементов.
Комбинированный блок Набор строк в списке, плюс выбраннаястрока.
Кнопка с независимойфиксацией Значения Word с указывающими состоянияbf_Unchecked,
bf_Checked и bf_Grayed.
Кнопка с зависимойфиксацией Значения Word с указывающими состоянияbf_Unchecked,
bf_Checked и bf_Grayed.
Полоса прокрутки Запись типа TScrollBarTransferRec, сохраняющая диапазон
полосы прокрутки и позицию в ней.
Тип TScrollBarTransferRec имеет вид:
TScrollBarTransferRec := record
LowValue : Integer;
HighValue: Integer;
B.Pascal 7 & Objects/OW - 231 -
Position : Integer; end;
Определение окна
Окно или диалоговый блок, которые используют буфер передачи, должны создавать
объекты участвующих управляющих элементов в той последовательности, в
которой определяются их соответствующие поля буфера передачи. Для подключения
механизма передачи к объекту окна или диалога нужно просто установить
значение его поля TransferBuffer в указатель на определенный вами буфер
передачи.
Использование буфера передачи с диалоговым блоком
Для случая окон с управляющими элементами объекты управляющих элементов
конструируются с использованием Init. Для диалогов и окон диалогов нужно
использовать конструктор InitResource. Например (используется определенный
ранее тип TSampleRecord):
type
TSampleTransferRecord = record
.
.
.
PParentWindow = ^TParentWindow;
TParentWindow = object(TWindow)
TheDialog: PDialog;
TheBuffer: SampleTransferRecord;
.
.
B.Pascal 7 & Objects/OW - 232 -
.
.
constructor TParentWindow.Init(AParent: PWindowsObject;
ATitle: PChar); var
Stat1: PStatic;
Edit1: PEdit;
List1: PListBox;
Combo1: PComboBox;
Check1: PCheckBox;
Radio1: PRadioButton;
Scroll1: PScrollBar; begin
TWindow.Init(AParent, ATitle);
TheDialog^.Init(@Self, PChar(101));
New(Stat1, InitResource(TheDialog, id_Stat1));
New(Edit1, InitResource(TheDialog, id_Edit1));
New(List1, InitResource(TheDialog, id_List1));
New(Combo1, InitResource(TheDialog, id_Combo1));
New(Check1, InitResource(TheDialog, id_Check1));
New(Radio1, InitResource(TheDialog, id_Radio1));
New(Scroll1, InitResource(TheDialog, id_Scroll1));
TheDialog^.TranssferBuffer:=@TheBuffer; end;
Для управляющих элементов, построенных с помощью
InitResource, механизм передачи разрешается автоматически.
B.Pascal 7 & Objects/OW - 233 -
Использование буфера передачи с окном
Для случая окна с управляющими элементами используйте для конструирования
объектов управления в надлежащей последовательности Init, а не InitResource.
Другое отличие между диалогами и окнами состоит в том, что механизм передачи
по умолчанию для управляющих элементов окна запрещен. Для разрешения использования
механизма вызывается EnableTransfer:
constructor TSampleWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
Edit1 := New(PEdit, Init(@Self, id_Edit1, '', 10, 10,
100, 30, 40, False));
Edit1^.EnableTransfer; end;
Чтобы явно исключить управляющий элемент из механизма передачи, вызовите
после его создания метод DisableTransfer.
Передача данных
В большинстве случаев передача данных в окно выполняется автоматически,
но в любой момент вы можете явно передать данные.
Передача данных в окно
После создания окна или диалогового блока данные автоматически. Для создания
экранного элемента, представляющего оконный объект, конструктор вызывает
SetupWindow. Затем для загрузки данных из буфера передачи вызывается TransferData.
Окно SetupWindow интерактивно вызывает SetupWindow для каждого из дочерних
окон, так что дочерние окна имеют возможность передать свои данные. Поскольку
порождающее окно устанавливает свои дочерние окна в порядке их построения,
данные в буфере передачи должны следовать в том же порядке.
Если объект управляющего элемента был построен с помощью InitResource
или если порождающее окно явным образом разрешило межанизм передачи путем
вызова для управляющего элемента EnableTransfer, то методы управляющего
объекта SetupWindow вызывают TransferData.
Передача данных из диалогового окна
Когда режимное диалоговое окно получает командной сообщение с идентификатором
управляющего элемента id_OK, оно автоматически передает данные из управляющего
элемента в буфер передачи. Обычно это сообщение указывает, что пользователь
для завершения диалога щелкнул "мышью" на кнопке OK, так что
диалог автоматически обновляет свой буфер передачи. Затем, если вы снова
выполняете диалог, диалоговый блок передает текущие данные в управляющие
элементы.
Передача данных из окна
Однако, вы можете явно передавать данные в любом направлении в любой момент
времени. Например, вы можете передать данные из управляющих элементов
окна или безрежимного диалога. Вы также можете сбросить состояния управляющих
элементов, используя данные буфера передачи, в ответ на щелчок "мышью"
на кнопке Reset (сброс). В обоих случаях используется метод TransferData.
Константа tf_SetData обозначает передачу данных из буфера в управляющий
элемент, а константа tf_GetData - передачу в другом направлении. Например,
вы можете вызвать TransferData в методе Destroy объекта окна:
procedure TSampleWindow.Destroy;
begin
TransferData(tf_GetData);
TWindow.Destroy; end;
Поддержка передачи для специализированных управляющих элементов
Вы можете изменить способ передачи данных для конкретного управляющего
элемента или включить новый управляющий элемент, определенный вами в механизме
передачи. В обоих случаях вам просто нужно написать метод Transfer для
вашего управляющего объекта, который если установлен флаг tf_GetData копирует
данные из управляющего элемента в место, задаваемое указателем. Если установлен
флаг tf_SetData, то просто скопируйте данные по заданному указателю в
управляющий элемент. Рассмотрим в качестве примера TStatic.Transfer:
function TStatic.Transfer(DataPrt: Pointer;
TransferFlag: Word): Word; begin
if TransferFlag = tf_GetData then
GetText(DataPrt, TextLen)
else if TransferFlag = tf_SetData then
SetText(DataPtr);
Transfer:=TextLen; end;
Метод Transfer должен всегда возвращать число переданных байт информации.
Пример программы: TranTest
Основное окно программы TranTest воспроизводит режимный диа-
B.Pascal 7 & Objects/OW - 235 -
лог с полями, в которые пользователь вводит данные об имени и адресе.
Буфер передачи используется для хранения этой информации и отображения
ее в управляющих элементах диалога при повторном его выполнении. Обратите
внимание на то, что нам не нужно определять новый тип объекта диалога
для установки и поиска данных диалога. Также обратите ваше внимание на
то, что мы непосредственно манипулируем данными буфера передачи, поэтому
статическое управление при первом выводе диалога гласит "First Mailing
Label" (первая почтовая этикетка), а при всех остальных появлениях
"Subsequent Mailing Label" (следующая почтовая этикетка).
Примечание: Полный текст программы содержится в файле TRANTEST.PAS на
ваших дистрибутивных дискетах.
B.Pascal 7 & Objects/OW - 236 -
Использование специализированных управляющих элементов
Windows обеспечивает механизм, позволяющий вам создавать свои собственные
виды управляющих элементов, а ObjectWindows облегчает создание объектов,
использующих преимущества управляющих элементов. В данном разделе обсуждается
использование специализированных управляющих элементов Borland, которые
придают своеобразный вид работающим в Windows приложениям Borland, а затем
описывается, как создавать свои собственные уникальные управляющие элементы.
Специализированные управляющие элементы Borland для Windows
Специализированные управляющие элементы Borland для Windows (BWCC) обеспечивают
выразительный внешний вид приложений Borland для Windows. Основными средствами
BWCC являются:
* командные кнопки с графическими изображениями;
* серый "рельефный" фон диалоговый блоков;
* трехмерные кнопки с зависимой и независимой фиксацией.
ObjectWindows дает вам возможность простого доступа к BWCC, так что вы
можете придать своим приложениями стандартный для Borland вид.
B.Pascal 7 & Objects/OW - 237 -
Использование стандартных BWCC
ObjectWindows позволяет легко добавлять BWCC в ваши приложения Windows.
Нужно просто добавить модуль BWCC в оператор uses программы:
uses BWCC;
Использование BWCC автоматически позволяет вам делать следующее:
* использовать загружаемые из ресурсов управляющие элементы
BWCC;
* создавать в вашей программе BWCC.
Например, с помощью пакета разработчика ресурсов Resource WorkShop вы
можете создать ресурсы диалоговых блоков, использующие специализированные
управляющие элементы Borland. Включение в оператор uses программы модуля
BWCC обеспечивает для вашей программы информацию о том, где искать динамически
компонуемую библиотеку (BWCC.DLL), содержащую код, который обеспечивает
работу BWCC.
Кроме того, после добавления модуля BWCC любые создаваемые в программе
объекты управляющих элементов будут иметь вид и характеристики управляющих
элементов Borland.
Средства BWCC
BWCC добавляет к стандартным управляющим элементам в стиле Windows некоторые
новые стили, но подчиняется также новым соглашения и предположениям. Если
вы создаете все свои новые управляющие элементы из ресурсов, то беспокоиться
об этом вам не нужно. Однако при построении управляющих элементов в программном
коде вам может потребоваться использовать некоторые новые стили и следовать
соглашениям.
B.Pascal 7 & Objects/OW - 238 -
Расширение BWCC
BWCC обеспечивает кнопки с графическими изображениями для всех стандартных
командных кнопок Windows. То есть, имеются графические изображения, предусмотренные
для командных кнопок, для которых Windows обеспечивает стандартный идентификатор:
id_Abort, id_Cancel, id_Ignore, id_No, id_Ok, id_Retry и id_Yes.
Создание кнопок с графическими изображениями
В своих приложениях вы можете обеспечить для командных кнопок собственные
графические образы. Все что нужно предусмотреть - это шесть ресурсов графических
изображений (битовых массивов), пронумерованных относительно идентификатора
управляющего элемента вашей командной кнопки. Например, если вы хотите
создать графическую командную кнопку с идентификатором id_MyButton, то
создаете ресурсы битовых массивов с идентификаторами ресурса 1000 + id_MyButton,
2000 + id_MyButton, 3000 + id_MyButton, 4000 + id_MyButton, 5000 + id_MyButton
и 6000 + id_MyButton. Каждый представляемый битовый массив показан в следующей
таблице:
Ресурсы битовых массивов для командных кнопок BWCC Таблица 12.12
Образ Идентификатор ресурса VGA Идентификатор ресурса VGA
Командная кнопкав фокусе 1000 + идент. 2000 + идент.
Нажатая команднаякнопка 3000 + идент. 4000 + идент.
Командная кнопкане в фокусе 5000 + идент. 6000 + идент.
Графические образы командных кнопок VGA должны иметь ширину 63 и высоту
39 элементов изображения. Графические образы командных кнопок EGA должны
иметь ширину 63 и высоту 39 элементов изображения.
B.Pascal 7 & Objects/OW - 239 -
Для текста следует использовать шрифт Helvetica размером 8 пунктов, а
вокруг образа кнопки, находящейся в фокусе, следует выводить рамку из
точек. Набор графических изображений для командных кнопок с идентификатором
201 показан на следующем рисунке:
-------------------- -------------------- --------------------
| | | | | |
| Add | | Add | | Add |
| Pen | | Pen | | Pen |
| | | | | |
| | | | | |
-------------------- -------------------- --------------------
1201 3201 5201
-------------------- -------------------- --------------------
| | | ..... | | ..... |
| Add | | : Add : | | : Add : |
| Pen | | : Pen : | | : Pen : |
| | | ..... | | ..... |
| | | | | |
-------------------- -------------------- --------------------
2201 4201 6201
Рис. 12.9 Графические ресурсы для командной кнопки BWCC с идентификатором
201.
B.Pascal 7 & Objects/OW - 240 -
Создание ваших собственных специализированных управляющих элементов
-----------------------------------------------------------------
Простейший способ создания специализированного управляющего элемента состоит
в фактическом создании окна, которое действует как управляющий элемент,
но вовсе не является окном. Этот подход используется в программе Steps
в Части 1 данного руководства. Тот же используемый в программе Steps метод
применяется для ее объекта палитры, который можно использовать, например,
для создания объекта инструментальной полосы. Таким "управляющие
элементы" являются наследниками TWindow, а не TControl, поскольку
TControl имеет дело только со стандартными управляющими элементами Windows.
Другим стандартным способом создания специализированного управляющего
элемента является построение в динамически компонуемой библиотеке нового
класса окон. После этого вы можете создавать объекты ObjectWindows, использующие
этот новый класс. Пакет разработчика ресурсов также может использовать
специализированные управляющие элементы, созданные в DLL. Информацию об
использовании специализированных управляющих элементов в ресурсах диалоговых
блоках вы можете найти в "Руководстве пользователя по пакету разработчика
ресурсов".
Примечание: О классах окон рассказывается в Главе 10.
B.Pascal 7 & Objects/OW - 241 -
Глава 13. Проверка допустимости данных
ObjectWindows представляет вам несколько гибких способов проверки допустимости
информации, набираемой пользователем в управляющем элементе редактирования,
путем связи объектов проверки допустимости с объектами управляющих элементов
редактирования. Использование объектов проверки допустимости облегчает
добавление механизма проверки допустимости к существующим приложениям
ObjectWindows или для изменения способа проверки в поле его данных.
Данная глава охватывает следующие темы, относящиеся к проверке допустимости:
* Три вид проверки допустимости данных.
* Использование объектов проверки допустимости.
* Как работает проверка допустимости.
Проверка допустимости обрабатывается методом CanClose интерфейсных объектов.
В любой момент вы можете проверить содержимое любого конкретного управляющего
элемента редактирования или экрана данных, вызвав метод CanClose объекта,
но ObjectWindows предусматривает также механизм автоматизации проверки
допустимости данных. В большинстве случаев проверка допустимости данных
практически не требует от программиста никаких усилий.
Три вида проверки допустимости данных
Существует три различных типа проверки допустимости данных, и ObjectWindows
поддерживает их по-разному. Этими тремя видами являются:
* Фильтрация ввода.
* Проверка допустимости каждого элемента.
* Проверка допустимости полных экранов.
Заметим, что эти методы не являются взаимно-исключающими. Ряд стандартных
средств проверки допустимости могут комбинировать в одном механизме проверки
допустимости различные методы.
Важно запомнить, что проверка допустимости выполняется объектом проверки
допустимости, а не объектом управляющего элемента редактирования. Если
вы уже создали для особого назначения специализированный управляющий элемент
редактирования, то возможно сдублировали возможность, встроенную в управляющие
элементы редактирования и их средства проверки допустимости.
B.Pascal 7 & Objects/OW - 242 -
В разделе данной главы "Как работают средства проверки допустимости"
описываются различные способы, с помощью которых объекты управляющего
элемента редактирования автоматически вызывают объекты проверки допустимости.
Фильтрация ввода
Простейший способ обеспечения включения в поле только допустимых данных
состоит в обеспечении ввода пользователем только допустимых данных. Например,
числовое поле ввода может быть ограничено вводом пользователем только
цифровых данных.
Объект фильтра проверки допустимости ObjectWindows представляет общий
механизм, ограничивающий вид символов, которые пользователь может вводить
в данном управляющем элементе редактирования. Объекты проверки допустимости
рисунков могут также контролировать форматирование и типы символов, которые
может набирать пользователь.
Проверка допустимости каждого поля
Иногда удобно гарантировать, чтобы пользователь обеспечивал для конкретного
поля допустимый ввод перед переходом к следующему полю. Этот подход часто
называют "проверкой допустимости по табуляции", поскольку переход
в новое поле обычно выполняется по клавише Tab.
В качестве примера можно привести приложение, которое выполняет поиск
в базе данных, где пользователь вводит в поле некоторые виды ключевой
информации, а приложение отвечает на это считыванием соответствующей записи
и фильтрацией остальных полей. В таком случае вашему приложению перед
действием по клавише требуется проверка, что пользователь набрал в этом
ключевом поле правильную информацию.
Проверка допустимости полных экранов
Проверить допустимость полных экранов вы можете тремя различными способами:
* Проверкой допустимости режимных окон.
* Проверкой допустимости при изменении фокуса.
* Проверкой допустимости по запросу.
Проверка допустимости режимных окон
Когда пользователь закрывает режимное окно, оно перед закрытием автоматически
проверяет допустимость всех своих подобластей просмотра (если закрывающей
командой не была cmCancel). Для проверки допустимости всех подобластей
окно вызывает метод CanClose
B.Pascal 7 & Objects/OW - 243 -
каждой подобласти, и если каждый из них возвращает True, то окно
можно закрыть. Если любая из подобластей возвращает значение
False, то окно закрыть нельзя.
Пока пользователь не обеспечит допустимые данные, режимное окно с недопустимыми
данными можно только отменить.
Проверка допустимости по запросу
В любой момент вы можете указать окну на необходимость проверки всех его
подокон путем вызова метода CanClose. CanClose по существу спрашивает
окно "Если сейчас будет дана команда закрытия, являются ли все поля
допустимыми?" Окно вызывает методы CanClose всех своих дочерних окон
в порядке включения и возвращает True, если все они возвращают значение
True.
Вызов CanClose не обязывает вас фактически закрывать окно. Например, вы
можете вызвать CanClose, когда пользователь "нажимает" командную
кнопку Save (Сохранение), обеспечивая проверку допустимости данных перед
их сохранением.
Вы можете проверить любое окно (режимное или безрежимное) и в любое время.
Однако автоматическую проверку допустимости при закрытии имеют только
режимные окна. Если вы используете безрежимные окна ввода данных, то нужно
обеспечить, чтобы приложение перед выполнением действий с введенными данными
вызывало метод CanClose окна.
Использование механизма проверки допустимости данных
Использование объекта проверки допустимости данных с управляющим элементом
редактирования требует двух шагов:
* Построение объекта проверки допустимости.
* Присваивание объекта проверки допустимости управляющему
элементу редактирования.
После того, как вы построите объект проверки допустимости и свяжите его
с управляющим элементом редактирования, вам не потребуется взаимодействовать
с ним непосредственно. Управляющий элемент редактирования знает, когда
вызывать методы проверки допустимости и в какие моменты.
B.Pascal 7 & Objects/OW - 244 -
Построение объектов проверки допустимости
Так как объекты проверки допустимости не являются интерфейсными объектами,
их конструкторам требуется только информация, достаточная для установки
критерия проверки допустимости. Например, объект проверки допустимости
числового диапазона воспринимает два параметра - минимальное и максимальное
значения в допустимом диапазоне:
constructor TRangeValidator.Init(AMin, AMax: Integer);
Добавление к управляющим элементам редактирования средств проверки допустимости
-----------------------------------------------------------------
Каждый управляющий элемент редактирования имеет поле с именем Validator,
установленное по умолчанию в nil, которое может указывать на объект проверки
допустимости. Если вы не присваиваете объекта полю Validator, то управляющий
элемент редактирования ведет себя так, как описано в Главе 12. После присваивания
с помощью вызова SetValidator объекта проверки допустимости управляющий
элемент редактирования автоматически проверяется им при обработке основных
событий и при самом вызове для проверки допустимости.
Обычно, как показано ниже, объект проверки допустимости строится и присваивается
в одном операторе:
.
. создание трехсимвольного управляющего элемента редакти-
. рования
Ed := New(PEdit, Init(@Self, id_Me, '', 10, 10, 50, 30, 3,
False));
Ed^.SetValidator(New(PRangeValidator, Init(100, 999)));
.
.
.
Как работает проверка допустимости
В ObjectWindows предусмотрено несколько видов объектов проверки допустимости,
которые должны охватывать большинство ваших потребностей по проверке данных.
Из абстрактных типов проверки допустимости вы можете также построить свои
собственные производные типы.
В данном разделе освещаются следующие темы:
* Виртуальные методы объекта проверки допустимости.
* Стандартные типы объекта проверки допустимости.
B.Pascal 7 & Objects/OW - 245 -
Методы объекта проверки допустимости
Каждый объект проверки допустимости наследует от абстрактного объектного
типа TValidator четыре важных метода. Различным образом переопределяя
эти методы, наследующие объекты проверки допустимости выполняют свои конкретные
задачи по проверке. Если вы собираетесь модифицировать стандартные объекты
проверки допустимости или написать собственные объекты проверки допустимости,
то нужно понимать, что делает каждый из этих методов и как их используют
управляющие элементы редактирования.
Этими четырьмя методами являются следующие:
* Valid
* IsValid
* IsValidInput
* Error
Единственными методами, вызываемыми вне объекта, являются Valid и IsValidInput.
Error и IsValid - единственные методы, вызываемые другими методами объекта
проверки допустимости.
Проверка допустимости данных
Основным внешним интерфейсом с объектами проверки допустимости данных
является метод Valid. Аналогично методу CanClose интерфейсных объектов,
Valid представляет собой булевскую функцию, которая возвращает значение
True, если переданная ей строка содержит допустимые данные. Один из компонентов
метода CanClose управляющего элемента редактирования является вызов метода
Valid с переданным ему текущим текстом управляющего элемента редактирования.
При использовании средств проверки допустимости с управляющими элементами
редактирования вам никогда не требуется вызывать или переопределять метод
Valid объекта проверки допустимости. По умолчанию Valid возвращает True,
если возвращает True метод IsValid. В противном случае для уведомления
пользователя об ошибке и возврата значения False вызывается Error.
B.Pascal 7 & Objects/OW - 246 -
Проверка полной строки
Объекты проверки допустимости содержат виртуальный метод IsValid, который
воспринимает в качестве единственного аргумента строку и возвращает True,
если строка представляет допустимые данные. IsValid - это метод, который
выполняет фактическую проверку допустимости, так что если вы создаете
собственные объекты проверки допустимости, то почти всегда переопределяете
IsValid.
Заметим, что метод IsValid не вызывается вами явно. Используйте для вызова
IsValid метод Valid, так как для уведомления пользователя в случае возврата
методом IsValid значения False Valid вызывает метод Error. Не путайте
также проверку допустимости сообщением об ошибке.
Проверка допустимости нажатий клавиш
Когда объект управляющего элемента редактирования получает имеющее для
него значение событие нажатия клавиши, он вызывает метод IsValidInput
объекта проверки допустимости. По умолчанию методы IsValid всегда возвращают
True. Это означает, что воспринимаются все нажатия клавиш. Однако, наследующие
объекты проверки допустимости могут переопределять метод IsValidInput,
чтобы отфильтровывать нежелательные нажатия клавиш.
Например, средства проверки допустимости диапазона, которые используются
для числового ввода, возвращают из IsValidInput True только для цифр и
символов '+' и '-'.
IsValidInput воспринимает два параметра. Первый параметр - это параметр-переменная,
содержащая текущий текст ввода. Второй параметр - это булевское значение,
указывающее, следует ли перед попыткой проверки допустимости применять
к строке ввода дополнение или заполнение. TPictureValidator - это единственный
из стандартных объектов проверки допустимости, использующий второй параметр.
Сообщение о недопустимых данных
Виртуальный метод Error уведомляет пользователя, что содержимое управляющего
элемента редактирования не прошло проверку допустимости. Стандартные объекты
проверки допустимости в общем случае представляет простой блок сообщения,
уведомляющий пользователя, что содержимое ввода недопустимо, и описывающее,
каким должен быть правильный ввод.
Например, метод Error для проверки допустимости диапазона создает блок
сообщения, указывающий, что значение в управляющем элементе редактирования
не находится между указанными минимальным и максимальным значениями.
B.Pascal 7 & Objects/OW - 247 -
Хотя большинство объектов проверки допустимости переопределяют Error,
вам не следует вызывать его непосредственно. Метод Error вызывается методом
Valid, если IsValid возвращает False (что является единственным моментом,
когда необходимо вызывать Error).
B.Pascal 7 & Objects/OW - 248 -
Стандартные средства проверки допустимости
ObjectWindows включает в себя шесть стандартных типов объектов проверки
допустимости, включая абстрактный объект проверки допустимости и следующие
пять специальных типов таких объектов:
* Фильтрация.
* Проверка диапазона.
* Проверка допустимости с просмотром.
* Проверка допустимости с просмотром строк.
* Проверка допустимости с просмотром шаблонов.
Абстрактный объект проверки допустимости
Абстрактный тип TValidator служит базовым типом для всех объектов проверки
допустимости, но сам по себе он не делает ничего полезного. По существу,
TValidator - это объект проверки допустимости, для которого всегда допустим
любой ввод: IsValid и IsValidInput возвращают True, а Error не выполняет
никаких функций. Наследующие типы переопределяют IsValid и/или IsValidInput
для фактического определения того, какие значения являются допустимыми.
Если никакие из других объектных типов проверки допустимости не годятся
в качестве исходных, вы можете использовать TValidator в качестве отправной
точки собственных объектов проверки допустимости.
Фильтрация
Фильтрующие объекты проверки допустимости - это простая реализация средств
проверки допустимости, при которой проверяется только набираемый пользователем
ввод. Конструктор фильтрующего объекта проверки допустимости воспринимает
один параметр - набор допустимых символов:
constructor TFilterValidator.Init(AValidChars: TCharSet);
TFilterValidator переопределяет IsValidInput для возврата True только
в том случае, если все символы в текущей строке ввода содержатся в наборе
символов, переданных конструктору. Управляющие элементы редактирования
включают символы только в том случае, если IsValidInput возвращает True,
так что нет необходимости переопределять IsValid. Поскольку символы проходят
через фильтр ввода, полная строка допустима по определению.
Потомки TFilterValidator, такие как TRAngeValidator, могут сочетать фильтрацию
ввода с другими проверками завершенной строки.
B.Pascal 7 & Objects/OW - 249 -
Проверка диапазона
Объект проверки допустимости диапазона TRangeVaidator - это потомок TFilterValidator,
которые воспринимают только числа и добавляют к итоговым результатам проверку
диапазона. Конструктор воспринимает два параметра, определяющим минимальное
и максимальное допустимое значение:
constructor TRangeValidator.Init(AMin, AMax: Integer);
Объект проверки допустимости диапазона сам строит числовое средство проверки-фильтрации,
воспринимающее только цифры '0'..'9' и символы плюса и минуса. Таким образом,
наследуемый IsValidInput обеспечивает отфильтрацию только цифр. Затем
TRangeValidator переопределяет IsValid, чтобы он возвращал True только
если введенные числа находятся в допустимом диапазоне, определяемом в
конструкторе. Метод Error выводит блок сообщения, указывающий, что введенное
значение находится вне диапазона.
Проверка допустимости с просмотром
Абстрактный объект проверки допустимости с просмотром TLookupValidator
обеспечивает основу для общего типа объекта проверки допустимости, который
для определения допустимости сравнивает введенное значение со списком
воспринимаемый элементов.
TLookupValidator - это абстрактный тип, который никогда не используется
сам по себе, но служит важным изменением и дополнением к стандартному
объекту проверки допустимости.
Примечание: Пример работы такого объектного типа вы можете найти в разделе
по преобразованию строк.
Новый метод, вводимый объектом TLookupValidator называется Lookup. По
умолчанию Lookup возвращает значение False, но при образовании производного
абстрактного объекта проверки допустимости c просмотром вы можете переопределить
Lookup для сравнения переданной строки со списком и возвращать True, если
строка содержит допустимую запись.
TLookupValidator переопределяет IsValid для возврата True только если
Lookup также возвращает True. В наследующих типах проверки допустимости
с просмотром вам следует переопределять не IsValid, а Lookup.
Просмотр строк
Рабочий пример объекта проверки допустимости с преобразованием представляет
TStringLookupValidator, сравнивающий переданную из управляющего элемента
редактирования строку с элементами в
B.Pascal 7 & Objects/OW - 250 -
списке строк. Если переданная строка содержится в списке, метод
объекта проверки допустимости с просмотром строки возвращает
True. Конструктор воспринимает только один параметр - список допустимых
строк:
constructor TStringLookupValidator.Init(AString: PStringCollection);
Чтобы после построения объекта проверки допустимости с просмотром использовать
другой список строк, передайте новый список методу NewStringList объекта
проверки допустимости (который уничтожает старый список и задает новый).
TStringLookupValidator переопределяет методы Lookup и Error, так что Lookup
возвращает True, если переданная строка содержится в наборе строк, а Error
выводит на экран блок сообщения, указывающий, что строка отсутствует в
списке.
Проверка допустимости по шаблону
Объекты проверки допустимости с шаблоном сравнивают строки, набранные
пользователем, с шаблоном, описывающим формат допустимого ввода. Применяемые
шаблоны совместимы с теми, которые используются для контроля ввода в реляционной
базе данных Paradox фирмы Borland. При построении объекта проверки допустимости
по шаблону используется два параметра: строка, содержащая образ шаблона,
и булевское значение, указывающее, нужно ли заполнять по шаблону литеральные
строки.
Примечание: Синтаксис шаблонов описывается в справочнике. См. TPXPictureValidator.Picture.
constuctor TPictureValidator.Init(const APic: String;
AAutoFill: Boolean);
TPictureValidator переопределяет Error, IsValidInput и IsValid и добавляет
новый метод Picture. Изменения в Error и IsValid просты: Error выводит
на экран блок сообщения, указывающий, какой формат должна иметь строка,
а IsValid возвращает True только если True возвращается функцией Picture,
позволяя получать новые производные типы проверки допустимости по шаблону
путем переопределения только метода Picture. IsValidInput проверяет символы
по мере набора их пользователем, допуская только те символы, которые разрешены
в шаблоне формата, и возможно дополняя литеральные символы из шаблона.
Метод Picture пытается сформатировать заданную строку ввода в соответствии
с шаблоном формата и возвращает значение, указывающее степень успеха:
полный, неполный или ошибка.
B.Pascal 7 & Objects/OW - 251 -
Глава 14. Объекты MDI
Многодокументальный интерфейс (MDI) - это стандарт интерфейса для приложений
Windows, которые позволяют пользователю одновременно работать с несколькими
открытыми документами. Документ, в этом смысле, это обычно связанная с
файлом задача, например, редактирование текстового файла или работа с
файлом электронной таблицы. В приложениях MDI пользователь может, например,
иметь несколько открытых файлов в одном приложении. Возможно, что вы уже
использовали приложения MDI: Microsoft Exel, администратор программ Windows,
администратор файлов Windows. Стандарт MDI является также частью спецификации
общего доступа пользователя (CUA) фирмы IBM.
ObjectWindows предусматривает объекты, позволяющие легко писать приложения
MDI.
Что такое приложение MDI?
Имеются определенные компоненты, которые присутствуют в каждом приложении
MDI. Чаще всего основное окно вызывает окно с рамкой. В области клиента
окна-рамки есть невидимое окно - окно клиента MDI - которое содержит дочернее
окно, вызывающее дочерние окна MDI. Это очень важно, т.к. обработка дочерних
окон MDI происходит скрытно от пользователя.
MDI Conformist
MDI Children
| --------------------------------------------------------| | X| Child
#2 |
|| Child 3
| | ----- ^ || | | X | CanClose блоки минимизации и ---- |-----| -----
максимизации || ^ |
дочернее окно MDI --
| <---- пиктограмма
Child
| ^
окно клиента MDI -- |
окно-рамка MDI --
Рис. 14.1 Компоненты приложения MDI.
B.Pascal 7 & Objects/OW - 252 -
Меню дочернего окна
Строка меню окна-рамки содержит меню, управляющее дочерними окнами MDI.
Меню дочернего окна содержит такие элементы как Tile (Вывод без перекрытия),
Cascade (Вывод с перекрытием), Arrange (Упорядочить) и Close All (Закрыть
все). Имя каждого открытого окна MDI автоматически добавляется к концу
этого меню с выбором текущего окна.
Дочерние окна MDI
Каждое дочернее окно MDI имеет некоторые характеристики перекрывающего
окна. Его можно максимизировать до полного размера окна клиента MDI или
минимизировать в пиктограмму, которая помещается к нижней границе окна-рамки.
Дочернее окно MDI никогда не выходит за границы его окна-рамки (обрамляющего
окна). Дочернее окно MDI не может иметь меню, поэтому все его функции
реализуются меню окна-рамки. Заголовок каждого дочернего окна MDI часто
представляет собой имя открытого файла, связанного с этим окном, хотя
его поведение заранее неизвестно и определяется программой. Можно рассматривать
приложение MDI как мини-сеанс Windows, когда несколько приложений представлены
окнами или пиктограммами.
Окна MDI в ObjectWindows
ObjectWindows определяет типы для представления рамок MDI и клиентов MDI.
Это соответственно TMDIWindow и TMDIClient. TMDIWindow является производным
от TWindow, но TMDIClient на самом деле представляет собой управляющий
элемент и является производным от TControl. В приложении MDI ObjectWindows,
окно-рамки владеет своим окном клиента MDI и хранит его в поле ClientWnd.
Окно-рамка также содержит каждое из дочерних окон MDI в связанном списке
ChildList. Дочерние окна MDI являются экземплярами типа объекта, производного
от написанного вами TWindow.
Методы TMDIWindow занимаются в основном конструированием и управлением
дочерними окнами MDI, окном клиента MDI и обработкой выбора в меню. Главная
работа TMDIClient происходит скрытно от пользователя и состоит в управлении
дочерними окнами MDI. При разработке приложений MDI вы в общем случае
будете создавать новые производные типы для своих рамок и дочерних окон
соответственно от TMDIWindow и TWindow.
Построение приложения MDI
Построение приложения MDI в ObjectWindows представляет собой относительно
простую задачу:
* Построение основного окна MDI.
B.Pascal 7 & Objects/OW - 253 -
* Установка меню дочернего окна.
* Предоставление основному окну возможности создания дочерних MDI.
Окно MDI обрабатывает для вас все специфические функции, а ваши функции,
специфические для приложения, могут перейти в дочерние окна.
Построение рамки MDI
Окно-рамка MDI всегда является основным окном приложения, поэтому оно
конструируется в методе InitMainWindow его объекта приложения. Однако,
существует два аспекта рамки MDI, которые отличают его от других основных
окон:
* Рамка MDI всегда является основным окном, поэтому оно никогда не имеет
порождающего окна. Таким образом, TMDIWindow.Init нет необходимости воспринимать
в качестве параметра указатель порождающего окна.
* Окно-рамка MDI всегда должно иметь меню, так что вторым
параметром Init является описатель меню. Для основных
окон, отличных от MDI и производных от TWindows, вы определяете Init для
установки Attr.Menu в допустимый описатель меню. TMDIWindow.Init устанавливает
для вас AttrMenu.
Типичный метод InitMainWindow для приложения MDI может выглядеть следующим
образом:
procedure TMDIApplication.InitMainWindow;
begin
MainWindow := New(PMyFrame, Init('Заголовок рамки',
LoadMenu(HInstance, 'MenuName'));
Если предположить, что TMyFrame - это потомок TMDIWindow, при этом будет
создаваться окно-рамка MDI с заголовком "Заголовок рамки" и
строкой меню, заданной ресурсом "MenuName".
Создание меню дочерних окон
Меню окна-рамки должно включать в себя меню дочернего окна в стиле MDI.
Открытие дочернего окна MDI добавляет его заголовок к меню дочернего окна,
а закрытие дочернего окна удаляет его из списка. Это позволяет пользователю
активизировать любое дочернее окно, даже если оно не является видимым.
Окно-рамка должно знать, каким элементом меню верхнего уровня является
меню его дочернего окна. Объект TMDIWindow хранит целое значение позиции
в поле объекта ChildMenuPos. TMDIWindow.Init
B.Pascal 7 & Objects/OW - 254 -
первоначально устанавливает ChildMenuPos в ноль, указывая крайний левый
элемент меню верхнего уровня. Однако, для установки позиции ChildMenuPos
вы можете переопределить Init для своего производного от TMDIWindow типа:
constructor TMyMDIWindow.Init(ATitle: PChar; AMenu: HMenu); begin
inherited Init(ATitle, AMenu);
ChildMenuPos := 1; end;
TMDIWindow.Init также вызывает InitClientWindow для конструирования объекта
TMDIClient, который будет служит его окном клиента MDI. TMDIWindow.SetupWindow
создает окно клиента MDI.
Создание дочерних окон MDI
TMDIWindow определяет автоматический метод реакции
CreateChild, который вызывается при выборе из меню варианта, результатом
которого будет команда с идентификатором Create_Child. Обычно этот вариант
меню называется New или Create. Как это определено в TMDIWindow, CreateChild
конструирует и создает дочернее окно MDI типа TWindow вызовом TMDIWindow.InitChild.
Для задания корректного типа дочернего окна (производного от TWindow),
переопределим InitChild для вашего типа окна-рамки MDI:
function MyMDIWindow.InitChild: PWindowsObject;
begin
InitChild:=New(PMyChild, Init(@Self,
'Новое дочернее окно'));
end;
Автоматические дочерние окна
Может потребоваться, чтобы ваша окно-рамка воспроизводило только одно
дочернее окно MDI при своем первом появлении. Для этого первого дочернего
окна вы можете явно задать его размер. В отличие от других дочерних окон,
дочерние окна MDI должны быть сконструированы и созданы в методе SetupWindow
окна-рамки MDI, а не в Init. Вы также должны явно создать экранный элемент
дочернего окна с помощью вызова MakeWindow:
procedure MyMDIWindow.SetupWindow;
var
ARect: TRect;
NewChild: PMyChild; begin
TMDIWindow.SetupWindow;
NewChild:=PMyChild(InitChild);
GetClientRect(HWindow, ARect); with NewChild^.Attr, ARect do
B.Pascal 7 & Objects/OW - 255 -
begin
W:=(right*4) div 5;
H:=(bottom*3) div 5;
Title:='Child #1'; end;
Application^.MakeWindow(NewChild); end;
В некоторых приложениях вам может потребоваться создать дочернее окно
MDI в ответ на более чем один выбор в меню. Например, пункты меню New
и Open в редакторе файла могут приводить к возникновению нового дочернего
окна с заголовком в виде имени файла. В этом случае определите для построения
дочернего окна методы автоматической реакции. ObjectWindows определяет
команды cm_MDIFileOpen и cm_MDIFileNew, что облегчает дифференциацию от
стандартных cm_FileOpen и cm_FileNew.
Управление дочерним окном MDI
Тип окна MDI в ObjectWindows содержит методы манипулирования дочерними
окнами MDI приложения MDI. Хотя большая часть скрытой работы делается
в TMDIClient, доступ к данным и функциям происходит через метод TMDIWindow.
TMDIWindow определяет методы реакции на сообщения Windows, которые автоматически
реагируют на выбор команды стандартного меню MDI: Title, Cascade, Arrange
Icon и Close All. Эти методы ожидают основанных на командах сообщений
с заранее определенными константами идентификаторов меню. Обязательно
используйте эти идентификаторы при построении ресурса меню дочернего окна:
Стандартные методы, команды и действия MDI Таблица 14.1
Действие Константа ID меню Метод TMDIWindow
TileCascadeArrange IconsClose All cmcmcmcm TileChildrenCascadeChildrenArrangeChildIconsCloseChildren
CMCMCMCM TileChildrenCascadeChildrenArrangeChildIconsCloseChildren
Методы реакции TMDIWindows, подобные CMTileChildren, вызывают другие методы
TMDIWindows, такие как CMChildren. Эти методы вызывают методы TMDIClient
с тем же именем, например, TMDIClient^.TileChildren. Для переопределения
такого автоматического поведения нужно переопределить TMDIWindow.TileChildren
или другой метод TMDIWindow. Для дочерних окон MDI не подходит реагирование
на основанные на командах сообщения, генерируемые меню дочернего окна.
B.Pascal 7 & Objects/OW - 256 -
Настройка активизации дочернего окна
Пользователь приложения MDI может свободно активизировать любое открытое
или минимизировать дочернее окно MDI. Однако, вам может потребоваться
предпринять некоторые действия, когда пользователь дезактивирует одно
дочернее окно активизацией другого. Например, меню окна-рамки может отражать
текущее состояние активного дочернего окна, выделяя его цветом. Каждый
раз, когда дочернее окно становится активным или неактивным, оно получает
сообщение Windows wm_MDIActivate. Определив метод реакции на это с общение
для дочернего окна, вы можете отслеживать, какое дочернее окно активно
и соответственно реагировать.
Обработка сообщений в приложении MDI
Как и для обычных порождающих и дочерних окон, основанные на командах
и дочерних идентификаторах сообщения Windows сначала поступают в дочерние
окна для их восприятия и обработки. Затем сообщения поступают в порождающее
окно. Однако, в случае приложения MDI сообщения поступают к текущему дочернему
окну MDI, затем к окну клиента MDI, и, наконец, к окну-рамке MDI (которое
является порождающим окном для всех дочерних окон MDI). Следовательно,
меню окна-рамки можно использовать для управления работой в текущем активном
дочернем окне MDI. Затем шанс отреагировать получают окно клиента и окно-рамка.
Пример приложения MDI
Программа MDITest создает приложение MDI, показанное на Рис. 14.1. Полный
текст файла MDITEST.PAS содержится на ваших дистрибутивных дискетах.
B.Pascal 7 & Objects/OW - 257 -
Глава 15. Объекты печати
Один из наиболее трудных аспектов программирования в Windows
- это вывод на принтер. ObjectWindows путем использования ряда модулей
и инкапсуляции поведения устройства печати и самой распечатки делает печать
более простой.
Данная глава описывает основы процесса печати, после чего описываются
следующие задачи:
* Построение объекта принтера.
* Создание распечатки.
- Печать документа.
- Печать содержимого окна.
* Передача распечатки на принтер.
* Выбор другого принтера.
* Настройка конфигурации принтера.
Почему печать представляет трудности?
С одной стороны печать в Windows достаточно проста. Вы можете использовать
для генерации распечатки те же функции GDI, что используются для вывода
образов на экран. Для вывода текста используется функция TextOut, а для
вычерчивания прямоугольника - Rectangle.
С другой стороны, процесс осложняется, так как Windows требует непосредственного
"общения" с драйверами принтера через вызовы Escape или получения
адреса DeviceMode или ExtDeviceMode. Это еще более осложняется требованием
Windows, чтобы приложение считывало имя драйвера устройства из файла WIN.INI.
Кроме того, устройства печати обладают большими возможностями проверки
допустимости и возможностями разрешения, чем видеоустройства.
ObjectWindows не может преодолеть все препятствия на этом пути, но делает
процесс печати более простым и легким для понимания.
Печать в ObjectWindows
Модуль ObjectWindows OPrinter предусматривает для упрощения печати два
объекта - TPrinter и TPrintout. TPrinter инкапсулирует доступ к устройствам
печати. Он предоставляет возможность конфигурирования принтера, выводя
диалог, в котором пользователь может
B.Pascal 7 & Objects/OW - 258 -
выбрать нужный принтер, а также установить параметры печати, такие как
графическое разрешение или ориентация (горизонтальная и вертикальная)
печати.
TPtintout инкапсулирует задачу печати документа. К принтеру этот объект
имеет такое же отношение, как TWindow - к экрану. Рисование на экране
выполняется методом Paint объекта TWindow, а печать на принтере - методом
PrintPage объекта TPrintout. Чтобы напечатать что-то на принтере, приложение
должно передать методу Print объекта TPrinter экземпляр TPrintout.
Построение объекта принтера
В большинстве случаев приложению требуется в каждый момент времени доступ
только к одному принтеру. Простейшим способом реализации этого является
задание в объекте основного окна поля с именем Printer (типа PPrinter),
которые другие объекты в программе вызывают для целей печати. Чтобы сделать
принтер доступным, поле Printer должно указывать на экземпляр TPrinter.
В большинстве приложений это просто. Основное окно приложения инициализирует
объект принтера, который использует заданный по умолчанию принтер, указанный
в WIN.INI:
constructor TSomeWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
Inherited Init(AParent, ATitle);
.
.
.
Printer := New(PPrinter, Init); end;
В некоторых случаях может возникать необходимость использовать в приложении
различные принтеры одновременно из различных окон. В этом случае постройте
объект принтера в конструкторах каждого такого окна, затем смените устройство
принтера на один или более таких принтеров. Если программа использует
различные принтеры, но не одновременно, то возможно лучше использовать
один и тот же объект принтера и при необходимости выбирать различные принтеры.
Хотя вы можете сомневаться насчет переопределения конструктора TPrinter
для использования принтера, отличного от заданного в системе по умолчанию,
рекомендуемой процедурой является использование конструктора по умолчанию,
а затем смена связанного с объектом устройства. См. раздел "Выбор
другого принтера".
B.Pascal 7 & Objects/OW - 259 -
Создание распечатки
Единственной "хитрой" частью процесса печати в ObjectWindows
являются создание распечатки. Этот процесс аналогичен написанию метода
Paint для объекта окна: вы используете графические функции Windows для
генерации в контексте устройства нужного графического образа. Контекст
устройства оконного объекта обрабатывает ваши взаимодействия с устройством
экрана; аналогичным образом контекст устройства распечатки изолирует вас
от устройства печати.
Примечание: Графические функции Windows поясняются в Главе 17.
Чтобы создать объект распечатки, постройте новый тип, производный от TPtintout,
который переопределяет PrintPage. В очень простых случаях это все, что
требуется сделать. Если документ имеет размер более одной страницы, то
вам нужно также переопределить HasNextPage для возврата True. Текущий
номер страницы передается в качестве параметра PrintPage.
Объект распечатки имеет поля, содержащие размер страницы и контекст устройства,
который уже инициализирован для принтера. Объект принтера устанавливает
значения, вызывая метод объекта распечатки SetPrintParams. Используйте
контекст устройства объекта распечатки в любом вызове графических функций
Windows.
Модуль OPrinter включает в себя два специализированных объекта распечатки,
которые показывают диапазон сложности распечаток. Объект TWindowPrintout,
печатающий содержимое окна, очень прост. TEditPrintout, который печатает
содержимое управляющего элемента редактирования, очень сложен, так как
имеет множество возможностей.
Печать документа
Windows рассматривает распечатку как последовательность страниц, поэтому
задачей вашего объекта распечатки является превращение документа в последовательность
станичных образов для печати Windows. Аналогично тому как оконные объекты
используются для отображения образов на экране дисплея, объекты распечатки
используются для печати образов на принтере.
ObjectWindows предусматривает абстрактный объект распечатки TPrintout,
из которого вы можете создать производные объекты распечатки. Вам нужно
переопределить в TPrintout только несколько методов.
Ваши объекты распечатки должны делать следующее:
* Устанавливать параметры принтера.
B.Pascal 7 & Objects/OW - 260 -
* Подсчитывать страницы.
* Отображать каждую страницу в контексте устройства.
* Указывать, есть ли еще страницы.
Остальная часть этой главы ссылается на пример программы PrnTest, записанной
на ваших дистрибутивных дискетах под именем PRNTEST.PAS. PrnTest считывает
текстовый файл в набор строк, а затем по команде печатает документ. Объект
PrnTest описывается следующим образом:
type
PTextPrint = ^TTextPrint;
TTextPrint = object(TPrintout);
TextHeight, LinesPerPage, FirstOnPage, LastOnPage:
Integer;
TheLines; PCollection; constructor Init(ATitle: PChar;
TheText: PPCharCollection); function GetDialogInfo(var Pages: Intger):
Boolean;
virtual;
function HasNextPage(Page: Word): Boolean; virtual;
procedure SetPrintParams(ADC: HDC; ASize: TPoint);
virtual;
procedure PrintPage(Page: Word; var Rect: TRect;
Flags: Word); virtual; end;
Задание параметров печати
Перед запросом распечатки документа объект принтера предоставляет вашему
документу возможность разбивки на страницы. Для этого вызываются два метода
объекта распечатки - SetPrintParams и GetDialogInfo.
Функция SetPrintParams предназначена для инициализации структур данных,
которые могут потребоваться для получения эффективной распечатки отдельных
страниц. SetPrintParams - это первая возможность вашей распечатки обратиться
к контексту устройства и задать для принтера размер страницы. Приводимый
ниже фрагмент программы показывает пример переопределенного метода SetPrintParams.
Если вы переопределяете SetPrintParams, убедитесь в вызове наследуемого
метода, устанавливающего значения полей распечатки объекта.
Подсчет страниц
После вызова SetPrintParams объект печати вызывает булевскую
B.Pascal 7 & Objects/OW - 261 -
функцию GetDialogInfo. GetDialogInfo задает информацию, необходимую для
вывода на экран диалогового блока, позволяющего пользователю выбрать перед
печатью диапазон страниц. В подсчете страниц в GetDialogInfo и индикации
вывода диалогового блока имеются два аспекта.
Функция GetDialogInfo воспринимает единственный параметр-переменную Pages,
которую она должна устанавливать в число страниц в документе или в 0,
если она не может подсчитать страницы. Возвращаемое значение равно True,
если вы хотите вывести диалоговый блок, и False для подавления его вывода.
По умолчанию GetDialogInfo устанавливает Pages в 0 и возвращает True,
что означает, что она не знает, сколько может получиться страниц, и что
перед печатью будет выводиться диалоговый блок. GetDialogInfo обычно переопределяется
для установки Pages в число страниц в документе и возвращает True.
Например, PrnTest подсчитывает, сколько строк текста выбранного шрифта
может поместиться в области печати в SetPrintParams, а затем использует
это число для подсчета количества страниц, которые нужно напечатать в
GetDialogInfo:
procedure TTextPrint.SetPrintParams(ADC: HDC;
ASize: TPoint); var TextMetrics: TTextMetric;
begin
inherited SetPrintParams(ADC, ASize); установить DC и
размер Size
GetTextMetrics(DC, TextMetrics); получить информацию о размере текста
TextHeigh := TextMetrics.tmHeight; вычислить высоту строки
LinesPerPages := Size.Y div TextHeight; и число строк на странице
end;
function TTextPtint.GetDialogInfo(var Pages: Integer):
Boolean); begin
Pages:= TheLines^.Count div LinesPerPage + 1;
GetDialogInfo := True вывод перед печатью диалогового блоки
end;
Часть №3
|