|
Содержание
Введение.......................................................25
Что такое ObjectWindows?.......................................25
Для чего предназначена ObjectWindows?..........................26
Что нужно знать................................................26
Как работать с данным руководством.............................27
О чем рассказывается в данном руководстве......................27
Часть 1. Изучение ObjectWindows................................28
Глава 1. Знакомство с Windows..................................28
Шаг 1: Создание базового приложения............................28
Требования к приложению........................................29
Определение типа приложения....................................30
Инициализация основного окна...................................30
Объект основного окна..........................................32
Что такое объект окна?.........................................32 Описатели......................................................33
Порождающие и дочерние окна....................................33
Создание нового типа окна......................................33
Реакция на сообщения...........................................34
Завершение прикладной программы................................36
Переопределение CanClose.......................................37
Дальнейшее изменение закрытия..................................38
Глава 2. Заполнение окна.......................................41
Шаг 2: Отображение текста в окне...............................41
Вывод в контексте дисплея......................................41
Что такое контекст дисплея?....................................42
Получение контекста дисплея....................................42
Использование контекста дисплея................................43
Освобождение контекста дисплея.................................43
Координаты Windows.............................................44
Параметры сообщений............................................44
Очистка окна...................................................45
Шаг 3: Изображение линий в окне................................47
Буксировка линии...............................................48
Сообщения wm_MouseMove.........................................48
Реакция на сообщения буксировки................................49
Изображение точек и линий......................................50
Перехват "мыши"................................................50
Изменение размера пера.........................................51
Отслеживание размера пера......................................51
Получение пера нового размера..................................52
Глава 3. Меню и диалоговые ресурсы.............................56
Шаг 4: Добавление строки меню..................................56
Ресурсы меню...................................................57
Загрузка ресурса меню..........................................60
Перехват сообщений меню........................................61
Определение методов реакции на команду.........................62
Связывание клавиш с командами..................................62
Реакция на команды меню........................................63
Добавление диалогового блока...................................64
Добавление поля объекта........................................66
Шаг 5: Добавление диалогового блока............................68
Создание ресурсов диалогового блока............................69
Идентификаторы управляющих элементов...........................69
B.Pascal 7 & Objects/OW - 2 -
Построение объекта диалогового блока...........................70
Выполнение диалогового блока...................................70
Режимные и безрежимные диалоговые блоки........................72
Глава 4. Работа с диалоговым блоком............................73
Шаг 6: Изменение атрибутов пера................................73
Создание объекта пера..........................................74
Создание сложного диалогового блока............................76
Управляющие объекты............................................77
Использование интерфейсных объектов............................78
Конструктор InitResource.......................................79
Создание буфера передачи.......................................79
Передача данных................................................81
Чтение возвращаемых значений...................................81
Вызов диалогового блока пера...................................82
Глава 5. Повторное отображение графики.........................83
Шаг 7: Вывод на экран графики..................................83
Изображение и рисование........................................83
Сохранение графики в объектах..................................84
Добавление поля объекта........................................85
Определение объекта линии......................................85
Изменение методов работы с "мышью".............................87
Вывод сохраненной графики......................................88
Шаг 8: Сохранение рисунка в файле..............................89
Отслеживание состояния.........................................89
Сохранение и загрузка файлов...................................91
Шаг 9: Печать графического образа..............................94
Построение объекта принтера....................................94
Создание объекта распечатки....................................95
Запись в контекст устройства...................................95
Создание распечатки окна.......................................95
Вывод распечатки...............................................96
Выбор другого принтера.........................................96
Глава 6. Вывод всплывающего окна...............................98
Шаг 10: Добавление всплывающего окна...........................98
Добавление к окну дочернего окна...............................99
Построение окна палитры.......................................100
Назначение порождающего окна..................................100
Создание элементов экрана.....................................102
Вывод и сокрытие палитры......................................103
Шаг 11: добавление специализированных управляющих элементов...103
Добавление к палитре командных кнопок.........................104
Объекты управляющих элементов как поля........................105
Работа с управляющими элементами..............................105
Сокрытие вместо закрытия......................................106
Разрешение специализированных управляющих элементов...........107
Создание для командных кнопок графических изображений.........109
Нумерация ресурсов графических изображений....................109
Шаг 12: Создание специализированного управляющего элемента окна.........................................................111
Динамическое изменение размеров палитры.......................111
Реакция на события управляющих элементов......................112
Имена методов реакции на сообщения управляющих элементов......112
Добавление "кнопок" палитры...................................114
B.Pascal 7 & Objects/OW - 3 -
Определение объекта палитры...................................114
Создание и уничтожение палитры................................116
Размещение в порождающем окне.................................117
Добавление и удаление перьев..................................118
Отображение содержимого палитры...............................120
Выбор перьев с помощью "мыши".................................121
Что дальше?...................................................121
Многодокументальный интерфейс.................................122
Сглаживание линий.............................................122
Отмена........................................................122
Поведение палитры.............................................123
Прокрутка.....................................................123
Часть 2. Использование ObjectWindows..........................124
Глава 7. Иерархия ObjectWindows...............................124
Соглашения Windows............................................124
Имена объектов................................................124
Имена методов.................................................124
Обзор объектов................................................125
Иерархия объектов.............................................125
Файлы ObjectWindows...........................................130
Файлы ресурсов................................................131
Файлы Windows 3.1.............................................131
Взаимодействие с Windows......................................132
Функции API Windows...........................................132
Вызов в ObjectWindows функций API.............................132
Доступ к функциям API.........................................133
Константы Windows.............................................133
Записи данных Windows.........................................133
Комбинирование констант стилей................................134
Типы функций Windows..........................................134
Функции системного вызова.....................................135
Глава 8. Объекты приложения...................................136
Минимальные требования........................................136
Поиск объекта приложения......................................136
Минимальное приложение........................................137
Методы Init, Run и Done.......................................137
Конструктор Init..............................................137
Метод Run.....................................................138
Деструктор Done...............................................138
Инициализация приложения......................................138
Инициализация основного окна..................................139
Специальный вывод основного окна..............................140
Инициализация первого экземпляра..............................140
Инициализация каждого экземпляра..............................142
Выполнение приложений.........................................143
Закрытие приложений...........................................143
Модификация поведения при закрытии............................143
Глава 9. Интерфейсные объекты.................................145
Для чего нужны интерфейсные объекты?..........................145
Что делают интерфейсные объекты?..............................145
Общий интерфейсный объект.....................................146
Создание интерфейсных объектов................................146
Допустимость описателя окна...................................147
B.Pascal 7 & Objects/OW - 4 -
Видимость на экране...........................................148
Уничтожение интерфейсных объектов.............................148
Связь порождающего и дочернего объектов.......................149
Список дочерних окон..........................................149
Построение дочерних окон......................................150
Создание дочерних элементов экрана............................150
Уничтожение дочерних окон.....................................150
Запрещение автоматического создания...........................151
Итерация дочерних окон........................................151
Поиск определенного дочернего окна............................151
Глава 10. Объекты окон........................................153
Что такое объекты окон?.......................................153
Окна, которые не являются окнами..............................153
Где найти объекты окон........................................154
Инициализация объектов окон...................................154
Установка атрибутов создания..................................155
Используемые по умолчанию атрибуты окна.......................156
Переопределение используемых по умолчанию атрибутов...........157
Атрибуты порожденного окна....................................157
Создание элементов окна.......................................158
Задание атрибутов регистрации.................................159
Классы окон...................................................160
Используемые по умолчанию атрибуты регистрации................162
Регистрация нового класса.....................................162
Изменение имени класса........................................163
Определение новых атрибутов регистрации.......................163
Использование специализированных окон.........................165
Использование окон редактирования.............................165
Использование файловых окон...................................167
Прокрутка содержимого окон....................................168
Что такое объект прокрутки?...................................169
Задание для окна объекта прокрутки............................171
Пример прокрутки..............................................171
Запрещение автоматической прокрутки...........................173
Отслеживание полос прокрутки..................................173
Модификация единиц прокрутки и диапазона......................174
Изменение позиции прокрутки...................................174
Установка размеров страницы...................................175
Оптимизация методов Paint для прокрутки.......................175
Глава 11. Объекты диалоговых блоков...........................177
Использование объектов диалоговых блоков......................177
Построение объекта............................................178
Вызов конструктора............................................178
Выполнение диалоговых блоков..................................178
Режимные и безрежимные диалоговые блоки.......................179
Выполнения режимных диалоговых блоков.........................179
Выполнение безрежимных диалоговых блоков......................180
Работа с безрежимными диалоговыми блоками.....................180
Завершение диалогов...........................................181
Работа с управляющими элементами..............................182
Взаимодействие с управляющим элементом........................182
Реакция на сообщения управляющих элементов....................183
Пример связи..................................................183
B.Pascal 7 & Objects/OW - 5 -
Ассоциирование объектов управляющих элементов.................184
Использование диалоговых окон.................................185
Использование предопределенных диалоговых окон................186
Использование диалоговых блоков ввода.........................186
Файловые диалоговые блоки.....................................188
Инициализация файлового диалогового блока.....................189
Выполнение файловых диалоговых блоков.........................189
Глава 12. Объекты управляющих элементов.......................191
Где можно использовать объекты управляющих элементов?.........191
Что такое объекты управляющих элементов?......................194
Построение и уничтожение объектов управляющих элементов.......194
Построение объекта управляющего элемента......................195
Вызов конструкторов объектов управляющих элементов............195
Присваивание полям объекта....................................195
Изменение атрибутов объекта управляющего элемента.............197
Инициализация управляющего элемента...........................197
Сохранение управляющих элементов..............................198
Уничтожение управляющих элементов.............................198
Связь с управляющими элементами...............................198
Работа с управляющими элементами окна.........................198
Реакция на управляющие элементы...............................199
Действие, аналогичное диалоговому блоку.......................199
Использование конкретных управляющих элементов................199
Использование блока списка....................................199
Построение объектов блока списка..............................200
Модификация блоков списка.....................................200
Запрос в блоках списка........................................201
Реакция на блок списка........................................201
Пример программы: LBoxTest....................................202
Использование статических управляющих элементов...............203
Построение статических управляющих элементов..................204
Пример программы StatTest.....................................205
Использование командных кнопок................................206
Построение командных кнопок...................................207
Реакция на командные кнопки...................................207
Использование блоков выбора...................................208
Построение кнопок с зависимой и независимой фиксацией.........208
Модификация блоков выбора.....................................210
Опрос блоков выбора...........................................210
Использование групповых блоков................................210
Построение групповых блоков...................................211
Группирование управляющих элементов...........................211
Реакция на групповые блоки....................................213
Пример программы: BtnTest.....................................213
Использование полос прокрутки.................................214
Построение полос прокрутки....................................214
Управление диапазоном полосы прокрутки........................215
Управление параметрами полосы прокрутки.......................216
Опрос полосы прокрутки........................................216
Модификация полос прокрутки...................................216
Реакция на полосы прокрутки...................................217
Пример программы: SBarTest....................................218
Использование управляющих элементов редактирования............218
B.Pascal 7 & Objects/OW - 6 -
Построение управляющих элементов редактирования...............220
Использование буфера вырезанного изображения и меню Edit......220
Опрос управляющих элементов редактирования....................222
Модификация управляющих элементов редактирования..............223
Пример программы: EditTest....................................224
Использование комбинированных блоков..........................224
Три типа комбинированных блоков...............................225
Выбор типа комбинированного блока.............................226
Построение комбинированных блоков.............................226
Модификация комбинированных блоков............................227
Пример программы: CBoxTest....................................227
Установка значений управляющих элементов......................227
Для чего используется буфер передачи?.........................228
Определение буфера передачи...................................228
Определение окна..............................................231
Использование буфера передачи с диалоговым блоком.............231
Использование буфера передачи с окном.........................233
Передача данных...............................................233
Передача данных в окно........................................233
Передача данных из диалогового окна...........................233
Передача данных из окна.......................................234
Поддержка передачи для специализированных управляющих элементов....................................................234
Пример программы: TranTest....................................234
Использование специализированных управляющих элементов........236
Специализированные управляющие элементы Borland для Windows...236
Использование стандартных BWCC................................237
Средства BWCC.................................................237
Расширение BWCC...............................................238
Создание ваших собственных специализированных управляющих элементов....................................................240
Глава 13. Проверка допустимости данных........................241
Три вида проверки допустимости данных.........................241
Фильтрация ввода..............................................242
Проверка допустимости каждого поля............................242
Проверка допустимости полных экранов..........................242
Использование механизма проверки допустимости данных..........243
Построение объектов проверки допустимости.....................244
Добавление к управляющим элементам............................244
Как работает проверка допустимости............................244
Методы объекта проверки допустимости..........................245
Проверка допустимости данных..................................245
Проверка полной строки........................................246
Проверка допустимости нажатий клавиш..........................246
Сообщение о недопустимых данных...............................246
Стандартные средства проверки допустимости....................248
Абстрактный объект проверки допустимости......................248
Фильтрация....................................................248
Проверка диапазона............................................249
Проверка допустимости с просмотром............................249
Просмотр строк................................................249
Проверка допустимости по шаблону..............................250
Глава 14. Объекты MDI.........................................251
B.Pascal 7 & Objects/OW - 7 -
Меню дочернего окна...........................................252
Дочерние окна MDI.............................................252
Окна MDI в ObjectWindows......................................252
Построение приложения MDI.....................................252
Построение рамки MDI..........................................253
Создание меню дочерних окон...................................253
Создание дочерних окон MDI....................................254
Автоматические дочерние окна..................................254
Управление дочерним окном MDI.................................255
Настройка активизации дочернего окна..........................256
Обработка сообщений в приложении MDI..........................256
Пример приложения MDI.........................................256
Глава 15. Объекты печати......................................257
Почему печать представляет трудности?.........................257
Печать в ObjectWindows........................................257
Построение объекта принтера...................................258
Создание распечатки...........................................259
Печать документа..............................................259
Задание параметров печати.....................................260
Подсчет страниц...............................................260
Печать каждой страницы........................................261
Указание оставшихся страниц...................................263
Другие соглашения по печати...................................263
Печать содержимое окна........................................264
Вывод распечатки на принтер...................................265
Выбор другого принтера........................................265
Выбор принтера пользователем..................................266
Назначение конкретного принтера...............................266
Часть 3. Продвинутое программирование с использование
ObjectWindows................................................267
Глава 16. Сообщения Windows...................................267
Что такое сообщение?..........................................267
Именующие сообщения...........................................268
Откуда поступают сообщения....................................268
Обычная диспетчеризация сообщений.............................269
Способ, предлагаемый ObjectWindows............................269
Динамические виртуальные методы...............................270
Написание методов реакции на сообщение........................270
Что такое сообщение?..........................................271
Поля параметров...............................................271
Поле Result...................................................272
Объектно-ориентированная обработка сообщения..................272
Отмена поведения по умолчанию.................................272
Замена поведения по умолчанию.................................273
Дополнение поведения по умолчанию.............................273
Вызов наследуемых методов.....................................273
Вызов процедур, используемых по умолчанию.....................274
Командные, уведомляющие и управляющие идентификаторы..........275
Командные сообщения...........................................275
Уведомляющие сообщения........................................276
Уведомления управляющих элементов.............................276
Уведомление порождающего объекта..............................277
Уведомления управляющих элементов и порождающих объектов......278
B.Pascal 7 & Objects/OW - 8 -
Определение ваших собственных сообщений.......................278
Передача сообщений............................................279
Передача и отправление сообщений..............................279
Передача сообщения............................................280
Отправление сообщения.........................................280
Передача сообщения управляющему элементу......................280
Диапазоны сообщений...........................................282
Глава 17. Интерфейс с графическими устройствами...............284
Запись на устройство вывода...................................284
Чем отличаются контексты устройства?..........................285
Управление контекстом дисплея.................................285
Работа с контекстом дисплея...................................286
Что содержится в контексте устройства?........................286
Побитовая графика.............................................287
Изобразительные средства......................................287
Цвет..........................................................289
Режимы отображения............................................289
Обрезание областей............................................289
Инструментальные средства рисования...........................290
Основные инструментальные средства............................290
Логические инструментальные средства..........................291
Логические перья..............................................291
Логические кисти..............................................293
Логические шрифты.............................................294
Использование изобразительных инструментальных средств........298
Отображение графики в окнах...................................300
Изображение окон..............................................300
Стратегия графики.............................................301
Рисование в окнах.............................................301
Графические функции GDI.......................................302
Функции изображения текста....................................302
Функции рисования линий.......................................303
Изображение фигур.............................................305
Использование палитр..........................................307
Установка палитры.............................................307
Рисование с палитрами.........................................308
Запрос палитры................................................308
Модификация палитры...........................................309
Реакция на изменения палитры..................................309
Глава 18. Более подробно о ресурсах...........................311
Создание ресурсов.............................................311
Добавление ресурсов к выполняемой программе...................312
Загрузка ресурсов в приложение................................312
Загрузка меню.................................................312
Загрузка оперативных клавиш...................................313
Загрузка блоков диалога.......................................314
Загрузка курсоров и пиктограмм................................315
Загрузка строковых ресурсов...................................315
Загрузка графических изображений..............................317
Использование побитовых отображений для создания кистей.......319
Отображение графических изображений в меню....................320
Глава 19. Наборы..............................................322
Объекты наборов...............................................322
B.Pascal 7 & Objects/OW - 9 -
Динамическая установка размеров наборов.......................322
Полиморфизм наборов...........................................323
Проверка типа и наборы........................................323
Объединение в набор элементов, не являющихся объектами........324
Создание набора...............................................324
Методы итератора..............................................326
Итератор ForEach..............................................326
Итераторы FirstThat и LastThat................................327
Отсортированные наборы........................................328
Наборы строк..................................................329
Пересмотренные итераторы......................................331
Полиморфические наборы........................................331
Наборы и управление памятью...................................335
Глава 20. Потоки..............................................336
Вопрос: объектный ввод-вывод..................................336
Ответ: потоки.................................................337
Полиморфизм потоков...........................................337
Потоки обрабатывают объекты...................................337
Смысл использования потоков...................................338
Чтение из потока и запись в поток.............................339
Закрытие потока...............................................340
Как сделать объекты потоковыми................................340
Методы загрузки и хранения....................................340
Регистрация потока............................................341
Номера идентификаторов объектов...............................342
Автоматические поля...........................................342
Регистрация на месте..........................................343
Регистрация стандартных объектов..............................343
Механизм потока...............................................343
Процесс Put...................................................343
Процесс Get...................................................344
Обработка указателей объектов со значением nil................344
Наборы в потоке: пример.......................................344
Добавление методов Store......................................345
Регистрация записей...........................................346
Регистрация...................................................347
Запись в поток................................................347
Как все хранится?.............................................348
Поля в потоке.................................................348
Родство экземпляров окон......................................349
Копирование потока............................................350
Потоки произвольного доступа..................................350
Необъектные элементы потоков..................................351
Разработка пользователем собственных потоков..................351
Обработка ошибок потока.......................................352
Часть 4. Справочник по ObjectWindows..........................353
Глава 21. Объектные типы ObjectWindows........................353
TSample модуль
TSample......................................................354 Поля..........................................................354
Методы........................................................354 Init..........................................................355
Zilch (иногда переопределяется)...............................355
B.Pascal 7 & Objects/OW - 10 -
Процедура Sample (модуль
Sample)......................................................355 Процедура
Abstract модуль
Objects......................................................355 Функция
AllocMultiSel модуль
ODialogs.....................................................355 Переменная
Application модуль
OWindows.....................................................356 Константы
bf_XXXX модуль
ODialogs.....................................................356 Стили кнопок
bs_XXXX модуль
WinTypes.....................................................357 Переменная
BWCCClassNames модуль
OWindows.....................................................358 Стили комбинированного
блока cbs_XXXX модуль
WinTypes.....................................................359 Константы
cm_XXXX модуль
OWindows.....................................................361 Константы
coXXXX модуль
Objects......................................................363 Стили класса
cs_XXXX модуль
WinTypes.....................................................364 Константа
cw_UseDefault модуль
WinTypes.....................................................365 Процедура
DoneMemory модуль
OMemory......................................................365 Константы
em_XXXX модуль
OWindows.....................................................365 Переменная
EmsCurHandle модуль
Objects......................................................365 Переменная
EmsCurPage модуль
Objects......................................................366 Стили управляющих
элементов es_XXXX модуль
WinTypes.....................................................366 Процедура
FreeMultiSel модуль
ODialogs.....................................................368 Константа
tsFileSpec модуль
OStdDlgs.....................................................368 Константы
id_XXXX модуль
OWindows.....................................................369 Процедура
InitMemory модуль
OMemory......................................................370 Стили блока
списка lbs_XXXX модуль
WinTypes.....................................................370 Функция
LongDiv модуль
OWindows.....................................................372 Функция
LongMul модуль
OWindows.....................................................373 Тип LongRec
модуль
Objects......................................................373 Функция
LoMemory модуль
OMemory......................................................373 Тип MakeIntResource
модуль
B.Pascal 7 & Objects/OW - 11 -
WinTypes.....................................................373 Переменная
MaxCollectionSize модуль
Objects......................................................374 Флаги блоков
mb_XXXX модуль
WinTypes.....................................................375 Функция
MemAlloc модуль
OMemory......................................................376 Функция
MemAllocSeg модуль
OMemory......................................................376 Константы
nf_XXXX модуль
OWindows.....................................................377 Константы
pf_XXX модуль
OPrinter.....................................................378 Тип PString
модуль
Objects......................................................379 Тип PtrRec
модуль
Objects......................................................379 Процедура
RegisterODialogs модуль
ODialogs.....................................................379 Процедура
RegisterOStdWnds модуль
OSrdWnds.....................................................379 Процедура
RegisterOWindows модуль
OWindows.....................................................380 Процедура
RegisterType модуль
Objects......................................................380 Процедура
RegisterValidate модуль
Validate.....................................................380 Процедура
RestoreMemory модуль
OMemory......................................................380 Переменная
SafetyPoolSize модуль
OMemory......................................................381 Стили полосы
прокрутки sbs_XXXX модуль
WinTypes.....................................................382 Константы
sd_XXXX модуль
OStdDlgs.....................................................384 Стили управляющего
элемента ss_XXXX модуль
WinTypes.....................................................385 Пpедопpеделенные
логические объекты модуль
WinTypes.....................................................386 Переменная
StreamError модуль
Objects......................................................387 Константы
stXXX модуль
Objects......................................................388 Константы
отображения окна sw_XXX модуль
WinTypes.....................................................389 TApplication
модуль
OWindows.....................................................391 Поля..........................................................391
Методы........................................................392 Init (иногда
переопределяется)................................392 Done (иногда переопределяется)................................392
CanClose (переопределяется редко).............................393 Error
(часто переопределяется)................................393
B.Pascal 7 & Objects/OW - 12 -
ExecDialog (никогда не переопределяется)......................393
ExecDialog (никогда не переопределяется)......................393
IdleAction....................................................394
InitApplication (иногда переопределяется).....................394
InitInstance (иногда переопределяется)........................394
InitMainWindow (всегда переопределяется)......................395
MakeWindow (никогда не переопределяется)......................395
MessageLooр (никогда не переопределяется).....................395 рrocessAccels
(иногда переопределяется).......................396 рrocessAppMsg (иногда
переопределяется).......................396 рrocessDlgMsg (иногда переопределяется).......................396
рrocessDMIAccels (иногда переопределяется)....................396 Функция
Run (переопределяется редко)..........................398 SetKBHandler (никогда
не переопределяется)....................398 TBufStream модуль
Objects......................................................399 Поля..........................................................399
Методы........................................................400 Init..........................................................400
Done (никогда не переопределяется)............................400 Flush
(никогда не переопределяется)...........................400 Getрos (никогда
не переопределяется)..........................401 GetSize (никогда не переопределяется).........................401
Read (никогда не переопределяется)............................401 Seek (никогда
не переопределяется)............................401 Truncate (никогда не
переопределяется)........................401 Write (никогда не переопределяется)...........................402
TButton модуль
ODialogs.....................................................403 Методы........................................................405
Init..........................................................405 InitResource..................................................405
GetClassName (никогда не переопределяется)....................405 Тип TByteArray
модуль
Objects......................................................405 TCheckBox
модуль
ODialogs.....................................................407 Поля..........................................................408
Методы........................................................409 Init (иногда
переопределяется)................................409 InitResource..................................................409
Load..........................................................409 BNClicked
(иногда переопределяется)...........................410 Check (переопределяется
редко)................................410 GetCheck (переопределяется редко).............................410
GetClassName..................................................410 SetCheck
(переопределяется редко).............................410 Store.........................................................411
Toggle (переопределяется редко)...............................411 Transfer
(иногда переопределяется)............................411 UnСheck (переопределяется
редко)..............................411 TCollection модуль
Objects......................................................413
B.Pascal 7 & Objects/OW - 13 -
Поля..........................................................413
Методы........................................................414
Init..........................................................414
Load..........................................................414
Done (часто переопределяется).................................414
At............................................................415
AtDelete......................................................415
AtFree........................................................415
AtInsert......................................................415
Atрut.........................................................416
Delete........................................................416
DeleteAll.....................................................416
Error (иногда переопределяется)...............................416
FirstThat.....................................................416
ForEach.......................................................417
Free..........................................................417
FreeAll.......................................................418
FreeItem (иногда переопределяется)............................418
GetItem (иногда переопределяется).............................418
IndexOf (никогда не переопределяется).........................418
Insert (никогда не переопределяется)..........................419
Insert (никогда не переопределяется)..........................419 рutItem
(иногда переопределяется).............................419 SetLimit (переопределяется
редко).............................420 Store.........................................................420
TComboBox модуль
ODialogs.....................................................421 Поля..........................................................423
Методы........................................................423 Init (иногда
переопределяется)................................423 InitResource..................................................423
Load..........................................................424 Clear.........................................................424
GetClassName (никогда не переопределяется)....................424 GetEditSel....................................................424
GetText.......................................................424 GetTextLen....................................................425
HideList......................................................425 SetEditSel....................................................425
SetText.......................................................425 SetuрWindow...................................................425
ShowList......................................................425 Store.........................................................426
Transfer......................................................426 TControl
модуль
ODialogs.....................................................427 Методы........................................................428
Init..........................................................428 InitResource..................................................429
GetGlassName (всегда переопределяется)........................429 Register
(никогда не переопределяется)........................429 WMрaint (переопределяется
редко)..............................429 TDialog модуль
B.Pascal 7 & Objects/OW - 14 -
ODialog......................................................430 Поля..........................................................431
IsModal.......................................................431 Методы........................................................432
Init (иногда переопеределяется)...............................432 Load..........................................................432
Done (иногда переопределяется)................................432 Cancel
(иногда переопределяется)..............................432 Create (никогда
не переопределяется)..........................433 DefWndрroc (никогда не
переопределяется)......................433 EndDlg (никогда не переопределяется)..........................433
Execute (никогда не переопределяется).........................433 GetItemHandle
(никогда не переопределяется)...................434 Ok (иногда переопределяется)..................................434
SendDlgItemMsg (никогда не переопределяется)..................434 Store.........................................................434
WMClose.......................................................434 WMInitDialog
(никогда не переопределяется)....................435 WMрostInvalid.................................................435
WMQueryEndSession.............................................435 Тип TDialogAttr
модуль
ODialogs.....................................................435 TDlgWindow
модуль
ODialogs.....................................................437 Методы........................................................438
Init..........................................................438 Create
(никогда не переопределяется)..........................439 GetWindowClass
(часто переопределяется).......................439 TDosStream модуль
Objects......................................................440 Поля..........................................................440
Методы........................................................440 Init..........................................................440
Done (никогда не переопределяется)............................441 Getрos
(никогда не переопределяется)..........................441 GetSize (никогда
не переопределяется).........................441 Read (никогда не переопределяется)............................441
Seek (никогда не переопределяется)............................441 Truncate
(никогда не переопределяется)........................442 Write (никогда
не переопределяется)...........................442 TEdit модуль
ODialogs.....................................................443 Поля..........................................................445
Методы........................................................445 Init..........................................................445
InitResource..................................................446 Load..........................................................446
Done..........................................................446 CanClose......................................................447
CanUndo (переопределяется редко)..............................447 ClearModify
(переопределяется редко)..........................447 CMEditClear (никогда
не переопределяется).....................447 CMEditCoрy (никогда не переопределяется)......................447
B.Pascal 7 & Objects/OW - 15 -
CMEditCut (никогда не переопределяется).......................448
CMEditDelete (никогда не переопределяется)....................448
CMEditрaste (никогда не переопределяется).....................448
CMEditUndo (никогда не переопределяется)......................448
Coрy (переопределяется редко).................................449
Cut (переопределяется редко)..................................449
DeleteLine (переопределяется редко)...........................449
DeleteSelection (переопределяется редко)......................449
DeleteSubText (переопределяется редко)........................449
GetClassName (никогда не переопределяется)....................449
GetLine (переопределяется редко)..............................450
GetLineFromрos (переопределяется редко).......................450
GetLineIndex (переопределяется редко).........................450
GetLineLength (переопределяется редко)........................450
GetNumLines (переопределяется редко)..........................451
GetSelection (переопределяется редко).........................451
GetSubText (переопределяется редко)...........................451
Insert (переопределяется редко)...............................451
IsModified (переопределяется редко)...........................452
IsValid.......................................................452 рaste
(переопределяется редко)................................452 Scroll (переопределяется
редко)...............................452 Search........................................................452
SetSelection (переопределяется редко).........................453 SetuрWindow...................................................453
SetValidator..................................................453 Store.........................................................453
Transfer (иногда переопределяется)............................454 Undo (переопределяется
редко).................................454 WMChar........................................................454
WMGetDlgCode..................................................454 WMKeyDown.....................................................455
WMKillFocus...................................................455 TEditPrintout
OPrinter.....................................................456 Поля..........................................................456
Методы........................................................457 Init..........................................................457
BeginDocument.................................................458 GetDialogInfo.................................................458
HasHextPage...................................................458 PrintPage.....................................................458
SetPrintParams................................................459 TEditWindow
модуль
OStdWnds.....................................................460 TEmsStream
модуль
Objects......................................................462 Поля..........................................................462
Методы........................................................463 Init..........................................................463
Done (никогда не переопределяется)............................463 GetPos
(никогда не переопределяется)..........................463 GetSize (никогда
не переопределяется).........................463
B.Pascal 7 & Objects/OW - 16 -
Read (никогда не переопределяется)............................463
Seek (никогда не переопределяется)............................464
Truncate (никогда не переопределяется)........................464
Write (никогда не переопределяется)...........................464 Константы
tf_XXXX модуль
OWindows.....................................................464 TFileDialog
модуль
OStdDlgs.....................................................466 Поля..........................................................467
Методы........................................................468 Init..........................................................468
CanClose......................................................468 SetupWindow...................................................468
HandleFName...................................................469 HandleFList...................................................469
HandleDList...................................................469 TFileWindow
OStdWnds.....................................................470 TFilterValidator
модуль
Validate.....................................................472 Поля..........................................................472
Методы........................................................472 Init..........................................................472
Load..........................................................472 Error.........................................................473
IsValid.......................................................473 IsValidInput..................................................473
Store.........................................................473 TGroupBox
ODialogs.....................................................474 Поля..........................................................475
Методы........................................................476 Init (иногда
переопределяется)................................476 InitResource..................................................476
Load..........................................................476 GetClassName
(иногда переопределяется)........................476 SelectionChanged (иногда
переопределяется)....................477 Store.........................................................477
TInputDialog модуль
OStdDlgs.....................................................478 Поля..........................................................479
Методы........................................................480 Init..........................................................480
CanClose......................................................480 SetupWindow...................................................480
Тип TItemList модуль
Objects......................................................480 TListBox
модуль
ODialogs.....................................................482 Методы........................................................483
Init..........................................................483 AddString
(иногда переопределяется)...........................484 ClearList (иногда
переопределяется)...........................484
B.Pascal 7 & Objects/OW - 17 -
DeleteString (иногда переопределяется)........................484
GetClassName (переопределяется редко).........................484
GetCount (никогда не переопределяется)........................484
GetMsgID......................................................485
GetSelIndex (переопределяется редко)..........................485
GetSelString (переопределяется редко).........................485
GetString (переопределяется редко)............................485
GetStringLen (переопределяется редко).........................485
InsertString (иногда переопределяется)........................486
SetSelIndex (переопределяется редко)..........................486
SetSelString (переопределяется редко).........................486
Transfer (иногда переопределяется)............................486 TLookupValidator
модуль
Validate.....................................................488 Методы........................................................488
IsValid (переопределяется редко)..............................488 Lookup
(часто переопределяется)...............................488 TMDIClient модуль
OWindows.....................................................490 Поля..........................................................491
Методы........................................................492 Init (переопределяется
редко).................................492 Load..........................................................492
ArrangeIcons (переопределяется редко).........................492 CascadeChildren
(переопределяется редко)......................492 GetClassName (никогда
не переопределяется)....................493 Register......................................................493
Store.........................................................493 TileChildren
(переопределяется редко).........................493 WMPaint (никогда не
переопределяется).........................493 TMDIWindow модуль
OWindows.....................................................494 Поля..........................................................495
Методы........................................................496 Init (часто
переопределяется).................................496 Load..........................................................496
Done (иногда переопределяется)................................496 ArrangeIcons
(переопределяется редко).........................497 CascadeChildren (переопределяется
редко)......................497 CloseChildren (переопределяется редко)........................497
CMArrangeIcons (переопределяется редко).......................497 CMCascadeChildren
(переопределяется редко)....................497 CMCreateChild (никогда не
переопределяется)...................498 CMTileChildren (переопределяется
редко).......................498 CreateChild...................................................498
DefWndProc....................................................498 GetClassName
(иногда переопределяется)........................498 GetClient (никогда
не переопределяется).......................499 GetWindowClass (иногда переопределяется)......................499
InitChild (часто переопределяется)............................499 InitClientWindow
(иногда переопределяется)....................499 SetupWindow (часто переопределяется)..........................499
Store.........................................................500
B.Pascal 7 & Objects/OW - 18 -
TileChildren (переопределяется редко).........................500 Тип TMessage
модуль
OWindows.....................................................501 Тип TMultiSelRec
модуль
ODialogs.....................................................501 TObject
модуль
Objects......................................................502 Методы........................................................502
Init..........................................................502 Free..........................................................502
Done..........................................................502 Тип TPaintStruct
модуль
WinTypes.....................................................502 Тип TPicResult
модуль
Validate.....................................................503 TPrintDialog
модуль
OPrinter.....................................................504 Поля..........................................................505
Методы........................................................507 Init..........................................................507
Тип TPrintDialogRec модуль
OPrinter.....................................................508 TPrinter
модуль
OPrinter.....................................................510 Поля..........................................................510
Методы........................................................512 Init..........................................................512
Done (переопределяется редко).................................512 ClearDevice...................................................512
Configure.....................................................512 GetDC
(переопределяется редко)................................512 InitAbortDialog
(переопределяется редко)......................513 InitPrintDialog (переопределяется
редко)......................513 InitSetupDialog (переопределяется редко)......................513
Print.........................................................513 ReportError
(иногда переопределяется).........................514 SetDevice.....................................................514
Setup.........................................................514 TPrinterAbortDlg
модуль
OPrinter.....................................................515 Методы........................................................516
Init..........................................................516 SetupWindow
(переопределяется редко)..........................516 WMCommand (переопределяется
редко)............................517 TPrinterSetupDlg модуль
OPrinter.....................................................518 Поля..........................................................519
Методы........................................................519 Init..........................................................519
Done (переопределяется редко).................................520 Cancel
(никогда не переопределяется)..........................520 IDSetup (никогда
не переопределяется).........................520 TransferData (никогда не
переопределяется)....................520
B.Pascal 7 & Objects/OW - 19 -
TPrintout модуль
OPrinter.....................................................521 Поля..........................................................521
Методы........................................................522 Init..........................................................522
Done..........................................................522 BeginPrinting.................................................523
EndDocument...................................................523 EndPrinting...................................................523
GetDialogInfo.................................................523 GetSelection..................................................524
HasNextPage...................................................524 PrintPage.....................................................524
SetPrintParams................................................524 TPXPictureValidator
модуль
Validate.....................................................526 Поля..........................................................526
Методы........................................................526 Init..........................................................526
Load..........................................................527 Done..........................................................527
Error.........................................................527 ISValidInput..................................................527
IsInvalid.....................................................527 Picture.......................................................528
Store.........................................................529 TRadioButton
модуль
ODialogs.....................................................530 Методы........................................................531
Init (иногда переопределяется)................................531 GetGlassName..................................................532
TRangeValidator модуль
Validate.....................................................533 Поля..........................................................533
Методы........................................................533 Init..........................................................534
Load..........................................................534 Error.........................................................534
IsValid.......................................................534 Store.........................................................535
Transfer......................................................535 TScrollBar
модуль
ODialogs.....................................................536 Поля..........................................................538
Методы........................................................538 Init..........................................................538
InitResource..................................................538 Load..........................................................539
DeltaPos (переопределяется редко).............................539 GetClassName
(никогда не переопределяется)....................539 GetPosition (переопределяется
редко)..........................539 GetRange (переопределяется редко).............................539
SBBottom (переопределяется редко).............................540
B.Pascal 7 & Objects/OW - 20 -
SBLineDown (переопределяется редко)...........................540
SBLineUp (переопределяется редко).............................540
SBPageDown (переопределяется редко)...........................540
SBPageUp (переопределяется редко).............................540
SBThumbPosition (переопределяется редко)......................541
SBThumbTrack (иногда переопределяется)........................541
SBTop (переопределяется редко)................................541
SetPosition (переопределяется редко)..........................541
SetRange (переопределяется редко).............................541
SetupWindow (иногда переопределяется).........................542
Store.........................................................542
Transfer (иногда переопределяется)............................542 TScroller
модуль
OWindow......................................................543 Поля..........................................................543
Методы........................................................546 Init..........................................................546
Load..........................................................546 Done..........................................................546
AutoScroll (иногда переопределяется)..........................547 BeginView.....................................................547
EndView (иногда переопределяется).............................547 HScroll
(никогда не переопределяется).........................547 IsVisibleRect
(переопределяется редко)........................547 ScrollBy (переопределяется
редко).............................547 ScrollTo (иногда переопределяется)............................548
SetPageSize (иногда переопределяется).........................548 SetRange
(никогда не переопределяется)........................548 SetBarRange (никогда
не переопределяется).....................548 SetUnits......................................................548
Store.........................................................548 VScroll
(никогда не переопределяется).........................549 TSortedCollection
модуль
Objects......................................................550 Поля..........................................................550
Методы........................................................551 Load..........................................................551
Compare (всегда переопределяется).............................551 IndexOf
(никогда не переопределяется).........................551 Insert (никогда
не переопределяется)..........................552 KeyOf (иногда переопределяется)...............................552
Search (переопределяется редко)...............................552 Store.........................................................553
TStatic модуль
ODialogs.....................................................554 Поля..........................................................555
Методы........................................................555 Init..........................................................556
InitResource..................................................556 Load..........................................................556
Clear (переопределяется редко)................................556 GetClassName
(переопределяется редко).........................556 GetText (переопределяется
редко)..............................557
B.Pascal 7 & Objects/OW - 21 -
SetText (переопределяется редко)..............................557
Store.........................................................557
Transfer (иногда переопределяется)............................557 TStrCollection
модуль
Objects......................................................558 Методы........................................................558
Compare (иногда переопределяется).............................558 FreeItem
(переопределяется редко).............................559 GetItem (переопределяется
редко)..............................559 PutItem (переопределяется редко)..............................559
TStream метод
Objects......................................................560 Поля..........................................................560
ErrorInfo (чтение/запись).....................................560 Методы........................................................561
CopyFrom......................................................561 Error
(иногда переопределяется)...............................561 Flush (иногда
переопределяется)...............................561 Get...........................................................562
GetPos (всегда переопределяется)..............................562 GetSize
(всегда переопределяется).............................562 Put...........................................................562
Read (всегда переопределяется)................................563 ReadStr.......................................................563
Reset.........................................................563 Seek (всегда
переопределяется)................................563 StrRead.......................................................564
Truncate (всегда переопределяется)............................564 Write
(всегда переопределяется)...............................564 WriteStr......................................................564
Тип TStreamRec модуль
Objects......................................................565 TStringLookupValidator
модуль
Validate.....................................................567 Поля..........................................................567
Методы........................................................567 Init..........................................................567
Load..........................................................568 Done..........................................................568
Error.........................................................568 Lookup........................................................568
NewStringList.................................................568 Store.........................................................569
TValidator модуль
Validate.....................................................570 Поля..........................................................570
Status........................................................570 Методы........................................................570
Init..........................................................570 Load..........................................................571
Error.........................................................571 IsValid.......................................................571
IsValidInput..................................................571
B.Pascal 7 & Objects/OW - 22 -
Store.........................................................572
Transfer......................................................572
Valid.........................................................573 Тип TVTransfer
модуль
Validate.....................................................574 Тип TWndClass
модуль
WinTypes.....................................................574 TWindow
модуль
OWindows.....................................................576 Поля..........................................................577
Методы........................................................578 Init (часто
переопределяется).................................578 InitResource..................................................579
Load..........................................................579 Done (часто
переопределяется).................................579 Create........................................................579
DefWndProc (никогда не переопределяется)......................580 FocusChild....................................................580
GetID (переопределяется редко)................................580 GetWindowClass
(часто переопределяется).......................580 Paint (часто переопределяется)................................580
SetCaption....................................................581 SetupWindow
(часто переопределяется)..........................581 Store.........................................................581
UpdateFocusChild..............................................581 WMActivate
(иногда переопределяется)..........................582 WMCreate......................................................582
WMHScroll (иногда переопределяется)...........................582 WMLButtonDown
(иногда переопределяется).......................582 WMMDIActivate.................................................583
WMMove........................................................583 WMPaint
(переопределяется редко)..............................583 WMSize (иногда
переопределяется)..............................583 WMSysCommand..................................................583
WMVScroll (иногда переопределяется)...........................584 Тип TWindowAttr
модуль
OWindows.....................................................585 TWindowPrintout
модуль
OPrinter.....................................................586 Поля..........................................................586
Методы........................................................586 Init..........................................................586
GetDialogInfo.................................................587 PrintPage.....................................................587
TWindowsObject модуль
OWindows.....................................................588 Поля..........................................................588
Методы........................................................590 Init (часто
переопределяется).................................590 Load..........................................................590
Done (часто переопределяется).................................590 AddChild......................................................591
At............................................................591
B.Pascal 7 & Objects/OW - 23 -
CanClose (иногда переопределяется)............................591
ChildWithID (никогда не переопределяется).....................591
CloseWindow...................................................591
CMExit........................................................591
Create (никогда не переопределяется)..........................592
CreateChildren................................................592
DefChildProc (иногда переопределяется)........................592
DefCommandProc (иногда переопределяется)......................592
DefNotificationProc (иногда переопределяется).................593
DefWndProc....................................................593
Destroy (никогда не переопределяется).........................593
Disable.......................................................593
DisableAutoCreate.............................................594
DisableTransfer...............................................594
DispatchScroll (никогда не переопределяется)..................594
Enable........................................................594
EnableAutoCreate..............................................594
EnableKBHandler...............................................595
EnableTransfer................................................595
FirstThat.....................................................595
Focus.........................................................596
ForEach.......................................................596
GetChildPtr...................................................596
GetChildren...................................................596
GetClassName (иногда переопределяется)........................597
GetClient (никогда не переопределяется).......................597
GetId (переопределяется редко)................................597
GetSiblingPtr.................................................597
GetWindowClass (иногда переопределяется)......................598
IndexOf.......................................................598
IsFlagSet.....................................................598
Next..........................................................598
Previous......................................................598
PutChildPtr...................................................599
PutChildren...................................................599
PutSiblingPtr.................................................599
Register (никогда не переопределяется)........................599
RemoveChild...................................................600
SetFlags......................................................600
SetupWindow (часто переопределяется)..........................600
Show (никогда не переопределяется)............................600
Store.........................................................601
Transfer (иногда переопределяется)............................601
TransferData (иногда переопределяется)........................601
WMActivate (иногда переопределяется)..........................601
WMClose (иногда переопределяется).............................602
WMCommand (переопределяется редко)............................602
WMDestroy (переопределяется редко)............................602
WMHScroll (переопределяется редко)............................602
WMNCDestroy (никогда не переопределяется).....................602
WMQueryEndSession.............................................603
WMVScroll (переопределяется редко)............................603 Тип TWordArray
модуль
B.Pascal 7 & Objects/OW - 24 -
Objects......................................................603 Константы
voXXXX модуль
Validate.....................................................604 Константы
vsXXXX модуль
Validate.....................................................605 Константы
wb_XXXX модуль
OWindows.....................................................606 Константы
wm_XXXX модуль
OWindows.....................................................606 Тип WordRec
модуль
Objects......................................................606 Стили окна
ws_XXXX модуль
WinTypes.....................................................608
B.Pascal 7 & Objects/OW - 25 -
Введение
В данном руководстве вы найдете полную документацию по ObjectWindows - объектно-ориентированной
прикладной среде для Microsoft Windows. Здесь описываются не только то,
что может делать ObjectWindows и как, но и почему. Вы поймете, что ObjectWindows
- это наиболее быстрый путь построения развитых и многофункциональных приложений
Windows.
Хотя в данном руководстве поясняется, как работает Windows, и как с ней
взаимодействуют ваши прикладные программы, оно не охватывает все аспекты
программирования с использованием прикладного программного интерфейса Windows
(API). Эти подробности вы можете узнать в других книгах о программировании
в Windows.
ObjectWindows позволит вам избежать утомительных и трудоемких задач, связанных
с разработкой традиционных приложений Windows. Тем не менее вы будете иметь
доступ ко всем имеющимся в Windows средствам, но иметь дело с Windows вам
придется только когда вы этого захотите. Все остальное делает за вас ObjectWindows.
Что такое ObjectWindows?
В иерархию данной версии ObjectWindows включены новые объекты, а также добавлены
средства к существующим объектам. Изменения существующих объектов обладают
обратной совместимостью, так что существующий код ObjectWindows следует
компилировать с минимальными изменениями.
В данной версии ObjectWindows вы найдете следующие новые средства:
* поддержку проверки допустимости данных (Глава 13);
* объекты для печати документов и содержимого окон (Глава
15);
* специализированные управляющие элементы фирмы Borland в
стиле Windows;
* множество модулей.
Кроме того, данное руководство содержит следующие новые материалы:
* расширенное учебное руководство;
* новую главу по сообщениям Windows (Глава 16);
* реорганизованные главы, посвященные иерархии и объектам;
B.Pascal 7 & Objects/OW - 26 -
* более полную информацию о наследовании в справочной части.
Для чего предназначена ObjectWindows?
Windows знакомит вас со множеством вещей, которые, возможно, раньше никогда
не приходили вам в голову. Это, например, работа с текстом и графикой в
окнах с изменяемым размером, взаимодействие с другими программами в многозадачной
среде и работа с почти 600 функциями API Windows. Когда вы подумаете, сколько
основных шагов должна выполнять ваша программа при работе в Windows, и что
нужно отследить их все, это может выглядеть обескураживающим.
Чтобы прикладную программу можно было признать приложением Windows, она
должна делать очень многое. Например, она не может выводить информацию прямо
на экран и записывать данные непосредственно в видеопамять. Кроме того,
приложение Windows должно отвечать на уведомляющие сообщения, которые посылает
своим приложениям Windows в ответ на действия пользователя (события) тип
выбора пункта меню.
Но вам не обязательно делать все это самим. Хорошим началом для этого послужит
ObjectWindows.
ObjectWindows - это объектно-ориентированная библиотека, инкапсулирующая
большую часть свойств окна и позволяющая вам использовать наследование,
а не начинать заново с началом каждой новой программы. Обеспечивая для вас
стабильную и жесткую операционную среду, она позволяет вам сосредоточиться
на индивидуальных фрагментах программы, а не на частях, общих для всех приложений
Windows.
Что нужно знать
Перед началом программирования для Windows вы должны быть знакомы с его
основами. Во-первых, нужно знать, как использовать Паскаль и Windows. О
программировании на Паскале рассказывается в "Руководстве пользователя"
и "Руководстве по языку", а о работе с Windows вы можете прочитать
в документации, поставляемой с программным обеспечением Windows.
Кроме того, для работы с ObjectWindows вы должны владеть объектно-ориентированным
программированием. Приложения, написанные с использованием ObjectWindows,
интенсивно используют объектно-ориентированные методы, включая наследование
и полиморфизм. Эти темы освещаются в главе по объектно-ориентированному
программированию в "Руководстве пользователя". Кроме объектно-ориентированных
методов вы должны знать о работе с указателями и динамическими переменными,
поскольку почти все экземпляры объектов ObjectWindows динамически распределяются
в динамической области памяти. Об указателях также рассказывается в "Руководстве
пользо-
B.Pascal 7 & Objects/OW - 27 -
вателя".
Как работать с данным руководством
"Руководство по программированию с использованием
ObjectWindows" расширено, что сделало его более полным и простым в
использовании. Если вы уже знакомы с ObjectWindows, то можете пропустить
главы 7, 13, 15 и 16 и прочитать о новых средствах. Если вы только начинаете
работать с ObjectWindows, то прочитайте сначала первую часть ("Изучение
ObjectWindows"). Эту часть можно использовать в качестве учебного руководства,
в котором описывается построение полного приложения ObjectWindows и объясняются
принципы ObjectWindows.
О чем рассказывается в данном руководстве
Так как ObjectWindows представляет собой новый подход в программировании
для Windows и использует некоторые новые методы, с которыми вы, вероятно,
не знакомы, в этом руководстве вы можете найти поясняющий материал. Полные
справочные материалы по ObjectWindows вы можете найти в Главе 21 "Справочник
по ObjectWindows".
Это руководство разбито на 4 части:
* Часть 1, "Изучение ObjectWindows", знакомит вас с принципами
разработки прикладной программы Windows с помощью ObjectWindows, включая
учебные материалы, описывающие процесс написания и дополнения приложения
ObjectWindows.
* В Части 2, "Использование ObjectWindows", дается более детальная
информация об элементах ObjectWindows, включая обзор иерархии и ее взаимодействие
с операционной средой Windows, а также подробно поясняются части иерархии
и их использование.
* В Части 3, "Продвинутое программирование с использование
ObjectWindows" обсуждаются важные темы продвинутого программирования
в Windows, особенно в части непосредственного взаимодействия с операционной
средой Windows, включая сообщения, графику и использование ресурсов. Здесь
вы найдете также главы о наборах и потоковых объектах.
* Часть 4, "Справочник по ObjectWindows", представляет собой полный
справочник по всем объектам и других элементам, включенным в модули ObjectWindows.
B.Pascal 7 & Objects/OW - 28 -
Часть 1. Изучение ObjectWindows
Глава 1. Знакомство с Windows
В следующих нескольких главах мы построим графическую интерактивную программу
Windows, дополненную меню, средствами сохранения и загрузки файлов, графикой
и отображением текста, а также специализированными управляющими элементами.
По ходу дела вы познакомитесь с основными принципами проектирования программы
Windows, такими как обработка сообщений, управление дочерним и порождающим
окном и автоматическое повторное отображение графики.
Этот процесс разбит на следующие шаги:
- создание базового приложения;
- вывод текста в окне;
- изображение линий в окне;
- добавление строки меню;
- добавление диалогового окна;
- изменение атрибутов пера;
- повторное отображение графики;
- сохранение изображения в файле;
- печать образа;
- добавление всплывающего окна;
- добавление специализированных управляющих элементов;
- создание специализированного управляющего элемента окна.
Исходный код приложения для различных этапов вы можете найти на дистрибутивных
дисках. Описываемым в руководстве шагам соответствуют файлы STEP01.PAS,
STEP02.PAS и так далее (можно найти также промежуточные программы).
Шаг 1: Создание базового приложения
------------------------ Step 1: Basic App |Step 2: Text |Step 3: Lines
|Step 4: Menu |Step 5: About Box |Step 6: Pens |Step 7: Painting |Step 8:
Streams |Step 9: Printing |Step 10: Palette |Step 11: BWCC |Step 12: Custom
ctrls | Базовая программаТекстСтрокиМенюОб окнеПерьяРисованиеПотокиПечатьПалитраУправляющие
элементы окнаСпециализированные элементы
B.Pascal 7 & Objects/OW - 29 -
Отправным пунктом для всех программ, которые вы пишете с применением ObjectWindows,
является программа STEP01A.PAS. Эта программа, которая называется Steps,
создает основное окно приложения.
Все программы ObjectWindows должны использовать модуль OWindows, которые
содержит стандартные объекты, используемые ObjectWindows для приложений
и окон. Большинство приложений включают в себя также диалоговые блоки и
соответствующие управляющие элементы. ObjectWindows предусматривает для
них объекты в модуле ODialogs. Объекты, относящиеся к печати, находятся
в модуле OPrinter. Программам, применяющим наборы и потоки, необходим модуль
Objects.
Кроме модулей ObjectWindows большинству программ необходимы также модули
WinTypes и WinProcs. Эти два модуля определяют типы и константы (WinTypes)
и процедуры и функции (WinProcs), образующие прикладной программный интерфейс
Windows (API). Приложениям, использующим продвинутые средства Windows (версий
старше 3.0), кроме данных двух нужны также другие модули.
Примечание: Обзор модулей ObjectWindows вы можете найти в Главе 7 "Иерархия
ObjectWindows".
Требования к приложению
Все приложения Windows имеют основное окно, которое выводится при запуске
программы пользователем. Пользователь выходит из приложения, закрывая основное
окно. В приложении ObjectWindows основное окно представляет собой объект
окна. Этот объект принадлежит объекту приложения, который отвечает за создание
и вывод на экран основного окна, обработку сообщений Windows и завершение
программы. Объект приложения действует как объектно-ориентированная замена
самого приложения. Аналогично, чтобы сделать скрытыми детали программирования
в Windows, ObjectWindows предусматривает окно, диалоговый блок и другие
объектные типы.
Каждая программа ObjectWindows должна определять новый тип приложения, являющегося
наследником предоставляемого типа TApplication. В программе Steps этот тип
называется TMyApplication. Приведем основной блок программы Steps:
var
MyApp: TMyApplication; begin
MyApp.Init('Steps');
MyApp.Run;
MyApp.Done; end.
Init - это конструктор TMyApplication, создающий новый объект MyApp. Он
позволяет также задать имя приложения (поле объек-
B.Pascal 7 & Objects/OW - 30 -
та) 'Steps' и создает (и выводит) основное окно приложения. Run
запускает последовательность вызовов методов, составляющих ход
выполнения приложения Windows. Done - это деструктор
TMyApplication.
Определение типа приложения
Ваша прикладная программа должна создавать новый тип из стандартного типа
ObjectWindows TApplication (или некоторых типов, производных от TApplication).
Этот новый тип должен переопределять по крайней мере один метод - InitMainWindow.
TApplication.InitMainWindow вызывается ObjectWindows автоматически для установки
основного окна программы. Каждое приложение ObjectWindows должно строить
свое основное окно.
Примечание: Объекты приложения подробно описываются в Главе 8.
Определение TMyApplication имеет следующий вид:
type
TMyApplication = object(TApplication) procedure InitMainWindow; virtual;
end;
Инициализация основного окна
InitMainWindow отвечает за построение объекта окна, используемого в качестве
основного окна программы. Этот объект основного окна хранится в поле объекта
приложения MainWindow. Объекту приложения принадлежит объект основного окна,
но эти два объекта не являются родственными в иерархии наследования.
precedure TMyApplication.InitMainWindow;
begin
MainWindow := New(PWindow, Init(nil, 'Steps')); end;
Обычно метод InitMainWindow модифицируется для создания нового типа основного
окна. Указанный метод использует экземпляр объекта TWindow - предоставляемый
ObjectWindows тип окна, который определяет наиболее общее окно. На шаге
2 мы заменим его более интересным оконным типом.
Пока программа Steps просто выводит на экран пустое окно, которое можно
перемещать по экрану, изменять его размер, минимизировать, максимизировать
и закрывать. Приведем полный листинг программы Steps, которую мы получили
к данному моменту:
program Steps;
B.Pascal 7 & Objects/OW - 31 -
uses OWindows;
type
TMyApplication = object(TApplication) procedure InitMainWindow; virtual;
end;
procedure TMyApplication.InitMainWindow;
begin
MainWindows := New(PWindow, Init(nil, 'Steps')); end;
var MyApp: TMyApplication;
begin
MyApp.Init('Steps');
MyApp.Run;
MyApp.Done; end.
B.Pascal 7 & Objects/OW - 32 -
Объект основного окна
Пока программа Steps состоит из двух объектов - объекта приложения и объекта
окна. Объект приложения (MyApp) является экземпляром TMyApplication - типом,
производным от TApplication. Оконный объект, который содержится в поле MainWindow
объекта MyApp, является экземпляром TWindow (общее окно ObjectWindows).
Во всех программах, кроме простейших, вам нужно определить тип своего основного
окна, соответствующий поведению приложения. В данном разделе мы выведем
на экран основное окно, тип которого является производным от TWindow.
Приложения: Более подробно об основном окне рассказывается в Главе 8 "Объекты
приложения".
Что такое объект окна?
Объект приложения инкапсулирует стандартное поведение приложения Windows,
включая построение основного окна. Тип TApplication обеспечивает фундаментальное
поведение для каждого создаваемого вами приложения.
Аналогично, объект окна инкапсулирует поведение, реализуемое приложениями
ObjectWindows, включая их основные окна. Это поведение включает в себя вывод
на экран, изменение размера и закрытие; ответ на пользовательские события,
такие как щелчок кнопкой "мыши", буксировку и выбор пунктов меню;
вывод управляющих элементов, таких как блоки списка и командные кнопки.
Тип TWindow и его предок TWindowsObject предусматривают для данного базового
поведения методы и поля.
Примечание: Объекты окна подробно описываются в Главе 10 "Объекты окна".
Чтобы сделать ваши программы полезными и интересными, вам нужно создать
новый тип, производный от TWindow. Новый тип наследует поля и методы TWindow
и добавляет часть своих. В общем случае объектно-ориентированный подход
позволяет вам не "изобретать" каждый раз окно.
B.Pascal 7 & Objects/OW - 33 -
Описатели
Объект окна имеет по крайней мере три поля: HWindow. Parent и ChildList.
HWindow содержит описатель окна. Описатель окна - это уникальное число,
которое связывает интерфейсный объект (такой как окно, диалоговый блок или
объект управляющего элемента) с соответствующим элементом экрана.
Примечание: Подробно об описателях окна их использовании рассказывается
в Главе 10 "Объекты окна".
Таким образом, HWindow содержит целое значение, идентифицирующее соответствующий
элемент экрана. Это напоминает бирку на связке ключей. Аналогично тому как
вы выбираете ключ, чтобы достать из шкафа пальто, вы выбираете описатель
для получения окна. В большинстве случаев вы работаете с объектами окна,
и у вас нет необходимости манипулировать описателем окна непосредственно,
но они используются при вызове функций Windows. Например, на данном шаге
вы вызываете функцию MessageBox. Эта функция требует указания параметра,
идентифицирующего порождающее окно сообщений. Вы указываете основное окно,
описатель которого записан в его поле HWindow:
MessageBox(MainWindow^.HWindow, 'Хотите сохранить?',
'Файл не изменен', mb_YesNo or mb_IconQuestion);
Порождающие и дочерние окна
Большинство приложений используют несколько окон, и, чтобы они взаимодействовали,
их требуется связать. Например, когда вы завершаете приложение, оно должно
иметь способ очистки всех окон, за которые отвечает. В общем случае Windows
справляется с этим, связывая окна как дочернее и порождающее. Порождающее
окно отвечает за свое дочернее окно. ObjectWindows предусматривает для каждого
объекта окна поля для отслеживания порождающего и дочерних окон.
Примечание: Взаимодействие этих окон подробнее описывается в Главе 9.
Поле Parent содержит указатель на порождающий оконный объект. Это не порождающее
окно в смысле предка, а скорее окно-владелец. Взаимосвязь этих окон описывается
в шаге 10.
Третье поле оконного объекта - это поле ChildList, содержащее связанный
список дочерних окон.
Создание нового типа окна
Теперь у вас есть некоторое представление о том, что содер-
B.Pascal 7 & Objects/OW - 34 -
жит оконный объект, и вы можете создать новый оконный тип, производный от
TWindow, используя его как основное окно программы Step. Сначала измените
определения и задайте новый тип TStepWindow. Не забудьте также определить
новый указатель на тип TStepWindow - PStepWindow, который будет полезен
при создании экземпляров объектов TStepWindow.
type
PStepWindow = ^TStepWindow;
TStepWindow = object(TWindow) end;
Затем измените TMyApplication.InitMainWindow, чтобы создать в качестве основного
окна вместо TWindow TStepWindow.
procedure TMyApplication.InitMainWindow;
begin
Main := New(PStepWindow, Init(nil, 'Step')); end;
Определение нового типа и создание его экземпляра в InitMainWindow - это
все, что требуется для определения нового типа основного окна для TMyProgram.
Объект приложения вызывает методы для создания интерфейсного элемента окна
(Create) и вывода его на экран (Show). Вам почти никогда не потребуется
использовать эти методы непосредственно. Обычно они вызываются при вызове
метода MakeWindow объекта приложения.
Примечание: MAkeWindow поясняется в Главе 9 "Интерфейсные объекты".
Однако TStepWindow не определяет новых видов поведения, отличных от тех,
которые наследуются от TWindow и TWindowObject. Другими словами, программа
Step не становится более интересной. Такие виды поведения будут добавлены
в следующем разделе.
Реакция на сообщения
Скорейший способ сделать оконный объект полезным - это заставить его отвечать
на некоторые сообщения Windows. Например, когда вы щелкаете "мышью"
в основном окне программы Step, Windows посылает окну сообщение wm_LButtonDown,
которое перехватывается ObjectWindows и посылается затем соответствующему
оконному объекту. Это указывает оконному объекту, что пользователь щелкнул
в нем кнопкой "мыши". При этом передаются также координаты точки,
где пользователь нажал кнопку. (Эту информацию мы используем в шаге 2.)
Примечание: Сообщения Windows определены в модуле WinTypes.
Аналогично, когда пользователь щелкает правой кнопкой "мы-
B.Pascal 7 & Objects/OW - 35 -
ши", основной оконный объект получает сообщение wm_RButtonDown,
переданное Windows. На следующем шаге мы узнаем, как сделать так,
чтобы основное окно (экземпляр TStepWindow) отвечало на эти сообщения и
делало что-нибудь полезное.
Чтобы перехватывать сообщения Windows и отвечать на них, для каждого типа
поступающего сообщения, на которое вы хотите реагировать, вам нужно определить
метод оконного объекта. Такие методы называются методами реакции на сообщение.
Чтобы определить заголовок определения метода как метод реакции, нужно добавить
к виртуальному методу расширение, представляющее собой идентификатор сообщения,
на которое нужно реагировать. Например, определенный ниже метод реагирует
на все сообщения wm_LButtonDown.
type
TStepWindow = object(TWindow)
procedure WMLButtonDown(var Msg: TMessage); virtual
vm_First + wm_LButtonDown;
end;
Примечание: Все программы и модули, переопределяющие методы ответа на сообщение,
должны использовать WinTypes.
Все сообщения в Windows, включая системные сообщения Windows и команды меню,
представляются в виде чисел. Каждый метод реакции на сообщение должен иметь
уникальное число, так что для сообщений Windows и команд, если они имеют
одинаковые номера, вызываются различные методы.
Чтобы облегчить для вас эту задачу, ObjectWindows определяет для каждого
вида сообщений константы: wm_First для сообщений окон, cm_First для командных
сообщений и nf_First для уведомляющих сообщений. Подробнее об этих константах
рассказывается в Главе 7, но сейчас нужно только помнить, что когда вы пишете
метод реакции на сообщение, начинающееся с wm_, к нему добавляется wm_First.
Msg - это запись типа TMessage, содержащая такую информацию, как координаты
точки, где была нажата кнопка "мыши". Все методы реакции на сообщение
должны воспринимать один параметр-переменную типа TMessage. Аргумент Msg
мы рассмотрим в программе Step позднее.
В данный момент вы можете просто определить методы реакции, которые выводят
на экран окно сообщения о нажатии кнопки "мыши". Позднее вы сможете
добавить более полезную реакцию. Приведем определение метода реакции на
нажатие левой кнопки "мыши":
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
begin
MessageBox(HWindow, 'Вы нажали левую кнопку мыши',
'Диспетчеризуемое сообщение', mb_OK);
end;
B.Pascal 7 & Objects/OW - 36 -
Примечание: Программы, которые вызывают MessageBox или другие функции API
Windows, должны использовать модуль WinProcs.
Steps
| = Диспетчеризуемое сообщение |
| || Вы нажали левую кнопку мыши || ------------- || | OK | || -------------
|
Рис. 1.2 Программа Steps реагирует на пользовательское событие.
Завершение прикладной программы
Программа Steps завершает выполнение, когда пользователь дважды щелкает
"мышью" в блоке управляющего меню основного окна - маленьком
квадрате в левом верхнем углу. Окно и приложение немедленно закрываются.
Такое поведение годится для простых программ, но может вызвать затруднения
в более сложных случаях.
Перед выходом хорошо написанное приложение всегда спрашивает, хочет ли
пользователь сохранить несохраненные результаты работы. Такой вид поведения
вы легко можете добавить в свою прикладную программу ObjectWindows. Начните
со Step и добавьте двойную проверку запроса пользователя на выход.
Когда пользователь пытается закрыть приложение
ObjectWindows, Windows посылает основному окну сообщение
wm_Close, которое вызывает метод CanClose приложения. CanClose -
это булевская функция, указывающая, можно ли завершить (OK) приложение
(True). По умолчанию метод CanClose наследуется из вызова TApplication
метода CanClose основного оконного объекта. В большинстве случаев решение
о закрытии (OK) принимается объектом основного окна.
B.Pascal 7 & Objects/OW - 37 -
Переопределение CanClose
Тип основного окна TStepWindow наследует метод CanClose от TWindowObject,
которые вызывает методы CanClose каждого из своих дочерних окон (если
они имеются). Если дочерних окон нет (как в данном случае), CanClose просто
возвращает значение True. Чтобы модифицировать поведение приложения при
закрытии, вы можете переопределить метод CanClose для объектного типа
своего основного окна:
function TStepWindow.CanClose: Boolean;
var Reply: Integer;
begin
CanClose := True;
Reply := MessageBox(HWindow, 'Хотите сохранить?',
'Графическое изображение изменено',
mb_YesNo or mb_IconQuestion);
if Reply = id_Yes then CanClose := False;
end;
B.Pascal 7 & Objects/OW - 38 -
Теперь когда пользователи попытаются закрыть Step, они получат окно сообщений
с запросом "Хотите сохранить". Щелчок "мышью" на командной
кнопке Yes (Да) приводит к тому, что CanClose возвращает значение False
и предотвращает закрытие основного окна и приложения. Щелчок "мышью"
на No (Нет) возвращает True, и приложение завершает работу. На шаге 8
это окно сообщений получит некоторый смысл. Модифицированная программа
Steps показана на Рис.
1.3.
Steps
| = Изображение изменилось |
| || ? Хотите сохранить? || ------------- ------------- || | Yes | | No
| || ------------- ------------- |
Рис. 1.3 Программа Steps с переопределенным поведением окна.
Дальнейшее изменение закрытия
Естественно, сообщение о том, что изображение изменилось, полезно только
в том случае, если программа действительно обнаруживается изменение изображения.
Добавив в TStepWindow поле типа Boolean, вы можете задать флаг, указывающий
на изменение изображения, и выводить окно сообщения только тогда, когда
этот флаг установлен.
Нужно помнить о том, что когда вы добавляете это поле, поле нужно также
инициализировать, поэтому переопределим конструктор TStepWindow:
type
PStepWindow = ^TStepWindow;
TStepWindow = object(TWindow)
HasGhanged: Boolean;
constructor Init(AParent: PWindowsObject: ATitle:
PChar);
.
.
.
end;
B.Pascal 7 & Objects/OW - 39 -
constructor TStepWindow.Init(AParent: PWindowsObject:
ATitle: PChar); begin
inherited Init(AParent, ATitle);
HasChanged := False; end;
Далее измените метод CanClose для проверки перед выводом окна сообщения
HasChanged:
function TStepWindow.CanClose: Boolean;
var Reply: Integer;
begin
CanClose := True; if HasChanged then begin
Reply := MessageBox(HWindow, 'Хотите сохранить?', 'Изображение изменилось',
mb_YesNo or mb_IconQuestion);
if Reply = id_Yes then CanClose := False;
end;
end;
Позднее, когда вы фактически изменяете изображение,
HasChanged нужно установить в True. Следующий листинг показывает полный
исходный под программы Steps на данном шаге:
program Steps;
uses WinTypes, WinProcs, OWindows;
type
TMyApplication = object(TApplication) procedure InitMainWindow; virtual;
end;
type
PStepWindow = ^TStepWindow;
TStepWindow = object(TWindow)
Haschanged: Boolean;
constructio Init(AParent: PWindowsObject; ATitle:
PChar);
function CanClose: Boolean; virtual;
procedure CanClose: Boolean; virtual;
procedure WMLButtonDown(var Msg: TMessage);
virtual wm_First + wm_LButtonDown;
procedure WMRButtonDown(var Msg: TMessage);
virtual sm_First +? wm_RButtonDown;
end;
constructor TStepWindow.Init(AParent: PWindowsObject;
ATitle: PChar);
B.Pascal 7 & Objects/OW - 40 -
begin
inherited Init(AParent, ATitle);
HasChanged := False; end;
function TStepWindow.CanClose: Boolean;
var Reply: Integer;
begin
if HasChanged then
begin
CanClose := True;
Reply := MessageBox(HWindow, 'Хотите сохранить?',
'Изображение изменилось',
mb_YesNo or mb_IconQuestion);
if Reply = id_Yes then CanClose := False;
end;
end;
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
begin
MessageBox(HWindow, 'Вы нажали левую кнопку мыши',
'Диспетчеризуемое сообщение', mb_OK);
end;
procedure TStepWindow.WMRButtonDown(var Msg: TMessage);
begin
MessageBox(HWindow, 'Вы нажали правую кнопку мыши',
'Диспетчеризуемое сообщение', mb_OK);
end;
procedure TMyApplication.InitMainWindow;
begin
MainWindows := New(PStepWindow, Init(nil, 'Steps')); end;
var MyApp: TMyApplication;
begin
MyApp.Init('Steps');
MyApp.Run;
MyApp.Done; end.
B.Pascal 7 & Objects/OW - 41 -
Глава 2. Заполнение окна
Пока ваша программа не делает ничего интересного. В данной главе мы возьмем
программу Step, которая пока представляет собой просто оболочку программы,
и преобразуем ее в полезное интерактивное графическое приложение. Сначала
мы выведем в основном окне текст. Затем преобразуем Step в полное графическое
приложение, позволяющее вам отображать в основном окне линии различной
толщины.
Шаг 2: Отображение текста в окне
Step 1: Basic App Step 2: Text Step 3: LinesStep 4: MenuStep 5: About
BoxStep 6: PensStep 7: PaintingStep 8: StreamsStep 9: PrintingStep 10:
PaletteStep 11: BWCCStep 12: Custom ctrls
В качестве первого шага в направлении создания отображающей программы
нарисуем в окне некоторые текстовые символы. Текст будет отображаться
в ответ на щелчок левой кнопкой "мыши", который вы перехватывали
на шаге 1. Но вместо вывода окна сообщения на этот раз реакцией будет
вывод текста, показывающего координаты той точки в окне, где вы щелкнули
кнопкой "мыши".
В графической операционной среде типа Windows текст рисуется как графика,
а не выводится в виде символов на стандартное устройство вывода. В некотором
смысле это эквивалентно использованию позиционирования курсора в программах
DOS, где вы задаете расположение каждого текстового элемента, а не полагаетесь
на прокрутку экрана. Конечно, в Windows вы можете также управлять размером,
стилем, гарнитурой и цветом текста.
Вывод в контексте дисплея
Чтобы вывести текст в основном окне программы Step, вам нужна некоторая
отображаемая информация. В Windows имеются специальные средства, управляющие
ее графикой, которые называются контекстом дисплея. Контекст дисплея можно
рассматривать как элемент, представляющий поверхность окна, где выводится
изображение. Контекст экрана необходим Windows для отображения в окне
любого
B.Pascal 7 & Objects/OW - 42 -
текста или графики.
Примечание: Подробно о контексте дисплея рассказывается в Главе 17 "Интерфейс
с графическими устройствами".
Что такое контекст дисплея?
Контекст дисплея имеет три основных функции отображения:
* Он обеспечивает, что текст и графика не выводятся вне поверхности окна.
* Он управляет выбором и отменой инструментальных средств
отображения: перьев, кистей и шрифтов. В шаге 3 показан
пример выбора нового пера, но мы начнем сначала с вывода
текста.
* Он обеспечивает независимость от устройства. Для вывода в
контексте дисплея ваша программа использует стандартные
функции API Windows. В шаге 9 мы покажем как можно использовать одни и
те же команды для отображения в окне и на принтере.
Windows управляет контекстом дисплея в своем собственном пространстве
памяти, но ваша прикладная программа может отслеживать контекст дисплея
с помощью описателей. Как и описатель окна, описатель контекста дисплея
- это число, идентифицирующее корректный контекст дисплея Windows.
Поскольку, чтобы рисовать в окне при буксировке "мыши", вам
необходим контекст дисплея, создайте в объекте основного окна новое поле
с именем DragDC, которое будет содержать описатель контекста дисплея.
DragDC имеет тип HDC, который эквивалентен типу Word.
Чтобы использовать контекст дисплея, ваша программа должна:
* получить контекст дисплея;
* нарисовать в нем;
* освободить контекст дисплея.
Получение контекста дисплея
Чтобы отобразить что-то в окне, вы должны сначала получить контекст дисплея.
Это можно сделать, вызвав в одном из методов типа непосредственно перед
отображением на экране функцию Windows GetDC:
DragDC := GetDC(HWindow);
B.Pascal 7 & Objects/OW - 43 -
Использование контекста дисплея
Теперь вы можете использовать DragDC в качестве параметра в вызовах графических
функций Windows, требующих указания контекста дисплея. Приведем несколько
примеров:
TextOut(DragDC, 20, 20, 'Пример текста', 11);
LineTo(DragDC, 30, 45);
Освобождение контекста дисплея
После отображения текста или графики вы должны освободить контекст дисплея
(как только закончите отображение).
ReleaseDC(HWindow, DragDC);
Если вы не освободите весь полученный контекст дисплея, то скоро исчерпаете
его, что приводит обычно к зависанию компьютера. Если ваша программа не
может что-либо отобразить, проверьте освобождение контекстов дисплея.
Windows выделяет по пять контекстов дисплея на приложение, которые можно
совместно использовать через GetDC. Пока в Windows зарезервировано достаточно
памяти, вы можете с помощью GetDC получить другие контексты.
Примечание: GDI и вопросы использования памяти освещаются в Главе 17 "Интерфейс
с графическим устройством".
B.Pascal 7 & Objects/OW - 44 -
Координаты Windows
Если вы работали с графикой раньше, то вам уже знакомо понятие системы
координат. В Windows координаты потребуются вам для вывода текста.
При отображении вас касаются только координаты в контексте дисплея. Windows
обеспечивает, чтобы контекст дисплея попадал в область клиента окна.
Примечание: Область клиента - это часть окна внутри рамки.
На этом шаге Step отобразит текст, показывающий координаты той точки в
окне, где вы щелкнули кнопкой "мыши". Например, '(20,
30)' - это точка, отстоящая на 20 элементов изображения вправо и на 30
элементов изображения вниз от верхнего левого угла поверхности отображения.
Вы можете отображать прямо в той точке, где щелкнули "мышью".
Это показано на Рис. 2.1.
Steps
(3,7) (483,7)(385,31)(60,42)(217,52)(302,110) (444,110)(109,141)(52,182)(239,187)
(385,181)(4,288) (474,220)
Рис. 2.1 Отображение текста в точке нажатия кнопки "мыши".
Параметры сообщений
Щелчок левой кнопкой "мыши" генерирует сообщение
wm_LButtonDown, который вы перехватываете с помощью метода реакции на
сообщение WMLButtonDown.
Параметр Msg метода реакции на сообщение несет информацию о породившем
сообщение событии (такую как координаты точки, где пользователь щелкнул
кнопкой "мыши"). Msg - это запись TMessage,
B.Pascal 7 & Objects/OW - 45 -
поля которой содержат параметр lParam типа Longint и параметр
wParam типа Word. Идентификаторы lParam и wParam соответствуют
полям в структуре сообщения Windows TMsg.
TMessage определяют также вариантные поля, содержащие подполя lParam и
wParam. Например, Msg.lParamLo содержит младшее слово lParam, а Msg.lParamHi
- старшее слово. Чаще всего используются поля wParam, lParamLo и lParamHi.
В случае WMLButtonDown Msg.lParamLo содержит x-координату точки нажатия
кнопки "мыши", а Msg.lParamHi - y-координату этой точки. Таким
образом, чтобы переписать WMLButtonDown для отображения координат точки
нажатия кнопки, нужно преобразовать Msg.lParamLo и Msg.lParamHi в строки
и, чтобы они приняли вид '(25,21)', конкатенировать их с запятой. В примере
для форматирования строки используется функция Windows WVSPrintF.
Примечание: Слияние параметров зависит от сообщения. Подробности о каждом
сообщении и его параметре вы можете узнать, воспользовавшись оперативным
справочником Help.
После получения итоговой строки ее можно вывести в точке нажатия кнопки
"мыши" с помощью функции Windows TextOut. Перед отображением
нужно получить контекст дисплея, а после отображения
- освободить его.
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
var S: array[0..9] of Char;
begin
WVSPrint(S, '(%d,%d)', Msg.LParam);
DragDC := GetDC(HWindow);
TextOut(DragDc, Msg.LParamLo, Msg.LParamHi, S, StrLen(S));
ReleaseDC(HWindow, DragDC); end;
Примечание: Windows ожидает получения строк с завершающим нулем (конечным
нулевым байтом). Подробнее эти строки описываются в Главе 18 "Руководства
по языку".
Очистка окна
В приложение, отображающее текст, вы можете также добавить еще одну функцию
- функцию отчистки окна. Заметим, что после изменения размера окна, либо
когда вы скрываете его и выводите снова, нарисованный текст стирается.
Однако, можно задать принудительную очистку окна в ответ на команду меню
или какое-либо другое действие пользователя, например, щелчок кнопкой
"мыши".
Чтобы очистить окно в ответ на щелчок правой кнопкой "мыши",
переопределите метод WMRButtonDown и вызовите в нем процедуру InvalidateRect,
которая приводит к повторному отображению всего
B.Pascal 7 & Objects/OW - 46 -
окна. Так как ваша программа пока не знает, как повторно вывести
изображение, она просто очистит область клиента:
Procedure TStepWindow.WMRButtonDown(var Msg: TMessage); begin
InvelidateRect(HWindow, nil, Trut); end;
Текущий исходный код вы можете найти в файле STEP02.PAS.
B.Pascal 7 & Objects/OW - 47 -
Шаг 3: Изображение линий в окне
Step 1: Basic AppStep 2: Tex Step 3: Lines Step 4: MenuStep 5: About BoxStep
6: PensStep 7: PaintingStep 8: StreamsStep 9: PrintingStep 10: PaletteStep
11: BWCCStep 12: Custom ctrls
Теперь, когда вы познакомились со схемой отображения (получение контекста
дисплея, отображение, освобождение контекста дисплея), ее можно использовать
в более полном интерактивном графическом приложении. Следующие несколько
шагов посвящены построению простой графической программы, позволяющей
пользователю рисовать в основном окне.
На шаге 3 мы добавим следующее поведение:
* Щелчок левой кнопкой "мыши" и буксировка соединяют начальную
и конечную точки отображая в результате линию.
* Щелчок правой кнопкой "мыши" выводит диалоговое окно ввода,
позволяющее пользователю изменить толщину линии.
Чтобы выполнить эти шаги, изучим сначала схему буксировки Windows, а затем
реализуем простую графическую программу.
B.Pascal 7 & Objects/OW - 48 -
Буксировка линии
Мы уже видели, что щелчок левой кнопкой "мыши" дает в результате
сообщение wm_LButtonDown и вызывает метод WMLButtonDown. В шаге 1 ваша
программа отвечала на щелчки левой кнопкой "мыши", выводя окна
сообщений. Вы могли также видеть, что щелчок правой кнопкой "мыши"
давал в результате сообщение wm_RButtonDown и вызывал метод WMRButtonDown.
На нажатие правой кнопки "мыши" программа отвечала очисткой
окна.
Но это предусматривает реакцию только на щелчки кнопкой "мыши".
Многие программы Windows требуют от пользователя нажатия кнопки "мыши"
и перемещения ее указателя по экрану (буксировка). При этом рисуются линии
или прямоугольники, либо графическое изображение помещается в точку с
конкретными координатами. Для программ графического отображения желателен
перехват событий буксировки и реакция на них путем изображения линий.
Сообщения wm_MouseMove
Сделать это можно путем реакции еще на несколько сообщений. Когда пользователь
буксирует "мышь" в новую точку окна, Windows посылает сообщение
wm_MouseMove, а когда пользователь отпускает левую кнопку "мыши"
- сообщение wm_LButtonUp. Обычно окно получает одно сообщение wm_LButtonDown,
за которым следует последовательность сообщений wm_MouseMove (по одному
на каждую промежуточную точку буксировки) и одно сообщение wm_LButtonUp.
Типичная графическая программа Windows реагирует на сообщение wm_LButtonDown
инициализацией процесса рисования (получая, кроме всего прочего, контекст
дисплея). На сообщение wm_LButtonUp она реагирует завершением процесса
рисования (освобождая контекст дисплея).
B.Pascal 7 & Objects/OW - 49 -
Реакция на сообщения буксировки
Нужно помнить о том, что после wm_LButtonDown всегда следует сообщение
wm_LButtonUp (с промежуточными сообщениями wm_MouseMove или без них).
Таким образом, каждый раз, когда вы получаете контекст дисплея, вы можете
позднее освободить его.
Для правильного функционирования программы Windows очень важным является
освобождение каждого получаемого вами контекста дисплея. Однако вы можете
добавить еще одно более надежное средство. Определите в TStepWindow новое
булевское поле - тип основного окна с именем ButtonDown и обеспечьте его
инициализацию в TStepWindow.Unit значением False. Затем вы можете проверять
перед получением и освобождением контекста дисплея значение ButtonDown.
Приведем три метода обработки буксировки "мыши":
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
begin
InvalidateRect(HWindow, nil, True); if not ButtonDown then begin
ButtonDown := True; SetCapture(HWindow); DragDC := GetDC(HWindow); MoveTo(DragDC,
Msg.lParamLo, Msg.lParamHi);
end;
end;
procedure TStepWindow.WMMouseMove(var Msg: TMessage); begin
if ButtonDown then
LineTo(DragDC, Msg.lParamLo, MsglParamHi); end;
procedure TStepWindow.WMLButtonUp(var Msg: TMessage);
begin
if ButtonDown then
begin
ButtonDown := False;
ReleaseCapture;
ReleaseDC(HWindow, DragDC); end;
end;
B.Pascal 7 & Objects/OW - 50 -
Изображение точек и линий
В API Windows имеются графические функции MoveTo и LineTo, которые, соответственно,
перемещают текущую позицию рисования и рисуют линию до текущей позиции.
Для правильной работы функций требуется указание описателя контекста дисплея
DragDC. Нужно помнить о том, что вы рисуете не непосредственно в окне,
а в его контексте дисплея.
Перехват "мыши"
Передачу Windows соответствующих сообщений wm_MouseMove обеспечивают функции
SetCapture и ReleaseCapture. Например, если вы буксируете "мышь"
за пределы окна, Windows все равно будет посылать сообщения основному,
а не смежному с ним окну, в которое она попала. Перехват "мыши"
обеспечивает также поступление в ваше окно сообщения от "мыши",
так что оно будет знать о прекращении рисования даже если "мышь"
перемещается в другом окне.
Нужно изменить определение объекта для TStepWindow с заголовками метода
для WMMouseMove и WMLButtonUp:
procedure WMLButtonUp(var Msg: TMessage); virtual wm_First +
wm_LButtonUp;
procedure WMLMouseMove(var Msg: TMessage); virtual wm_First +
wm_LMouseMove;
Пример полученного исходного кода вы найдете в файле STEP03A.PAS.
B.Pascal 7 & Objects/OW - 51 -
Изменение размера пера
До сих пор вы могли рисовать только тонкие черные линии. Однако графические
программы традиционно позволяют изменять толщину изображаемых линий. При
этом вы изменяете на самом деле не толщину линии, а размер пера, используемого
для ее вычерчивания. Перья, также как кисти, шрифты и палитры, представляют
собой встроенные в контекст дисплея изобразительные средства. На данном
шаге вы узнаете, как установить в контексте дисплея новые изобразительные
средства, что даст программе Step возможность рисовать линии другой толщины.
Для реализации механизма выбора пользователем размера пера мы используем
диалоговое окно (типа TInputDialog). Это окно вида:
Steps
Введите новую толщину линии:
| 1 |
------------- -------------| OK | | Cancel |------------- -------------
Рис. 2.2 Задание новой толщины линии с помощью диалогового окна ввода.
Отслеживание размера пера
Чтобы изменить толщину изображаемых линий, вам нужно получить сначала
несколько более глубокое представление о графике Windows и о контексте
в частности.
Изобразительные средства
Для получения графики и текста в окне Windows использует несколько изобразительных
средств: перья, кисти и шрифты. Эти изобразительные средства представляют
собой элементы, хранимые в памяти Windows и не отличающиеся от видимых
элементов экрана, таких как окна и управляющие элементы. Ваша программа
может обращаться к изобразительным средствам с помощью описателей (как
это имеет место в случае окон). Так как ObjectWindows не использует для
представления изобразительных средств объекты, вашим программам не нужно
создавать их и удалять из памяти Windows при завершении работы с ними.
B.Pascal 7 & Objects/OW - 52 -
Примечание: В шаге 6 мы создадим объект, инкапсулирующий одно инструментальное
средство - перо.
Изобразительное средство можно рассматривать как кисть художника, а контекст
дисплея - как холст. Художник сначала создает изобразительные средства
(кисти) и получает контекст дисплея (холст). Затем художник выбирает соответствующее
изобразительное средство, используя в каждый момент одну из кистей. Аналогично,
программа Windows должна выбирать изобразительные средства в контексте
дисплея.
Используемые по умолчанию изобразительные средства
Итак, как же сделать, чтобы могли рисовать в своих окнах текста и линии,
не выбирая никаких изобразительных средств? Все контексты дисплея снабжены
набором используемых по умолчанию средств: тонким черным пером, твердой
черной кистью и системным шрифтом. На данном шаге мы выберем для рисования
в окне другое, более тонкое перо.
Получение пера нового размера
Сначала нужно обеспечить способ выбора нового размера пера. В простейшем
случае это можно сделать с помощью диалогового окна ввода модуля OStdDlgs.
Добавьте модуль OStdDlgs в оператор uses программы. Чтобы использовать
совместимые с Windows функции работы со строками, укажите также модуль
Strings. Начало программного файла должно выглядеть таким образом:
program Steps;
uses Strings, WinTypes, WinProcs, OWindow, OStdDlgs;
.
.
.
Выполнение диалогового окна ввода
Диалоговое окно ввода - это простое диалоговое окно, которое выводит подсказку
и возвращает одну введенную строку текста. Вы можете использовать его
без модификации TInputDialog или других методов.
Щелчок правой кнопкой "мыши" дает удобный способ вывода параметра
для изменения толщины пера. Давайте переопределим метод WMRButtonDown
для вывода нового диалогового окна ввода.
Так как диалоговое окно ввода появляется только на короткое время, а вся
обработка выполняется одним методом, вам нет необходимости определять
его как поле TStepWindows. Оно может существовать в виде локальной переменной
метода WMRButtonDown. Все построение и отмену объекта диалогового окна
вы можете выполнять в
B.Pascal 7 & Objects/OW - 53 -
рамках метода WMRButtonDowm.
Когда Init построит объект диалогового окна ввода, вы можете выполнить
его как режимное диалоговое окно, вызвав ExecDialog. ExecDialog проверяет
успешность выполнения конструктора Init и создает объект диалогового окна,
соответствующий элементу экрана, выполняя затем диалоговое окно. Обработка
для ExecDialog завершается только после того как пользователь закрыл диалог,
щелкнув "мышью" на командной кнопке OK (Подтверждение) или Cancel
(Отмена).
Если пользователь щелкнул "мышью" на командной кнопке OK, InputText
заполняется полученным от пользователя текстом, вызывая метод GetText
из TInputDialog. Так как вы запрашиваете номер толщины, возвращаемый текст
нужно преобразовать в число и передать его в вызове SetPenSize. Таким
образом, каждый раз, когда пользователь выбирает новую толщину линии,
старое перо удаляется и создается новое.
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
var
InputText: array[0..9] of Char;
NewSize, ErrorPos: Integer; begin
if not ButtonDown then
begin
Str(PenSize, InputText);
if Application^.ExecDialog(New(PInputDialog,
Init(@Self, 'Толщина линии',
'Введите новую толщину:', InputText,
SizeOf(InputText))) = id_Ok then begin
Val(InputText, NewSize, ErrorPos);
if ErrorPos = 0 then SetPenSize(NewSize); end;
end;
end.
Добавление полей объекта
Далее добавим в TStepWindow новое поле для хранения описателя пера, которое
вы будете использовать для рисования графики. В данной программе в каждый
момент времени вы можете рисовать и выводить на экран линии только одной
толщины. Соответствующее этой толщине перо хранится в новом поле TStepWindow
с именем ThePen. Вы напишете также метод SetPenSize, создающий новое перо
и удаляющий старое. Теперь описание объекта TStepWindow должно принять
следующий вид:
type
PStepWindow = ^TStepWindow;
TStepWindow = object(TWindow)
DragDC: HDC;
B.Pascal 7 & Objects/OW - 54 -
ButtonDown, HasChanged: Boolean;
ThePen: HPen;
PenSize: Integer;
constructor Init(AParent: PWindowsObject;
ATitle: PChar); destructor Done; virtual; function CanClopse: Boolean:
virtual; procedure WMLButtonDown(var Msg: TMessage); virtual
wm_First + wm_LButtonDown;
procedure WMLButtonUp(var Msg: TMessage); virtual
wm_First + wm_LButtonUp;
procedure WMMouseMove(var Msg: TMessage); virtual
wm_First + wm_LMouseMove;
procedure WMRButtonDown(var Msg: TMessage); virtual
wm_First + wm_RButtonDown;
procedure SetPenSize(NewSize: Integer); virtual;
end;
Инициализация полей
Чтобы инициализировать новые поля, вам нужно модифицировать конструктор
Init для установки пера и переопределить деструктор Done для его отмены.
Не забудьте вызвать в новых методах наследуемые методы:
constructor TStepWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
Inherited Init(AParent, ATitle);
ButtonDown := False;
HasChanged := False;
PenSize := 1;
ThePen := CreatePen(ps_Solid, Pensize, 0); end;
destructor TStepWindow.Done;
begin
DeleteObject(ThePen); inherited Done;
end;
Изображение линий
Теперь изменим метод WMLButtonDown для выбора текущего пера (ThePen) во
вновь полученном контексте дисплея. Аналогично MoveTo и MessageBox, SelectObject
является функцией API Windows.
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
begin
if not ButtonDown then
begin
ButtonDown := True;
SetCapture"(HWindow);
B.Pascal 7 & Objects/OW - 55 -
DragDC := GetDC(HWindow);
SelectObject(DragDC, ThePen);
MoveTo(DragDC, Msg.lParamLo, Msg.lParamHi); end;
end;
Указанные методы выбирают в контексте дисплея уже созданное перо. Однако
для создания пера нужно написать следующий вызываемый WMRButtonDown метод
SetPenSize:
procedure TStepWindow.SetPenSize(NewSize: Integer);
begin
DeleteObject(ThePen);
ThePen := Create(ps_Solid, NewSize, 0);
PenSize := NewSize; end;
Вызов функции Windows CreatePen - это один из способов создания пера Windows
заданной толщины. Описатель пера записывается в ThePen. Очень важным шагом
является удаление старого пера. Отсутствие такого шага приведет к неверному
использованию памяти Windows.
На шаге 5 и 6 вы создадите собственное диалоговое окно и объект пера и
используете их для более эффективного графического отображения.
B.Pascal 7 & Objects/OW - 56 -
Глава 3. Меню и диалоговые ресурсы
Большинство приложений Windows имеют в своих основных окнах меню, которые
предоставляют пользователю возможность выбора - например, команды File|Save,
File|Open и Help. В шаге 4 мы добавим в программу Steps строку меню. Ввод
пользователем данных и выбор параметров в программах Windows часто происходит
в диалоговых блоках. В шаге 5 в программу Steps будет добавлен диалоговый
блок.
Меню и диалоговые блоки объединены общим понятием ресурсов. Ресурсы -
это данные, хранимые в выполняемом файле, который описывает пользовательские
интерфейсные элементы приложений Windows. Ресурс не содержит фактического
меню или диалогового блока. Вместо этого он содержит информацию, необходимую
программе для создания конкретного диалогового блока или меню.
Ресурсы для программы проще всего создавать с помощью редакторов ресурсов,
таких как Resource Workshop (пакет разработчика ресурсов) фирмы Borland.
Подробно о создании и редактировании ресурсов рассказывается в "Руководстве
пользователя по пакету разработчика ресурсов".
Шаг 4: Добавление строки меню
Step 1: Basic AppStep 2: TextStep 3: Lines Step 4: Menu Step 5: About
BoxStep 6: PensStep 7: PaintingStep 8: StreamsStep 9: PrintingStep 10:
PaletteStep 11: BWCCStep 12: Custom ctrls
В оконной среде выбор пункта меню относится к той же категории, что и
щелчок кнопкой "мыши". И то, и другое - это пользовательские
события. Ответ на выбор пункта меню аналогичен реакции на другие пользовательские
события. В данном разделе описываются шаги, необходимые для добавления
в приложение меню.
* Проектирование меню как ресурса меню.
* Определение констант меню во включаемом файле.
* Загрузка файла ресурса из программы.
B.Pascal 7 & Objects/OW - 57 -
* Загрузка ресурса меню в объект основного окна.
* Определение реакции на выбор в меню.
Меню прикладной программы - это не отдельный объект, а атрибут основного
окна. Все оконные объекты имеют набор атрибутов, записанных в поле записи
Attr объекта. В поле Menu записи Attr хранится не описатель меню, а меню.
Чтобы установить атрибут меню, вы должны переопределить конструктор своего
типа окна TStepWindow.
Ресурсы меню
Определение ресурсов меню не является частью исходного кода программы.
Вместо этого существует ресурс, содержит текст пунктов меню и структуру
элементов верхнего уровня и их подсистем. Для проектирования меню и других
ресурсов, таких как диалоговые блоки, пиктограммы и битовые массивы, вы
можете использовать пакет разработчика ресурсов Resource Workshop.
Определение идентификаторов ресурса
Приложение обращается к присоединенным к нему ресурсам по идентификатору
ресурса. Этот идентификатор представляет собой целое значение, например,
100, или целочисленную константу, такую как MyMenu. Кроме того, приложение
отличает один выбор меню от другого по идентификатору, связанному с элементом
меню.
Определение констант меню
Чтобы сделать программу более читаемой, замените идентификаторы меню константами,
определяемыми во включаемом файле. При создании своего ресурса меню с
помощью Resource Workshop или компилятора ресурсов вы можете включить
те же константы и использовать те же идентификаторы, которые вы используете
для доступа к ресурсу к своей программе. Константы меню для программы
Steps определены в файле STEPS.INC:
const
cm_FilePrint = 105;
cm_FileSetup = 107;
cm_Pen = 200;
cm_About = 201;
cm_PalShow = 301;
cm_PalHide = 302;
Заметим, что число элементов меню в файле STEPS.INC не определено. Это
связано с тем, что ObjectWindows в файле IWINDOWS.INC определяет для вас
некоторые общие команды меню, включая cm_FileOpen, cm_FileNew, cm_FileSave
и cm_FileSaveAs.
B.Pascal 7 & Objects/OW - 58 -
Включение файлов ресурсов
Чтобы продолжить работу с программой Steps, используйте пакет разработчика
ресурсов или компилятор ресурсов для создания ресурса меню и сохраните
его в файле с расширением .RES - STEPS.RES. Формат файла ресурса в исходном
виде вы можете посмотреть в файле STEPS.RC. Вы можете также использовать
файл STEPS.RES, который можно найти на дистрибутивных дисках. Имея файл
STEPS.RES, вы можете включить его с помощью директивы компилятора $R:
$R STEPS.RES
Директива компилятора $R в конце компиляции и компоновки автоматически
добавляет заданный файл ресурса к выполняемому файлу. Ресурсы можно добавить
или удалить из выполняемых файлов, а существующие ресурсы можно модифицировать.
Примечание: О модификации ресурсов, уже скомпонованных с выполняемыми
файлами, рассказывается в "Руководстве пользователя по пакету разработчика
ресурсов".
B.Pascal 7 & Objects/OW - 59 -
На Рис. 3.1 показан внешний вид этого меню (идентификатор ресурса 100).
Оно включает в себя пункты File (Файл), Options (Параметры) и Palette
(Палитра), а меню File содержит элементы New (Новый), Open (Открытие),
Save (Сохранение), Save As (Сохранение под именем), Print (Печать), Printer
Setup (Установка принтера) и Exit (Выход). Элементы верхнего уровня, у
которых есть подэлементы, не имеют идентификаторов меню, а их вывод не
вызывает никаких действий кроме вывода подэлементов.
Примечание: Не путайте идентификатор ресурса меню с идентификаторами меню
отдельных элементов (пунктов) меню.
Steps
File Options Palette
New |Open... |Save |Save as... |
Print... |Printer Setup... |
Exit |
Рис. 3.1 Программа Steps с ресурсом меню.
B.Pascal 7 & Objects/OW - 60 -
Загрузка ресурса меню
Получить ресурс меню можно с помощью вызова функции Windows LoadMenu:
LoadMenu(HInstance, MakeIntResource(100));
MakeIntResource(100) приводит число 100 к ссылочному типу PChar, представляющему
собой указатель на массив символов. Функции Windows, воспринимающие в
качестве аргументов строки, требуют, чтобы они имели тип PChar. Имея дело
с ресурсами, Windows ожидает, что целые числа должны быть представлены
в виде PChar, поэтому если вы хотите обратиться к ресурсу, имеющему числовой
идентификатор, нужно преобразовать его тип с помощью MakeIntResource.
Примечание: Для использования типа PChar требуется установка $X+ (по умолчанию).
В качестве альтернативы идентификатор меню может иметь символьный идентификатор,
например, 'SAMPLE_MENU'. В этом случае загрузить ресурс меню можно следующим
образом:
LoadMenu(HInstance, 'SAMPLE_MENU');
Вот как это делает TStepWindow.Init (заметим, что первое, что он делает
- это вызов конструктора Init, наследуемого из TWindow, для выполнения
инициализации, необходимой для всех оконных объектов):
constructor TStepWindow(AParent: PWindowObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
Attr.Menu := LoadMenu(HInstance, MakeIntResource(100));
BottomDown := False;
HasChanged := False; end;
Теперь при выводе основного окна оно имеет рабочее меню, показанное на
Рис. 1.3. Однако, чтобы при выборе элементов меню выполнялись какие-либо
действия, вы должны перехватывать сообщения меню и реагировать на них.
Если вы не определили реакцию на команду меню, то можете выбирать элемент
меню, но при этом ничего не происходит.
B.Pascal 7 & Objects/OW - 61 -
Перехват сообщений меню
Когда пользователь выбирает элемент меню, окно, к которому присоединено
меню, получает командное сообщение Windows. ObjectWindows обрабатывает
и диспетчеризует эти сообщения wm_Command аналогично другим сообщениям,
но облегчает для вас работу со специальными командами.
Одним из параметров сообщения wm_Command является сама команда (номер,
соответствующий идентификатору меню выбранного элемента). Вместо вызова
метода WMCommand и возложения на вас решения, что делать с каждой возможной
командой, ObjectWindows вызывает основанные на конкретных командах методы.
Чтобы обработать эти сообщения, вы можете определить методы для объектного
типа TStepWindow, используя специальное расширение:
procedure CMFileNew(var Msg: TMessage);
virtual cm_First + cm_FileNew;
где cm_First - это константа ObjectWindows, определяющая начало
диапазона констант для команд, а cm_FileNew - это желаемая команда меню.
Это означает, что все элементы меню должны иметь уникальные идентификаторы
(если только не предполагается реагировать на них одинаковым образом).
Примечание: О диапазонах сообщений и смещениях рассказывается в Главе
16.
Не путайте основанный на cm_First динамический индекс метода с индексом,
соответствующим поступающему сообщению Windows (основанному на wm_First).
cm_First - это специальное смещение, используемое только для определения
методов реакции для команд меню и командных клавиш.
B.Pascal 7 & Objects/OW - 62 -
Определение методов реакции на команду
Теперь вы можете определить все методы реакции на команды:
procedure CMFileNew(var Msg: TMessage);
virtual cm_First + cm_FileNew;
procedure CMFileOpen(var Msg: TMessage);
virtual cm_First + cm_FileOpen;
procedure CMFileSave(var Msg: TMessage);
virtual cm_First + cm_FileSave;
procedure CMFileSaveAs(var Msg: TMessage);
virtual cm_First + cm_FileSaveAs;
procedure CMFilePrint(var Msg: TMessage);
virtual cm_First + cm_FilePrint;
procedure CMFileSetup(var Msg: TMessage);
virtual cm_First + cm_FileSetup;
Определять процедуру CMExit не требуется, поскольку
TWindowsObject уже определяет завершающую программу процедуру, которая
вызывается при поступлении в основное окно сообщения cm_Exit.
Связывание клавиш с командами
Методы реакции на команды не связываются с конкретным элементом меню -
они привязаны к конкретной команде. Объекту не важно, откуда поступила
команда. Он знает только, что что-то вызвало данное командное сообщение.
Таким образом, у вас есть несколько способов генерации команды. Обычно
для этого применяются оперативные клавиши, называемые командными клавишами.
Командные клавиши определяются в ресурсах аналогично меню, но они намного
проще. Ресурс командной клавиши - это таблица нажатий клавиш и команд,
которые они генерируют. О создании ресурсов для командных клавиш рассказывается
в "Руководстве пользователя по пакету разработчика ресурсов".
Каждая прикладная программа может иметь только один набор командных клавиш.
Чтобы загрузить в программу ресурс командных клавиш, переопределите метод
InitInstance:
procedure TMyApplication.InitInstance;
begin
inherited InitInstance;
HaccTable := LoadAccelerators(HInstance, 'ShortCuts'); end;
Командные клавиши 'ShortCuts' в STEPS.RES связывают знакомые вам по IDE
функциональные клавиши с аналогичными функциями программы Steps. Например,
клавиша F3 генерирует команду cm_FileOpen.
B.Pascal 7 & Objects/OW - 63 -
Реакция на команды меню
Теперь для каждого выбора в меню у вас есть метод, который будет вызываться
в ответ на соответствующую команду. Выбор команды File|Print вызывает
ваш метод CMFilePrint. Пока вызовем просто окно сообщения:
procedure TStepWindow.CMFilePrint(var sg: TMessage);
begin
Message(HWindow, 'Средство не реализовано',
'Печать файла', mb_Ok);
end;
На Рис. 3.2 показана реакция программы Steps на выбор команды File|Print.
Steps
File Options Palette
| = Печать файла |
| || Средство не реализовано || || ------------- || | OK | || -------------
|
Рис. 3.2 Программа Steps реагирует на команду File|Print.
Для CMFileOpen, CMFileSave, CMFileSaveAs и CMFileSetup напишите фиктивные
методы, аналогичные CMFilePrint. Позднее вы перепишете данные методы для
выполнения осмысленных действий.
Теперь, очистив окно, вы можете реагировать на выбор команды меню File|New
более интересным образом. Добавьте следующий метод CMFileNew:
procedure TStepWindow.CMFileNew(var Msg: TMessage);
begin
InvalidateRect(HWindow, nil, True);
B.Pascal 7 & Objects/OW - 64 -
end;
InvalidateRect выполняет принудительное повторное отображение окна. Полный
исходный код программы Steps для данного этапа содержится в файле STEP04A.PAS.
Добавление диалогового блока
Диалоговый блок аналогичен всплывающему окну, но обычно оно сохраняется
на экране в течении короткого периода и выполняет одну конкретную задачу,
связанную с вводом-выводом, такую как выбор принтера или настройка страницы
документа. Здесь мы добавим в программу Steps диалоговое окно для открытия
и сохранения файлов.
Файловое диалоговое окно, как одно из диалоговых окон ObjectWindows, определено
с типом TFileDialog. Файловое диалоговое окно полезно использовать в любой
ситуации, когда вы запрашиваете у пользователя для сохранения и загрузки
выбор файла на диске. Например, редактор текстов может использовать диалоговое
окно для открытия и сохранения документов.
B.Pascal 7 & Objects/OW - 65 -
Вы будете выводить файловое диалоговое окно в ответ на выбор пользователем
команды File|Open или File|Save As. Файловое диалоговое окно заменяет
окно сообщения "Средство не реализовано". В шаге 8 оно будет
приспособлено для некоторых реальных файлов, а также сохранения и открытия
их для записи и считывания реальных данных. Пока просто выведем диалоговые
окна. Вид файлового диалогового окна показан на Рис. 3.3.
Steps
File Options Palette
-------------------- ------------Имя файла: | *.pts | | OK | --------------------
------------
Каталог: a:\ | Cancel |
Файлы: Каталоги:
a]b]c]d]e]f]g]h]i]
Рис. 3.3 Программа Steps с диалоговым блоком File Open.
Добавление к программе Steps файлового диалогового блока требует трех
шагов:
* Добавление поля объекта, содержащего имя файла.
* Модификация конструктора объекта для инициализации файла.
* Выполнение диалогового блока.
B.Pascal 7 & Objects/OW - 66 -
Добавление поля объекта
Вместо хранения всего объекта файлового диалогового окна в виде поля его
порождающего окна, вам следует построить новый объект файлового диалогового
окна, когда он потребуется. Вместо данных, которые вам следует хранить
вместо данных этого диалогового окна, вы должны сохранять имя и маску
файла. На практике хорошо придерживаться следующего: вместо хранения всех
объектов, которые вам могут не потребоваться, храните просто данные, необходимые
для инициализации объектов, когда они потребуются.
Построение файлового диалогового блока требует трех параметров: порождающего
окна, шаблона ресурса и имя или маску файла (в зависимости от того, используется
файловое окно для открытия или закрытия файла). Шаблон ресурса определяет,
какое из стандартных файловых диалоговых окон вы хотите использовать.
Стандартные файловые диалоговые ресурсы определяются идентификаторами
ресурсов sd_FileOpen и sd_FileSave. Параметр имени файла используется
для передачи используемой по умолчанию маски файла диалогу открытия файла
(а также для возврата выбранного имени файла) и для передачи используемого
по умолчанию имени для сохранения файла.
Параметр шаблона ресурса определяет, будет ли файловый диалоговый блок
использоваться для открытия или для сохранения файла. Если диалоговый
ресурс имеет блок списка файлов с идентификатором управляющего элемента
id_FList, диалоговый блок используется для открытия файлов; отсутствие
такого блока списка указывает на диалоговое окно для сохранения файлов.
Определение типа TStepsWindow должно теперь выглядеть следующим образом:
TStepWindow = object(TWindow)
.
.
.
FileName: array[0...fsPathName] of Char;
.
.
.
Примечание: Для работы с константой fsPathName нужно использовать модуль
WinDos.
Модификация конструктора
Для создания экземпляра объекта справочного окна вы можете использовать
конструктор Init типа TStepWindow. Теперь вам потребуется добавить к нему
код для инициализации FileName:
StrCopy(FileName, '*.PTS');
B.Pascal 7 & Objects/OW - 67 -
Расширение .PTS используется для файлов, содержащих точки вашего графического
изображения.
Выполнение диалогового блока
В зависимости от переданного конструктору диалогового блока параметра
шаблона ресурса диалоговый блок может поддерживать открытие или сохранение
файла. Каждый параметр, при создании диалогового блока, аналогичен показанному
на Рис. 3.3. Между диалогами открытия или закрытия файла имеются два различия:
диалог открытия содержит список файлов в текущем каталоге, соответствующий
текущей маске файла, а в диалоге сохранения в поле редактирования управляющего
диалогового элемента выводится имя текущего файла, но список файлов отсутствует.
CMFileOpen и CMFileSaveAs следует переписать следующим образом:
procedure TStepWindow.CMFileOpen(var Msg: TMessage);
begin
if Application^.ExecDialog(New(PFileDialog,
Init(@Self, PChar(sd_FileOpen), FileName))) = id_Ok then MessageBox(HWindow,
FileName, 'Открыть файл:',
mb_Ok);
end;
procedure TStepWindow.CMFileSaveAs(var Msg: TMessage);
begin
if Application^.ExecDialog(New(PFileDialog,
Init(@Self, PChar(sd_FileSave), FileName))) = id_Ok then MessageBox(HWindow,
FileName, 'Сохранить файл:',
mb_Ok);
end;
Заметим, что при выполнении файлового диалогового окна используется тот
же метод ExecDialog, который вы вызывали для выполнения диалогового окна
ввода в шаге 3. С помощью метода ExecDialog выполняются все режимные диалоговые
окна в приложении.
Полный исходный код программы Steps для данного шага вы можете найти в
файле STEP04B.PAS.
B.Pascal 7 & Objects/OW - 68 -
Шаг 5: Добавление диалогового блока
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: Menu Step 5: About Box
Step 6: PensStep 7: PaintingStep 8: StreamsStep 9: PrintingStep 10: PaletteStep
11: BWCCStep 12: Custom ctrls
До сих пор в программе Steps использовались два очень простых диалоговых
блока: окно сообщений (в методе CanClose) и диалоговый блок ввода для
изменения размера пера. Эти диалоговые блоки удобно применять для простых
задач, но в программах обычно требуются более сложные и ориентированные
на задачу взаимодействия с пользователем. В таких случаях вы можете разработать
собственные диалоговые блоки.
Как и меню, диалоговые блоки обычно создаются из описания, сохраненного
в ресурсе. Для сложных диалоговых блоков это значительно быстрее, чем
индивидуальное создание каждого элемента отдельного окна. Однако в отличие
от меню, поскольку программы должны взаимодействовать с диалоговыми окнами
более разнообразными и сложными путями, ObjectWindows использует для представления
диалогового блока объект.
Создание диалогового блока из ресурса требует следующих шагов:
* Создание ресурса диалогового блока.
* Построение объекта диалогового блока.
* Выполнение диалогового блока.
B.Pascal 7 & Objects/OW - 69 -
Создание ресурсов диалогового блока
Проектировать ресурсы диалогового блока можно несколькими способами, используя
пакет разработчика ресурса Resource Workshop или компилятор ресурсов.
Диалоговый блок (блок диалога) - это специализированное окно с рамкой,
содержащее один или более управляющих элементов (командные кнопки, блоки
списка и пиктограммы). Ваша прикладная программа не знает о том, как выглядят
управляющие элементы и как они позиционированы; она знает только о типе
управляющих элементах и их идентификаторах.
Примечание: Не забывайте, что ресурс - это просто некое описание того,
что будет создавать ваша программа.
Идентификаторы управляющих элементов
Аналогично элементам в ресурсе меню, каждый управляющий элемент в ресурсе
диалогового блока имеет идентификатор, который прикладная программа использует
для определения того, с каким управляющим элементом нужно взаимодействовать.
Для статических элементов, с которыми ваша прикладная программа не взаимодействует
(статический текст или битовые массивы) уникальные идентификаторы не требуются,
поэтому они обычно имеют идентификатор -1.
Обычно, если вашей прикладной программе требуется доступ к конкретному
управляющему элементу, вы присваиваете ему идентификатор-константу, так
что и ваша программа, и компилятор ресурсов могут использовать в качестве
идентификатора одно и то же символьное имя. Такие идентификаторы-константы
следует определять во включаемом файле или в модуле, содержащем только
описания-константы. При создании или редактировании ваших ресурсов пакет
разработчика ресурсов автоматически управляет такими файлами.
B.Pascal 7 & Objects/OW - 70 -
Построение объекта диалогового блока
После того как ресурс диалогового окна будет определен, ваша программа
может использовать его для создания и выполнения диалогового окна. Диалоговые
блоки выводятся обычно как дочерние окна основного окна приложения, но
они создаются несколько по-другому, чем обычные окна.
Конструктор объекта диалогового блока выглядит как конструктор оконного
объекта, воспринимающий два параметра. В обоих случаях первый параметр
- это указатель на объект порождающего окна. Второй параметр (PChar) определяет
заголовок объекта окна. Однако для объекта диалогового блока в качестве
шаблона диалогового блока используется имя диалогового ресурса.
Файл ресурса для программы Steps определяет диалоговый блок с именем 'ABOUTBOX',
которое вы можете использовать в качестве окна About box, показанного
на Рис. 3.4. Построение объекта диалогового блока из данного ресурса выглядит
следующим образом:
New(PDialog, Init(@Self, 'ABOUTBOX'));
About Steps
| || ObjectWindows tutorial program || || Copiright (C) 1992 || Borland
International Inc. || All Rights Reserved |
OK
---------------------------------------------------
Рис. 3.4 Окно About Box для программы Steps.
Выполнение диалогового блока
Чтобы выполнить специализированный диалоговый блок, используйте тот же
метод ExecDialog, который вы уже использовали для других диалоговых блоков:
Application^.ExecDialog(New(PDialog,Init(@Self,'ABOUTBOX')));
Естественно, нужно определить команду для вывода диалогового
B.Pascal 7 & Objects/OW - 71 -
блока About box; Steps использует сообщение cm_About, генерируемое выбором
меню Optrions|About. Теперь такой вид реакции на команду должен быть вам
достаточно знаком (см. файл STEP05.PAS):
type
TStepWindow = object(TWindow)
.
.
.
procedure CMAbout(var Msg: TMessage);
virtual cm_First + cm_About;
end;
procedure TStepWindow.CMAbout(var Msg: TMessage);
begin
Application^.ExecDialog(New(PDialog, Init(@Self, 'ABOUTBOX')));
end;
В шаге 6 мы создадим более сложное диалоговое окно с несколькими управляющими
элементами.
B.Pascal 7 & Objects/OW - 72 -
Режимные и безрежимные диалоговые блоки
После выполнения окна с помощью ExecDialog диалоговый блок становится
режимным. Это означает, что программа работает с этим блоком до его закрытия.
Пока активно это окно, все получаемые программой сообщения поступают в
него. Такой диалоговый блок называется режимным окном приложения, поскольку
оно режимное только по отношению к выполняющему его приложению. Существуют
также системные режимные диалоговые блоки, которые приостанавливают всю
работу приложения, пока блок не будет закрыт. Такие блоки и окна используются
редко, и применять их следует только в том случае, если при работе других
приложений могут возникнуть проблемы.
Иногда желательно получить диалоговый блок, сохраняющийся при работе других
частей программы. Такой диалоговый блок работает почти как обычное окно,
но не является режимным, и потому носит название безрежимного. О создании
безрежимных диалоговых блоков рассказывается в Главе 11 "Объекты
диалоговых блоков".
B.Pascal 7 & Objects/OW - 73 -
Глава 4. Работа с диалоговым блоком
Теперь, когда вы оснастили программу Steps созданным из ресурса диалоговым
блоком, нужно научиться взаимодействовать с этим диалоговым блоком. Сначала
вы создадите объект, инкапсулирующий все характеристики окна пера, затем
используете диалоговый блок для установки и изменения этих характеристик.
В данной главе описаны следующие шаги:
* Определение объекта пера.
* Создание сложного диалогового блока.
* Добавление управляющих объектов.
* Создание буфера передачи.
* Выполнение диалогового блока.
* Чтение результатов.
Шаг 6: Изменение атрибутов пера
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: MenuStep 5: About Box
Step 6: Pens Step 7: PaintingStep 8: StreamsStep 9: PrintingStep 10: PaletteStep
11: BWCCStep 12: Custom ctrls
Данный шаг охватывает ряд тем, касающихся изобразительных средств Windows,
особенно перьевых средств, применяемых для изображения линий. Перья Windows
имеют три отдельных атрибута: стиль, ширину и цвет.
Первая часть данного шага - создание объекта для представления пера не
является абсолютно необходимой, но позволяет вашему окну работать с пером
как единой сущностью, а не отслеживать отдельно все атрибуты перьев. Инкапсулируя
перо, вы можете также избежать необходимости иметь дело с некоторыми повторяющимися
деталями использования инструментальных средств GDI, аналогично тому,
как объекты окон ObjectWindows предохраняют вас от мелких де-
B.Pascal 7 & Objects/OW - 74 -
талей, связанных с созданием окна.
Создание объекта пера
Хотя Windows ссылается на свои изобразительные средства как на "объекты"
(отсюда и имена типа SelectObject и DeleteObject), они не являются объектами
в истинном объектно-ориентированном смысле, так как не используют наследование
и полиморфизм. Перо на самом деле представляет собой просто группу из
трех характеристик отображения, на которые Windows ссылается при изображении
линии. Эти характеристики являются просто свойствами контекста дисплея,
но полезно рассматривать их, как встроенные в перо.
Характеристики пера
Три характеристики пера - это его стиль, размер и цвет. В шаге 3 вы изменяли
размер пера и отслеживали текущий размер пера в поле объекта окна. Вместо
реализации трех отдельных полей для отслеживания характеристик пера вы
можете инкапсулировать их в единый объект TPen. Описание TPen имеет следующий
вид:
type
PPen = ^TPen;
TPen = object(TObject)
Width, Style: Integer;
Color: Longint;
constructor Init(AStyle, AWidth: Integer;
AColor: Longint); constructor Load(var S: TStream); procedure ChangePen;
procedure Delete; procedure Select(ADC: HDC);
procedure SetAttributes(AStyle, AWidth: Integer;
AColor: Longint); procedure Store(var S: TStream);
private
PenHandle, OldPen: HPen;
TheDC: HDC;
PenData: TPenData; end;
Примечание: Большую часть исходного кода из данной главы вы можете найти
в файле PEN.PAS. Для использования модуля Pen в STEP06A.PAS и STEP06B.PAS
нужно внести минимальные изменения.
Примечание: Тип TPen определен в модуле Pen.
Конструктор Init создает новый объект пера с заданным стилем, размером
и цветом. SetAttributes изменяет атрибуты уже созданного объекта пера.
ChangePen выводит диалоговое окно, позволяющее пользователю задать атрибуты
пера. Load и Store позволяют
B.Pascal 7 & Objects/OW - 75 -
сохранять объекты пера в потоке.
Выбор и удаление объектов пера
Наиболее интересную работу выполняют процедуры Select и Delete. Select
создает изобразительное средство Windows на основе характеристик, записанных
в полях атрибутов. Вместо того, чтобы вызывать в графической программе
для создания пера, получения его описателя, выбора пера в контексте дисплея,
использования пера и его удаления функцию API Windows, вы строите объект
пера, а затем можете его использовать, выделять и удалять.
Метод Delete отменяет описатель пера, освобождая ресурс для Windows. Select
проверяет, имеется ли уже выделенное перо, и перед созданием и выбором
нового отменяет существующее перо. Это полезно использовать, если это
же перо предполагается применять повторно, так что вам не понадобиться
вызывать Delete при каждом использовании пера. С другой стороны, в шаге
7 вы увидите, как можно сохранять нарисованные линии, и каждая линия будет
иметь свой собственный объект пера. Если бы каждый объект пера создавался
и сохранялся в пере Windows, Windows скоро исчерпала бы ресурсы. Поэтому
важно непосредственно после использования пера вызывать для его отмены
метод Delete.
Основное достоинство TPen в том, что вам не нужно больше беспокоиться
о получении, сохранении и удалении объекта пера. TPen имеет два частных
поля, в одном их которых записывается описатель пера. Объект пера отслеживает
описатель и взаимодействия с Windows, а ваша программа просто имеет дело
с объектом. Другое частное поле, PenData, содержит используемый на этом
шаге буфер передачи.
Файл STEP06A.PAS содержит код программы Steps, модифицированный для использования
объекта TPen в модуле Pen. В основном изменения невелики (например, поле
ThePen изменяет тип с HPen на PPen, а метод SetPenSize заменяется вызовом
метода SetPenAttributes объекта пера, поскольку объект пера может управлять
цветом и стилем наряду с размером).
B.Pascal 7 & Objects/OW - 76 -
Создание сложного диалогового блока
До сих пор вы использовали достаточно простой диалоговый блок (см. блок
About Box в шаге 5). Особенно полезными становятся диалоговые блоки, когда
вы можете устанавливать и считывать значения их управляющих элементов.
В модуле Pen определяется более сложный ресурс диалогового блока с именем
'PenDlg', который дает вам возможность изменения атрибутов только что
определенного объекта пера. Этот диалоговый блок показан на Рис. 4.1.
Set Pen Attributes
-Color----------(*) Black( ) Purple( ) Blue( ) Cyan( ) Green( ) Yellow(
) Red( ) White -Style-----------(*) Solid( ) Dash( ) Dot( ) DashDot( )
DasDotDot( ) Null
Width: 1
| OK | | Cancel |
Рис. 4.1 Диалоговый блок с изменением атрибутов пера.
Set Pen Attributes - установка атрибутов пера; Color - цвет; Black - черный;
Purple - фиолетовый; Blue - голубой; Cyan - бирюзовый; Green - зеленый;
Yellow - желтый; Red - красный; White - белый; Style - стиль; Solid -
непрерывная линия; Dash - пунктир; Dot - точки; DashDot - точки и тире;
DasDotDot - тире и две точки; Null - пусто; Width - ширина; OK - подтверждение;
Cancel - отмена.
Построение объекта из ресурса 'PenDlg' выполняется также, как это делается
для окна About Box (за исключением порождающего окна). Поскольку диалоговый
блок атрибута пера выполняется из объекта TPen, а не из оконного объекта,
вы не можете в качестве порождающего окна использовать @Self. Вместо этого
TPen присоединяет диалоговый блок к одному из окон, о присутствии которых
известно заранее - основному окну приложения:
procedure TPent.ChangePen;
B.Pascal 7 & Objects/OW - 77 -
var PenDlg: PPenDialog;
begin
.
.
.
PenDlg := New(PPenDialog, Init(Application^.MainWindow,
'PenDlg'));
.
.
.
end;
Другим важным отличием является то, что на этот раз вы имеете новый производный
объектный тип TPenDialog. Так как окно About box не использует ничего,
кроме назначенного по умолчанию поведения диалогового окна, инкапсулированного
в TDialog, вам не требуется создавать для него новый объектный тип. Однако
диалог атрибутов пера отличается более сложным поведением и требует настройки
объекта.
Приведем определение TPenDialog из модуля Pen:
type
PPenDialog = ^TPenDialog;
TPenDialog = object(TDialog);
constructor Init(AParent: PWindowsObject; AName;
PChar); end;
constructor TPenDialog.Init(AParent: PWindowsObject;
AName: PChar; var
AControl: PRadioButton; i: Integer;
begin
inherited Init(AParent, AName);
AControl := New(PRadioButton, InitResource(@Self,
1100 + i)); for i := 0 to 5 do
AControl := New(PRadioButton, InitResource(@Self,
1200 + i)); end;
Построенные в TPenDialog управляющие объекты поясняются в следующем разделе.
Управляющие объекты
Если вашей программе требуется непосредственно взаимодействовать с управляющими
объектами в диалоговом окне (например, чтобы поместить элементы в блок
списка или определить выбор кнопки с независимой фиксацией), с этими управляющими
элементами по-
B.Pascal 7 & Objects/OW - 78 -
лезно связать объекты. Тогда вы сможете управлять этими элементами также,
как любыми другими объектами в программе.
Использование интерфейсных объектов
При "обычном" программировании в Windows (то есть без ObjectWindows),
ваша прикладная программа должна взаимодействовать с каждым элементом
экрана через функции API Windows. Как вы уже видели, ObjectWindows облегчает
создание и управление диалоговыми блоками, изолируя вас от Windows путем
максимально возможного использования для представления элементов экрана
объектов. Эти интерфейсные объекты также значительно облегчают взаимодействие
с управляющими элементами в диалоговых блоках.
Примечание: Интерфейсные объекты описываются в Главе 9, а управляющие
объекты описываются, в частности, в Главе
12.
Если вам не требуются управляющие объекты, вы все равно сможете взаимодействовать
с управляющими элементами, но это приведет к необходимости частого вызова
функций API Windows, передачи управляющим элементам сообщений и интерпретации
результатов. ObjectWindows значительно облегчает эту задачу, инкапсулируя
поведение каждого управляющего элемента в объекте. Передаются и обрабатываются
те же сообщения, но ObjectWindows заботится обо всех деталях.
Связь объекта с созданными из ресурса управляющим элементом достаточно
проста: внутри конструктора объекта диалогового блока вы строите объекты
для любых управляющих элементов, которыми хотите манипулировать. Однако
вместо использования для построения управляющих объектов конструктора
Init применяется InitResource.
B.Pascal 7 & Objects/OW - 79 -
Конструктор InitResource
Когда вы на этапе выполнения создаете управляющий объект (в противоположность
созданию его из ресурса), вам нужно задать расположение, размер и начальное
значение (или состояние) управляющего элемента, а также указать, какой
объект является порождающим. Все эти элементы передаются в качестве параметров
конструктору Init объекта.
Связь объекта с управляющим элементом из ресурса намного проще, так как
такая информация как расположение и размер, определяется ресурсом. Требуется
передать конструктору InitResource только порождающий объект и идентификатор
управляющего элемента. Так как управляющие объекты обычно строятся внутри
конструктора их порождающих диалоговых блоков, указатель порождающего
объекта почти всегда равен @Self.
Как показано в приведенном выше примере, диалог пера модуля Pen связывает
объекты с их управляющими элементами редактирования (для задания размера
пера) и обоими наборами кнопок с зависимой фиксацией (для задания цвета
и стиля).
Заметим, что все управляющие объекты строятся и присваиваются одной и
той же локальной переменной AControl. Вашей программе не придется взаимодействовать
ни с одним из этих управляющих элементов непосредственно, так как пока
выполняется режимный диалоговый блок, остальная часть программы не активна.
InitResource к списку дочерних окон диалогового блока, чтобы обеспечить
очистку и уничтожение элементов экрана вместе с диалоговым окном.
В общем случае нет необходимости присваивать дочерним окнам в режимных
диалоговых блоках поля объекта. Однако в шаге 11 вы увидите, как можно
сохранять указатели на управляющие элементы объектов безрежимного окна,
что облегчает работу с ними.
Создание буфера передачи
Теперь, когда в диалоговом блоке у вас есть объект, связанный с управляющими
элементами диалогового окна, необходим способ для установки и чтения их
значений. Это делается с помощью буфера передачи. Буфер передачи - это
запись, которая содержит одно поле для каждого управляющего элемента в
диалоговом окне, в который или из которого происходит передача.
Например, диалоговый блок, созданный в шаге 6, имеет поле редактирования
и четырнадцать кнопок с зависимой фиксацией. В управляющий элемент редактирования
требуется передавать строку, а каждая кнопка с зависимой фиксацией получает
значение Word, указывающее на его выбор. Модуль Pen определяет тип записи,
передаваемый TPenDialogs и из него:
B.Pascal 7 & Objects/OW - 80 -
type
TPenData = record
XWidth: array[0..6] of Char;
ColorArray: arra[0..7] of Word;
StyleArray: array[0..5] of Word; end;
Вы можете также управлять кнопками с независимой фиксацией, используя
14 отдельных полей или один массив из 14 значений типа Word; передаваемые
данные будут теми же. Однако, так как ваша прикладная программа будет
интерпретировать их как две группы из 8 и 6 кнопок соответственно, удобно
задать поле для каждой группы.
Присваивание буфера
Каждый потомок TWindowsObject имеет поле TransferBuffer. Когда вы хотите
передать данные в диалоговое окно, нужно задать объект TransferBuffer
диалогового блока, указывающий на запись передачи:
PenDlg := New(PPenDialog, Init(Application^.MainWindow,
'PenDlg')); PenDlg^.TransferBuffer := @PenData;
Если ваши программы создают объекты диалогового окна динамически, убедитесь,
что они каждый раз назначают буфер передачи. TransferBuffer по умолчанию
имеет значение nil. Это означает, что данные не переданы.
Заполнение буфера
Перед фактической передачей данных в диалоговое окно, вам нужно установить
значение полей в буфере передачи. Перед выводом диалогового окна пера
это делает TPen.ChangePen:
procedure TPen.ChangePen;
var
PenDlg: PPenDialog;
TempWidth, ErrorPos: Integer; begin
SetColorAttr(PenDate, Color);
SetStyle(PenDate, Style);
wvsprintf(PenDialog, Init(Application^.MainWindows,
'PenDlg'));
PenDlg^.TransferBuffer := @PenData;
if Application^.ExecDialog(PenDlg) <> id_Cancel then
begin
Val(PenData.XWidth, TempWidth, ErrorPos); if ErrorPos = 0 then
SetAttributes(SetStyle(PenData), TempWidth, GetColorAttr(PenData));
end;
B.Pascal 7 & Objects/OW - 81 -
end;
SetColorAttr и SetStyle используют то преимущество, что буфер передачи
задает кнопки с зависимой фиксацией в виде массива значений Word. SetStyle,
например, выглядит следующим образом:
procedure SetStyle(var ARec: TPenData; AStyle: Integer);
var i: Integer;
begin
for i := 0 to 5 do
if = AStyle then ARec.StyleArray[i] := bf_Checked
else ARec.StyleArray[i] := bf_Unchecked;
end;
Примечание: SetColorAttr выполняет то же назначение, что и ColorArray.
bf_Checked и bf_Unchecled - это константы ObjectWindows.
Передача данных
После того как вы создадите буфер передачи и заполняет его значениями,
получение этой информации в диалоговом блоке не представляет труда, поскольку
все за вас делает ObjectWindows. Когда для выполнения диалогового блока
вызывается ExecDialog, он вызывает TransferDatа для копирования значений
из буфера передачи в отдельные объекты управляющих элементов.
Когда вы завершите диалоговое окно, щелкнув "мышью" на командной
кнопке OK, ExecDialog перед уничтожением диалогового блока и его управляющих
элементов передает значения из управляющего элемента обратно в буфер передачи.
Отмена диалогового блока или его закрытие с помощью управляющего меню
обходит механизм передачи данных обратно в буфер передачи.
Таким образом, буфер передачи указывает на постоянный набор данных, не
зависящий от диалогового блока. Во многих случаях диалоговый блок создается
и уничтожается при выполнении программы многократно, а присваивание каждый
раз его поля TransferData одной и той же записи данных позволяет выводить
управляющие элементы так, как они выглядели при последнем закрытии диалогового
блока.
Чтение возвращаемых значений
Считывание значений обратно в буфер передачи - это обратный процесс по
отношению к заполнению буфера перед заполнением диалогового окна. В модуле
Pen определены некоторые функции, способствующие интерпретации выбора
кнопки с зависимой фиксацией в каждой группе.
function GetStyle(ARec: TPenDate): Longint;
B.Pascal 7 & Objects/OW - 82 -
var i: Integer;
begin
for i := 0 to 5 do
if ARec.StyleArray[i] = bf_Cheched then GetStyle := i; end;
Если пользователь отменяет диалоговый блок, то вас, конечно, не должно
беспокоить считывание значений: они совпадают с переданными значениями.
Обычно когда вы выполняете диалоговый блок с помощью ExecDialog, то чтобы
определить, возвратил ли диалоговый блок какие-либо полезные данные, проверяется
возвращаемое значение (id_Ok, если пользователь щелкнул "мышью"
на командной кнопке OK, в противном случае id_Cancel).
if Application^.ExecDialog(PenDlg) <> id_Cancel then
begin
Val(PenDate.XWith, TempWith, ErrorPos);
SetAttributes(GetStyle(PenData), TempWidth,
GetColorAttr(PenData)); end;
Вызов диалогового блока пера
Чтобы вывести диалоговый блок пера, вызовите его метод ChangePen. Программа
STEP06B.PAS делает это в ответ на команду cm_Pen, генерируемую выбором
пункта меню Options|Pen и щелчком правой кнопкой "мыши".
procedure TStepWindow.CMPen(var Msg: TMessage);
begin
CurrentPen^.ChangePen; CurrentPen - это объект
блока пера
end;
procedure TStepWindow.WMRButtonDown(var Msg: TMessage);
begin
if not ButtonDown then CurrentPen^.ChangePen;
end;
Примечание: Данные методы можно найти в файле STEP06B.PAS.
B.Pascal 7 & Objects/OW - 83 -
Глава 5. Повторное отображение графики
В следующих трех шагах вы узнаете как
* Отображать по запросу графический образ.
* Сохранять образ файла и загружать его.
* Печатать образ.
Шаг 7: Вывод на экран графики
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: MenuStep 5: About BoxStep
6: Pens Step 7: Painting Step 8: StreamsStep 9: PrintingStep 10: PaletteStep
11: BWCCStep 12: Custom ctrls
Возможно, вы удивитесь, узнав, что графика и текст, которые вы рисуете
в окне с помощью функций Windows типа TextOut или LineTo, исчезают при
изменении размера окна или повторного вывода его на экран. После того,
как графические данные переданы Windows, через вызовы функций Windows
вы никогда не получаете их обратно для повторного отображения.
Чтобы в окне повторно отображалась графика, вы должны сохранить эту графику
(или данные для регенерации графики) в структуре некоторого типа, такой
как объект. С помощью объектов вы можете полиморфически хранить простую
или сложную графику, а также хранить объекты и поля ваших оконных объектов.
Изображение и рисование
Существует два способа получения в окне графического образа. С рисованием
вы уже знакомы по предыдущим примерам. При рисовании вы создаете графический
образ в реальном времени в ответ на ввод данных пользователем. Но окно
не может требовать от пользователя воссоздания графики при обновлении
экрана.
Окна должны иметь возможность воссоздавать по запросу свои графические
образы. Windows сообщает своим оконным объектам, ког-
B.Pascal 7 & Objects/OW - 84 -
да они требуют изображения или обновления. При этом окно должно
каким-то образом генерировать образ экрана. В ответ на необходимость изображения.
ObjectWindows автоматически вызывает метод Paint вашего окна. Наследуемый
и TWindow метод Paint не выполняет никаких функций. В Paint вы должны
поместить код для передачи содержимого окна. Фактически Paint вызывается
при первом выводе окна. Paint отвечает за обновление (при необходимости)
изображения текущим содержимым.
Существует еще одно важное отличие между отображением графики в методе
Paint и другим ее отображением (например, в ответ на действия "мышью").
Содержимое экрана, которое должно использоваться для отображения, передается
в параметре PaintDC, так что вашей программе не требуется получать или
освобождать его. Однако вам потребуется вновь выбрать для PaintDC изобразительные
средства.
Чтобы отобразить содержимое окна, вместо повторения тех действий, которые
привели к первоначальному изображению (DragDC), вы используете PaintDC.
Визуальный эффект будет тот же, что и при первоначальном рисовании пользователем
(аналогично проигрыванию аудиозаписи концерта). Но чтобы "проигрывать"
ее в методе Paint, сначала вам нужно сохранить графику в виде объектов.
Сохранение графики в объектах
Созданные программой Steps изображения на самом деле просто представляют
наборы различного числа линий. При каждой буксировке "мыши"
вы добавляете другую линию. А каждая линия - это на самом деле определенный
набор точек, соединенных линейными сегментами. Чтобы сохранить и воспроизвести
такие изображения, вам необходим гибкий и расширяемый тип данных
Для размещения неизвестного числа линий или точек прекрасно подходит определенный
в модуле Objects тип TCollection. Это набор объектов, который может динамически
расширяться, когда вы добавляете другие элементы. Этим наборам не важно,
что они включают, поэтому вы можете использовать один и тот же механизм
и для рисунка (набора линий), и для линии (набора точек).
Примечание: О наборах рассказывается в Главе 19 "Наборы".
Концептуально вам нужно просто сделать так, чтобы окно знало о своем содержимом,
так что оно сможет обновить изображение. Окно содержит рисунок, представляющий
собой набор линий. Таким образом, вам нужно:
* Передать окну объект или поле, содержащее набор линий.
* Определить объект линии, который может отображаться.
B.Pascal 7 & Objects/OW - 85 -
* В ответ на сообщения "мыши" добавлять к сохраненным линиям
точки.
Добавление поля объекта
Чтобы сохранить рисунок в виде набора линий, добавьте в TStepWindow поле
с именем Drawing. В любой момент Drawing содержит текущий рисунок в виде
набора объектов линий. Когда требуется отобразить окно, оно использует
для изображения линии данные, записанные в Drawing.
Определение объекта линии
Далее нужно ответить на вопрос, что такое линия. В шаге 4 вы видели, что
изображаемая линия представляет собой просто набор точек, передаваемых
из Windows в программу через сообщение wm_MouseMove. Для представления
линий и точек вам необходимы объектные типы. Поскольку эффективный объект
изображения линии должен быть повторно используемой частью, создайте отдельный
модуль, определяющий объекты линий и точек.
TLine содержит всю информацию, необходимую для изображения данной линии:
перо и набор точек.
type
PLine = ^TLine;
TLine = object(TObject)
Points: PCollection;
LinePen: PPen;
constructor Init(APen: PPen);
constructor Load(var S: TStream);
destructor Done; virtual;
procedure AddPoint(AX, AY: Word);
procedure Draw(ADC: HDC);
procedure Store(var S: TStream);
end;
LinePen просто указывает на объект TPen, а Point - это набор объектов
точек. TLine и TLinePoint содержат методы Load и Store, преимущества использования
которых для записи картинок на диск вы увидите в шаге 8. В отличие от
них объект TLine весьма прост: конструктор и деструктор создают и уничтожают
LinePen, AddPoint включает объект точки в Points, а Draw рисует линии
между точками Points.
Объект TLinePoint еще проще:
type
PLinePoint = ^TLinePoint;
TLinePoint = object(TObject)
X, Y: Integer;
B.Pascal 7 & Objects/OW - 86 -
constructor Init(AX, AY: Integer);
constructor Load(var S: TStream);
procedure Store(var S: TStream);
end;
constructor TLinePoint.Init(AX, AY: Integer);
begin
X := AX;
Y := AY; end;
TLinePoint не определяет никакого нового поведения - это просто объект
данных, который должен использоваться в TLine. Но позднее (в шаге 8) он
понадобиться как объект для записи в поток. Не забудьте построить в TStepWindow.Init
Drawing и уничтожить его в TStepWindow.Done:
constructor TStepWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherites Init(AParent, ATitle);
ButtonDown := False;
HasChanged := False;
CommonPen := New(PPen, Init(ps_Solid, 1, 0));
Drawing := New(PCollection, Init(50, 50)); end;
destructor TStepWindow.Done;
begin
Dispose(CommonPen, Done);
Dispose(Drawing, Done); inherited Done;
end;
Основное окно программы Steps содержит набор в своем поле Drawing набор
линий. Когда пользователь рисует линии, вы должны преобразовывать их в
объекты и добавлять в Drawing. Затем, когда потребуется отобразить окно,
путем итерации Drawing нужно отобразить каждую его точку.
B.Pascal 7 & Objects/OW - 87 -
Изменение методов работы с "мышью"
Чтобы сохранять линии в виде объектов, вы должны изменить EMLButtonDown
и WMMouseMove, чтобы не только рисовать линии, но также сохранять точки
в наборе линий. Поскольку текущую линию придется обновлять не только одному
методу, добавьте в TStepWindow еще одно поле типа PLine с именем CurrentLine:
type
TStepWindow = object(TWindow);
CurrentLine: PLine;
.
.
.
end;
Кроме добавления изображения линии WMLButttonDown создает при каждом вызове
новый объект линии и добавляет его в набор в Drawing. WMMouseMove просто
добавляет новую точку в конец объекта текущей линии и изображает в окне
линейные сегменты. Сохраняя все точки всех линий, ваше окно будет записывать
информацию, необходимую для точного воспроизведения картинки.
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
begin
if not ButtonDown then
begin
ButtonDown := True;
SetCapture(HWindow);
DragDC := GetDC(HWindow);
CommonPen^.Select(DragDC);
MoveTo(DragDC, Msg.lParamLo, Msg.lParamHi);
CurrentLine := New(PLine, Init(CommonPen));
Drawing^.Insert(CurrentLine); end;
end.
procedure TStepWindow.WMMouseMove(var Msg: TMessage);
begin
if ButtonDown then
begin
LineTo(DragDC, Msg.lParamLo, Msg.lParamHi);
CurrentLine^.AddPoint(Msg.LParamLo, Msg.LParamHi); end;
end;
Примечание: Уничтожать устаревшие CurrentLine не требуется, поскольку
они записаны в наборе Drawing. Все объекты линий уничтожаются при уничтожении
Drawing.
WMLButtonUp модификации не требует. Вам не нужно уничтожать все объекты
линий при очистке отображаемого окна, поэтому добавь-
B.Pascal 7 & Objects/OW - 88 -
те в CMFileNew вызов метода FreeAll:
procedure TStepWindow.CMFileNew(var Msg: TMessage);
begin
Drawing^.FreeAll;
InvalidateRect(HWindow, nil, True); end;
Вывод сохраненной графики
Теперь, когда TStepWindow сохраняет свою текущую строку, вы должны научить
его по команде (этой командой является Paint) рисовать ее. Давайте напишем
для TStepWindow метод Paint, который повторяет действия WMLButtonDown,
WMMouseMove и WMLButtonUp. Путем итерации по набору линий Paint воссоздает
картинку аналогично тому, как это делаете вы. Метод Paint имеет следующий
вид (см. файл STEP07.PAS):
procedure TStepWindow.Paint(PaintDC: HDC; var PaintInfo:
TPintStruct);
procedure DrawLine(P: PLine); far;
begin
P^.Draw(PaintDC); end;
begin
Drawing^.ForEach(@DrawLine); end;
Примечание: Итерация методов описывается в Главе 19 "Наборы".
Метод Draw объекта линии для изображения каждой линии между точками также
использует итератор ForEach:
procedure TLine.Draw(ADC: HDC);
var First: Boolean;
procedure DrawLine(P: PLinePoint); far;
begin
if First then MoveTo(ADC, P^.X, P^.Y)
else LineTo(ADC, P^.X, P^.Y);
First := False; end;
begin
First := True;
LinePen^.Select(ADC);
Points^.ForEach(@DrawLine);
LinePen^.Delete; end;
B.Pascal 7 & Objects/OW - 89 -
------------------------------------------------------------------------
Шаг 8: Сохранение рисунка в файле
-----StepStepStepStepStepStepStep StepStepStepStepStep ------------------1:
Basic App |2: Text |3: Lines |4: Menu |5: About Box |6: Pens |7: Painting
|8: Streams |9: Printing |10: Palette |11: BWCC |12: Custom ctrls |
Теперь, когда вы сохранили представление данных в виде рисунка как часть
оконного объекта, можно легко записать эти данные в файл (фактически,
в буферизованный поток DOS) и считать его обратно.
Данный шаг посвящен добавлению полей объектов для записи состояния сохраняемой
информации, модификации сохраняемой в файле информации и методам открытия.
Используя предусмотренные в ObjectWindows потоковые объекты, вы убедитесь
в удобстве их применения для сохранения данных в файле.
Отслеживание состояния
Требуется отслеживать две характеристики рисунка. Изменение файла мы уже
отслеживали (в шаге 1 было добавлено поле HasChanged), но теперь нужно
знать, загружен ли файл в данный момент. Как и HasChanged, IsNewFile -
это атрибут TStepWindow типа Boolean, поэтому его также следует сделать
полем:
TStepWindow = object(TWindow)
ButtonDown, HasChanged, IsNewFile: Boolean;
.
.
.
end.
Поле HasChanged принимает значение True, если текущий рисунок модифицирован.
Модификация означает, что рисунок был изменен с момента последнего сохранения
или не сохранялся вовсе. Вы уже устанавливаете поле HasChanged в True,
когда пользователь начинает рисовать, и в False, когда окно очищается.
Когда пользователь открывает новый файл или сохраняет существующий, HasChanged
следует установить в False.
B.Pascal 7 & Objects/OW - 90 -
IsNewFile указывает, что рисунок не взят из файла, поэтому сохранение
рисунка потребует от пользователя задать имя файла. IsNeFile имеет значение
True только при первоначальном запуске приложения и после выбора пользователем
команды меню File|New (Файл|Новый). Это поле устанавливается в False,
когда файл открывается или сохраняется. Фактически, FileSave использует
IsNewFile, чтобы увидеть, можно ли сохранить файл немедленно, или пользователю
требуется выбрать файл из файлового диалога.
Приведем методы сохранения и загрузки файла. На данный момент они выполняют
только сохранение и загрузку файлов. Сохранение файла сконцентрировано
в одном новом методе, который называется WriteFile, а открытие файла выполняет
метод ReadFile.
procedure TStepWindow.CMFileNew(var Msg: TMessage);
begin
if CanClose then
begin
Drawing^.FreeAll;
InvalidateRect(HWindow, nil, True);
HasChanged := False;
IsNewFile := True; end;
end;
procedure TStepWindow.CMFileOpen(var Msg: TMessage);
begin
if CanClose then
if Application^.ExecDialog(New(PFileDialog, Init(@Self,
PChar(sd_FileOpen), StrCopy(FileName, '*.PTS')))) = id_Ok then ReadFile;
end;
procedure TStepWindow.CMFileSave(var Msg: TMessage);
begin
if IsNewFile then CMFileSaveAs(Msg) else WriteFile;
end;
procedure TStepWindow.CMFileSaceAs(var Msg: TMessage);
begin
if IsNewFile then StrCopy(FileName, '');
if Application^.ExecDialog(New(PFileDialog,
Init(@Self, PChar(sd_FileSave), FileName))) = id_Ok then WriteFile;
end;
procedure TStepWindow.ReadFile;
begin
MessageBox(HWindow, @FileName, 'Загрузить файл:', mb_Ok);
HasChanged := False;
IsNewFile := False; end;
B.Pascal 7 & Objects/OW - 91 -
procedure TStepWindow.WriteFile;
begin
MessageBox(HWindow, @FileName, 'Сохранить файл:', mb_Ok);
HasChanged := False;
IsNewFile := False; end;
Примечание: Данный текст программы можно найти в файле STEP08A.PAS.
Сохранение и загрузка файлов
Теперь, когда вы создали основную схему для построения и загрузки файлов,
осталось только выполнить фактическую загрузку и сохранение в файле наборов
точек. Для этого можно использовать потоковый механизм автоматического
сохранения объекта. Сначала вы научитесь сохранять и загружать сами объекты
точек и линий (как это сделать для наборов вы уже знаете). Затем методы
WriteFile и FileOpen будут модифицированы для использования потоков.
Примечание: Подробнее об использовании потоков с объектами рассказывается
в Главе 20 "Потоки".
Ниже приведен исходный код, показывающий как сохранять и загружать сами
объекты TLine и TLinePoint:
const
RLinePoint: TStreamRec = (
ObjType: 200;
VmtLink: Ofs(TypeOf(TLinePoint)^);
Load: @TLinePoint.Load;
Store: @TLinePoint.Store);
RLine: TStreamRec = (
ObjType: 201;
VmtLink: Ofs(TypeOf(TLine)^);
Load: @TLine.Load;
Store: @TLine.Store);
constructor TLinePoint.Load(var S: TStream);
begin
S.Read(X, SizeOf(X));
S.Read(Y, SizeOf(Y)); end;
procedure TLinePoint.Store(var S: TStream);
begin
S.Write(X, SizeOf(X));
S.Write(Y, SizeOf(Y)); end;
B.Pascal 7 & Objects/OW - 92 -
constructor TLine.Load(var S: TStream);
begin
Points := PCollection(S.Get);
LinePen := PPen(S.Get); end;
procedure TLine.Store(var S: TStream);
begin
S.Put(Points);
S.Put(LinePen); end;
procedure StreamRegistration;
begin
RegisterType(RCollection); end;
Для регистрации TCollection при запуске прикладной программы вы должны
вызывать StreamRegistration (который находится в Steps). Вы можете поместить
это вызов в метод TStepWindow.Init. Модуль DrawLine регистрирует в своем
коде инициализации TLinePoint и TLine, поэтому линии и точки регистрируются
простым включением DrawLine в оператор uses.
Заключительным шагом изменения методов WriteFile и ReadFile будет фактическая
запись в потоки и чтение из них (см. STEP08B.PAS):
procedure TStepWindow.ReadFile;
var
TempColl: PCollection;
TheFile: TDosStream; begin
TheFile.Init(FileName, stOpen);
TempColl: := PCollection(TheFile.Get);
TheFile.Done;
if TempColl <> nil then
begin
Dispose(Drawing, Done);
Drawing := TempColl;
InvalidateRect(HWindow, nil, True); end;
HasChanged := False;
IsNewFile := False; end;
procedure TStepWindow.WriteFile;
var
TheFile: TDosStream; begin
TheFile.Init(FileName, stCreate);
TheFile.Put(Drawng);
B.Pascal 7 & Objects/OW - 93 -
TheFile.Done;
IsNewFile := False;
HasChanged := False; end;
B.Pascal 7 & Objects/OW - 94 -
Шаг 9: Печать графического образа
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: MenuStep 5: About BoxStep
6: PensStep 7: PaintingStep 8: Streams Step 9: Printing Step 10: PaletteStep
11: BWCCStep 12: Custom ctrls
Печать из Windows может представлять собой сложную задачу, но ObjectWindows
предоставляет простой механизм добавления средств печати в вашу прикладную
программу.
Добавление этих средств предусматривает следующие три шага:
* Построение объекта принтера.
* Создание объекта распечатки.
* Печать объекта распечатки.
Построение объекта принтера
Любая программа ObjectWindows может получить доступ к принтеру с помощью
объекта типа TPrinter. В этом случае основное окно вашего приложения должно
построить объект принтера и сохранить его в объектном поле с именем Printer:
constructor TStepWindow.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
.
.
.
Printer := New(PPrinter, Init); end;
Примечание: Тип TPrinter определен в модуле OPrinter, поэтому не забудьте
добавить OPrinter в свой оператор uses.
Это все, что обычно приходится делать для инициализации объ-
B.Pascal 7 & Objects/OW - 95 -
екта принтера. По умолчанию TPrinter использует назначенный по
умолчанию принтер, заданный в файле WIN.INI. TPrinter предусматривает
также механизм для выбора альтернативных принтеров.
Создание объекта распечатки
ObjectWindows управляет выводимыми на печать данными точно также, как
выводом на экран. То есть вместо записи непосредственно на устройство
вывода (или даже непосредственно в Windows) вы направляете свой вывод
на объект, который знает, как представлять информацию на устройстве вывода.
Для вывода на печать используйте объекты, полученные из абстрактного типа
TPrintout и метода с именем PrintPage.
Существует два основных случая, с которыми вы будете иметь дело при генерации
из приложения Windows данных для печати: печать документов и печать содержимого
окна. Печать содержимого окна проще, поскольку окна уже "знают"
о своем представлении. Как оказывается на самом деле, это просто особый
случай печати документа.
Примечание: О печати документов рассказывается в Главе 15.
Запись в контекст устройства
До настоящего момента вы всегда записывали текст и графику в контекст
дисплея (что является способом представления в Windows пользовательской
области окон). Контекст дисплея - это просто специализированная версия
контекста устройства - механизма, через который приложения Windows работают
с различными устройствами, такими как экраны, принтеры или коммуникационные
устройства.
Запись в контекст одного устройства мало отличается от записи в контекст
другого, поэтому, например, достаточно просто сообщить, например, оконному
объекту, что для записи на принтер нужно использовать механизм Paint.
Создание распечатки окна
TWindowPrint - это специальный потомок TPrintout, используемый для печати
содержимого окна. Печать содержимого окна не представляет сложности по
двум причинам: вы имеете дело только с одной страницей, и объект окна
уже знает, как отображать свой образ.
Обычно при печати документа вашей прикладной программе нужно выполнять
итерации процесса печати для каждой страницы документа. Так как окно имеет
только один образ, при печати окна это не является необходимым.
B.Pascal 7 & Objects/OW - 96 -
Таким образом, печать также проста, как ориентация метода Paint объекта
окна на вывод вместо окна в контекст устройства, подходящий для принтера:
procedure TWindowPrint.PrintPage(DC: HDC; Page: Word;
Size: TPoint; var Rect: TRect; Flags: Word); var PS: TPaintStruct;
begin
Window^.Paint(DC, PS); end;
Поскольку переданный PrintPage параметр DC уже указывает на подходящий
для принтера контекст устройства, в простейшем случае PrintPage должен
только сообщить объекту окна на вывод его содержимого в этот контекст
устройства. Теперь ваш объект распечатки также знает о своем представлении.
Вывод распечатки
Наличие объекта распечатки, которому известно о своем представлении, это
все, что нужно для передачи распечатки на принтер. Программа Steps делает
это в ответ на команду cm_FilePrint, генерируемую командой Print меню
File:
procedure TStepWindow.CMFilePrint(var Msg: TMessage);
var P: PPrintout;
begin
if IsNewFile then StrCopy(FileName, 'Untitled');
P := New(PWindowPrint, Init(FileName, @Self));
Printer^.Print(@Self, P);
Dispose(P, Done); end;
CMFilePrint очень просто строит объект распечатки, озаглавленный заданным
именем (имя файла точек или 'Untitled') и заполняет его своим содержимым
(так как это единственное окно в приложении).
При наличии объекта распечатки CMFilePrint сообщает объекту принтера,
что его нужно напечатать, добавив какие-либо сообщения об ошибках или
диалоговые окна (отсюда параметр @Self). Когда печать закончится, CMFilePrint
уничтожает объект распечатки.
Выбор другого принтера
Одним из средств TPrinter является возможность изменения установки принтера.
TPrinter определяет метод Setup, который выводит диалоговое окно установки
принтера, позволяющее пользователю выбрать принтер из числа установленных
в Windows и обеспечивает доступ к диалоговому окну конфигурации устройства.
B.Pascal 7 & Objects/OW - 97 -
Чтобы вывести диалоговое окно установки принтера, ваша прикладная программа
вызывает метод Setup объекта принтера. Steps делает это в ответ на команду
cm_FileSetup (см. STEP09.PAS):
procedure TStepWindow.CMFileSetup(var Msg: TMessage);
begin
Printer^.Setup(@Self); end;
Диалоговое окно установки принтера является экземпляром типа TPrinterSetupDlg
(см. Рис. 5.1).
Select Printer
Принтер и порт
|PostScript Printer on LPT1: |v|
------------- ------------- -------------| OK | | Setup | | Cancel |-------------
------------- -------------
Рис. 5.1 Диалоговое окно установки принтера.
В комбинированном блоке диалогового окна выводятся принтеры, заданные
в WIN.INI. Это дает пользователю возможность доступа ко всем установленным
принтерам.
B.Pascal 7 & Objects/OW - 98 -
Глава 6. Вывод всплывающего окна
Итак, вы создали два типа окон - основное окно (объект TStepWindow) и
режимные дочерние окна, которые создаются и уничтожаются каждый раз, когда
они необходимы (например, блоки сообщений). Однако, в полноценной программе
Windows дочерние окна часто требуется сохранять активными в течении неопределенного
периода времени (в качестве примера можно привести окно оперативной полосы
SpeedBar в работающей под Windows интегрированной среде IDE).
До сих пор все дочерние окна в Steps имели фиксированный размер и создавались
из шаблонов ресурсов. В шагах 10 - 12 вы будете делать следующее:
* Создавать окна с динамическим размером, сохраняющиеся на
все время работы программы.
* Добавлять в окно специализированные управляющие элементы.
* Создавать собственное интерактивное окно.
Наконец, мы дадим предложения по дальнейшему расширению программы Steps.
Шаг 10: Добавление всплывающего окна
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: MenuStep 5: About BoxStep
6: PensStep 7: PaintingStep 8: StreamsStep 9: Printing Step 10: Palette
Step 11: BWCCStep 12: Custom ctrls
Создание и уничтожение окон и диалоговых блоков прекрасно подходит, когда
они используются не часто. Но в некоторых случаях желательно иметь дочернее
окно, доступное большую часть времени. Примером такого окна является инструментальная
палитра.
В этом шаге вы будете делать следующее:
* Добавите к основному окну поле.
B.Pascal 7 & Objects/OW - 99 -
* Построите плавающую палитру пера.
* Выведете и скроете палитру пера.
Палитра пера, которая выводится при выборе пользователем команды Palette|Show
(Палитра|Вывод) показана на Рис. 6.1.
PenPalette
Add Pen Delete Pen
Рис. 6.1 Палитра пера программы Steps с тремя перьями.
Поскольку это первое "новое" окно, которое вы создаете и которое
будет создаваться автоматически, неплохо рассмотреть, как создаются и
выводятся на экран объекты и элементы окна.
Добавление к окну дочернего окна
Режимными дочерними окнами, которые вы до сих пор использовали, управлять
легко. Вы можете их создать, использовать и отменить. Но здесь нам нужно
работать с диалоговым окном, которое не является режимным. Например, оно
должно закрываться, если закрывается приложение, и становиться скрытым,
если основное окно минимизируется.
В основном поведение диалоговых окон (такое как закрытие или когда окно
временно становится скрытым) автоматическое. Единственный случай, когда
вам нужно делать что-то особенное - это когда вы хотите сделать дочернее
окно независимым от его порождающего окна. Например, окно палитры, которое
вы собираетесь выводить, сможет скрываться и выводиться, пока основное
окно остается видимым. Окна, которые могут перемещаться или выводиться
независимо от своих порождающих окон, называются независимыми дочерними
окнами. На следующем шаге вы будете создавать зависимые окна, присоединенные
к независимому окну палитры.
B.Pascal 7 & Objects/OW - 100 -
Так как основное окно должно посылать команды окну палитры, потребуется
указатель на это окно, поэтому добавьте в TStepWindow его палитры пера.
TStepWindow содержит теперь следующие поля:
TStepWindow = object(TWindow)
DragDC: DHC;
ButtonDown: Boolean;
FileName: array[0..fsPathName] of Char;
HasChanged, IsNewFile: Boolean;
Drawing: PCollection;
Printer: PPrinter;
PenPalette: PPenPalette; окно палитры
.
.
.
end;
Осталось только построить объект дочернего окна и присвоить его PenPalette.
Этому посвящен следующий раздел.
Построение окна палитры
Объекты дочернего окна строятся обычно в конструкторах своих порождающих
окон. Аналогично тому, как это происходит при инициализации любого другого
поля, вы присваиваете значения любому указателю дочернего окна. В данном
случае:
constructor TStepWindows.Init(AParent: PWindowsObject;
ATitle: PChar); begin
inherited Init(AParent, ATitle);
.
.
.
PenPalette := New(PPenPalette, Init(@Self, 'Pan Palette'); end;
Назначение порождающего окна
Порождающие окна автоматически управляют своими дочерними окнами, поэтому
при создании дочернего окна ему передается указатель на объект порождающего
окна. Поскольку порождающее окно обычно строит свои дочерние окна, указателем
порождающего окна обычно является @Self.
Важным исключением является основное окно приложения. Так как оно не имеет
порождающего окна, конструктору основного окна передается nil.
Каждый оконный объект имеет список своих дочерних окон,
B.Pascal 7 & Objects/OW - 101 -
обеспечивающий создание, вывод, сокрытие и закрытие окон в нужные
моменты. Построение и уничтожение дочерних окон автоматически обновляет
список дочерних окон: построение дочернего окна добавляет его в список
своего порождающего окна; уничтожение окна удаляет его из списка.
B.Pascal 7 & Objects/OW - 102 -
Создание элементов экрана
При построении объекта дочернего окна, ObjectWindows берет на себя функции
по работе с соответствующими объекту элементами экрана. Это обратно тому,
что вы делали в шаге 6 с помощью InitResource. Тогда вы имели созданный
из ресурса элемент экрана и связывали с ним объект, благодаря чему могли
манипулировать элементом экрана. Теперь вы создали собственный объект,
и вам нужно сообщить Windows о необходимости создания соответствующего
экранного элемента.
Когда вы в шаге 3 делали это для диалогового окна, то вызывали ExecDialog.
Метод TApplication создает элемент экрана и выполняет режимное диалоговое
окно. Соответствующим методом для нережимных (или безрежимных) диалоговых
окон является TApplication.MakeWindow. Основным отличием является то,
что MakeWindow не выводит автоматически создаваемый элемент экрана и не
переходит в режимное состояние.
Примечание: MakeWindow и создание элементов экрана подробно описываются
в Главе 9 "Интерфейсные объекты".
Тогда процесс построения и вывода окна состоит из следующих трех этапов:
* Построение оконного объекта с помощью Init.
* Создание элемента экрана с помощью MakeWindow.
* Вывод окна с помощью Show.
К счастью, второй и третий шаги для основного окна приложения выполняются
автоматически. Кроме того, вызов для порождающего окна MakeWindow автоматически
вызывает для любого окна в его списке дочерних окон MakeWindow, так что
дочерние окна основного окна (такие как палитра пера) автоматически получают
элементы экрана.
В следующем разделе мы выведем дочернее окно.
B.Pascal 7 & Objects/OW - 103 -
Вывод и сокрытие палитры
Дочерние окна, отличные от тех, которые были созданы и выведены по умолчанию
их порождающими окнами (этот процесс управляется с помощью EnableAutoCreate
и DisableAutoCreate) в каждом интерфейсном объекте. Но вы можете скрыть
или вывести дочернее окно по команде. Обе функции метода Show наследуются
из TWindowsObject.
В зависимости от передаваемых параметров метод Show выводит либо скрывает
окно. Параметр - это одна из констант sw_, определенная в Windows. В ответ
на команды меню Palette|Show (Палитра|Вывод) или Palette|Hide (Палитра|Сокрытие),
которые генерируют, соответственно, команды cm_PalShow и cm_PalHide, TStepWindow
вызывает метод Show палитры пера (это дополняет STEP10.PAS):
procedure TStepWindow.CMPalShow(var Msg: TMessage);
begin
PenPalette^.Show(sw_ShowNA); end;
procedure TStepWindow.CMPalHide(var Msg: TMessage);
begin
PenPalette^.Show(sw_Hide); end;
Если у вас есть поле порождающего окна, указывающее на дочернее окно,
с которым необходимо работать, вы легко можете задать дочернее окно.
Шаг 11: добавление специализированных управляющих элементов
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: MenuStep 5: About BoxStep
6: PensStep 7: PaintingStep 8: StreamsStep 9: PrintingStep 10: Palette
Step 11: BWCC Step 12: Custom ctrls
В шаге 10 вы добавили к основному окну независимое дочернее окно. Теперь
вы добавите зависимые дочерние окна, которые называются управляющими элементами.
Порождающим окном этих управляющих элементов является окно палитры пера.
Нужно помнить о том, что
B.Pascal 7 & Objects/OW - 104 -
окно палитры пера является независимым дочерним окном, для которого порождающим
окном является основное окно. Таким образом, палитра пера является одновременно
дочерним окном основного окна и порождающим окном для управляющих элементов.
В шаге 6 вы уже имели дело с управляющими элементами и объектами управляющих
элементов, но тогда вы просто связывали объекты с управляющими элементами,
определенными в ресурсе. Построение управляющего элемента на этапе выполнения
несколько сложнее, так как наряду с типом как вам требуется задать позицию
и размер управляющих элементов.
Палитра пера, показанная на Рис. 6.1, использует две специализированные
кнопки кисти и последовательность графических изображений, каждое из которых
представляет перо, которое можно использовать для рисования. Эти перьевые
"кнопки" фактически не являются управляющими элементами, а скорее
представляют собой образы в единственным дочернем окне, которое может
их идентифицировать при щелчке "мышью".
В данном шаге вы добавите графические кнопки с помощью:
* добавления простых управляющих кнопок;
* реализации в программе специализированных управляющих элементов;
* определения графических изображений для кнопок.
Для всех управляющих элементов, в целом, поведение задается типом ObjectWindows
TControl и его типом-потомком, позволяющим работать с каждым типом управляющего
элемента. Например, TListBox определяет объекты блока списка, а TEdit
определяет каждый управляющий объект редактирования. Вы должны также понимать,
что TControl - это потомок TWindow.
Добавление к палитре командных кнопок
Хотя они ведут себя идентично, между управляющими кнопками диалоговых
блоков (таких как файловое диалоговое окно) и управляющими элементами
окон (таких как окно палитры) имеется существенное различие. Управляющие
элементы диалогового блока вы можете задать в ресурсе диалогового блока.
Они не являются объектами, и диалоговый блок, которому они принадлежат,
полностью отвечает за управление этими элементами. В Главе 11 показано,
как создать из диалоговых ресурсов свои собственные диалоговые блоки и
работать с их управляющими элементами.
Управляющие элементы окон задаются определением объекта. Порождающее окно
управляет их поведением через методы, определенные объектами управляющих
элементов ObjectWindows. Например, чтобы
B.Pascal 7 & Objects/OW - 105 -
получить следующий элемент, который пользователь выбрал в блоке
списка, вызовите метод GetSelString объекта блока. Аналогично
оконному объекту или объекту диалогового блока, объект управляющего элемента
имеет соответствующий визуальный элемент.
Объект управляющего элемента и его управляющий элемент связаны через поле
идентификатора объекта управляющего элемента. Каждый управляющий элемент
имеет уникальный идентификатор, который используется его порождающим окном
для идентификации управляющего элемента при маршрутизации управляющих
событий (таких как щелчок на элементе "мышью"). Для ясности
для каждого идентификатора управляющего элемента следует определить следующие
константы:
const
id_Add = 101;
id_Del = 102;
MaxPens = 9;
MaxPens задает максимальное число перьев, которые будет содержать палитра.
Значение 9 хорошо подходит для стандартного экрана VGA.
Объекты управляющих элементов как поля
Как и в случае других дочерних окон, часто удобно хранить указатель объекта
управляющего элемента в виде поля. Это необходимо только для дочерних
окон, с которыми вы позднее сможете работать непосредственно, вызывая
методы их объектов. TPenPalette записывает каждый из этих объектов управляющих
элементов в отдельном поле. Приведем часть описания объекта TPenPalette:
TPenPalette = object(TWindow)
AddBtn, DelBtn: PButton;
.
.
.
end;
После создания экземпляра этих дочерних объектов управляющих элементов
вы можете манипулировать ими с помощью вызовов методов. Например, в соответствующие
моменты можно разрешать или запрещать командные кнопки, вызывая их методы
Enable и Disable. Используя метод ChildList порождающего окна, можно получить
доступ к объектам управляющих элементов дочерних окон, не записанных в
полях, но гораздо удобнее делать это с помощью полей.
Работа с управляющими элементами
Любой тип окна, который имеет объекты управляющих элементов
B.Pascal 7 & Objects/OW - 106 -
(или другое дочернее окно) должен определять для построения своих
объектов управляющих элементов конструктор Init. Кроме того, для
задания управляющих элементов перед выводом вы можете переопределить SetupWindow.
Порождающее окно (TPenPalette) автоматически создает и выводит все свои
дочерние окна.
Приведем в качестве примера метод Init палитры пера. Первое, что он делает
- это установка собственного расположения и атрибутов размера. Так как
метод Init окна отвечает за задание его атрибутов создания, и поскольку
вместе с ним создаются управляющие элементы окна, вы должны также в методе
Init окна построить управляющие элементы. В каждом вызове конструктора
первый параметр
- это @Self (порождающее окно). За ним следует идентификатор управляющего
элемента.
constructor TPenPalette.Init(AParent: PWindowsObject; ATitle: PChar);
begin
inherited Init(AParent, ATitle);
with Attr do
begin
Style := Style or ws_Tiled or ws_SysMenu or ws_Visible;
W := 133;
H := GetSystemMetrics(sm_CYCaction) + 42;
AddBtn := New(PButton, Init(@Self, id_Add,
'Добавить перо', 0, 0, 65, 40, True); DelBtn := New(PButton, Init(@Self,
id_Del,
'Удалить перо', 0, 0, 65, 40, False);
end;
После создания окна, чтобы задать управляющие элементы окна, вызывается
виртуальный метод TPenPalette.SetupWindow. Поскольку здесь вы имеете дело
только с командными кнопками, инициализация не требуется, но TPenPalette.SetupWindow
первоначально запрещает одну из командных кнопок. Если бы вы использовали
другой управляющий элемент (например, блок списка), то для инициализации
объекта управляющего элемента потребовалось бы вызывать SetupWindow.
Примечание: Когда вы переопределяете метод SetupWindow окна, не забудьте
сначала вызывать наследуемый метод SetupWindow, так как он создает все
дочерние управляющие элементы.
Вызов методов Init и SetupWindow вполне достаточен для правильного вывода
в окне палитры всех управляющих элементов. Командные кнопки можно будет
активизировать ("нажимать"), но без каких-либо действий. В шаге
12 мы определим реакцию на события управляющего элемента.
Сокрытие вместо закрытия
B.Pascal 7 & Objects/OW - 107 -
Если вы дважды щелкните "мышью" в блоке системного меню палитры
пера, оно исчезнет. Выбор команды Palette|Show не может больше выводить
палитру, так как объект и его экранные элементы уничтожены. Выводить нечего.
Вы можете переопределить это, добавив метод CanClose, который скрывает
окно, а затем запрещает его закрытие (см. STEP11A.PAS):
function TPenPalette.CanClose: Boolean;
begin
Show(sw_Hide);
CanClose := False; end;
Теперь двойной щелчок "мышью" в блоке системного меню скрывает
окно, но не закрывает его, так что позднее вы можете вывести его снова.
Обычно наличие дочернего окна, которое всегда возвращает из CanClose False,
может предотвратить закрытие всего приложения. Но TStepWindow перед закрытием
не проверяет своих дочерних окон, так как в шаге 1 вы переопределили его
метод CanClose.
Разрешение специализированных управляющих элементов
Как вы уже знаете, объекты управляющих элементов создают стандартные управляющие
элементы Windows. Например, только что созданный вами объект TButton дает
в результате в палитре окна стандартную серую кнопку. Однако IDE и диалоговые
блоки, созданные вами из ресурсов, используют кнопки другого типа с расположенными
на них графическими изображениями. ObjectWindows предоставляет вам простой
способ использования в программах командных кнопок такого вида.
Использовать специализированные управляющие элементы Borland для Windows
(BWCC) также просто, как использование модуля. Для этого нужно просто
добавить BWCC в оператор uses основной программы. Это немедленно дает
два эффекта. Первый состоит в том, что все стандартные диалоговые блоки
(такое как файловое диалоговое окно, которое вы уже добавили в программу
Steps) используют для таких общих элементов как кнопки OK или Cancel,
а также кнопки с зависимой и независимой фиксацией, вместо стандартных
управляющих элементов специализированные.
Примечание: Об использовании и проектировании специализированных управляющих
элементов Borland рассказывается в Главе 12.
Фактически, после добавления в оператор uses программы Steps BWCC вы можете
перекомпилировать программу и получить доступ к диалоговым блокам. Без
каких-либо других усилий вы существенно
B.Pascal 7 & Objects/OW - 108 -
улучшите внешний вид программы и ее интерфейса.
Но как насчет кнопок в палитре пера? Они были созданы из управляющих объектов
с BWCC, используемых в программе, но выглядят как обычные командные кнопки.
Ответ, конечно, состоит в том, что вы еще не определили для кнопок, графические
изображения, так что по умолчанию они просто используют метки, переданные
в конструкторе Init. В следующем разделе вы увидите, как добавлять к специализированным
управляющим элементам графические изображения.
B.Pascal 7 & Objects/OW - 109 -
Создание для командных кнопок графических изображений
Хотя вы можете создавать графические изображения (битовые массивы) для
командных кнопок на этапе выполнения, эту задачу следует решать с помощью
ресурсов. Используя пакет разработчика ресурсов, вам нужно создать для
каждой командной кнопки три различных битовых массива: один для позиционирования
сверху, один для позиционирования снизу и один для позиционирования в
фокусе ввода.
С этими графическими изображениями вы можете делать что угодно. Здесь
ограничений нет. Вы можете изменять цвет образа в зависимости от состояния
кнопки или перемещать образы (что обычно используется) при нажатии, а
также добавлять вокруг текста кнопки линию из точек, когда она находится
в фокусе (активна). На Рис.
6.2 показано три графических изображения для командной кнопки Add
Pen палитры пера.
-------------------- -------------------- --------------------
| | | ..... | | ..... |
| Add | | : Add : | | : Add : |
| Pen | | : Pen : | | : Pen : |
| | | ..... | | ..... |
| | | | | |
-------------------- -------------------- --------------------
Рис. 6.2 Графические изображения для специализированной кнопки.
Нумерация ресурсов графических изображений
B.Pascal 7 & Objects/OW - 110 -
Единственная сложная часть в определении графических изображений для командных
кнопок - это присваивание идентификаторов ресурсов. Управляющие элементы
BWCC знают о том, какое графическое изображение использовать, основываясь
на идентификаторе конкретного управляющего элемента. Для командных кнопок
в системах с VGA для ресурсов используется 1000 + идентификатор для "верхнего"
образа, 3000 + идентификатор для "нижнего" образа и 5000 + идентификатор
для образа в фокусе.
Примечание: В системах с EGA используются, соответственно, ресурсы 2000
+ идентификатор, 4000 + идентификатор и 6000 + идентификатор.
Так как командная кнопка Add Pen имеет идентификатор 101 (id_Add), разрешение
использования BWCC принимает вид ресурсов 1101, 3101 и 5101. В программе
STEP11B.PAS, для доступа к специализированными графическим изображениям,
для командных кнопок Add Pen и Del Pen, используется директива:
$R PENTAL.RES
B.Pascal 7 & Objects/OW - 111 -
Шаг 12: Создание специализированного управляющего элемента окна
Step 1: Basic AppStep 2: TextStep 3: LinesStep 4: MenuStep 5: About BoxStep
6: PensStep 7: PaintingStep 8: StreamsStep 9: PrintingStep 10: PaletteStep
11: BWCC Step 12: Custom ctrls
Наиболее интересная часть создания палитры пера - это создание вашего
собственного специализированного окна палитры. Здесь вы можете, наконец,
использовать возможности, предусмотренные стандартными инструментальными
средствами окон, и что-то создать.
На этом шаге вы сделаете следующее:
* реализуете динамическое изменение размера окна палитры;
* зададите реакцию на уведомляющие сообщения от управляющих
элементов;
* создадите объект палитры с несколькими областями.
Динамическое изменение размеров палитры
Так как каждое перо, которое вы сохраняете в палитре, имеет один и тот
же размер (40 элементов изображения высотой и 128 шириной), вам нужно
убедиться, что окно палитры может увеличиваться и сжиматься на этот размер
каждый раз, когда вы удаляете перо. Объект TPenPalette определяет два
метода, которые позволяют это делать: Grow и Shrink.
procedure TPenPalette.Grow
var WindowRect: TRect;
begin
GetWindowRect(HWindow, WindowRect); with WindowRect do
MoveWindow(HWindow, left, top, right - left, bottom - top + 40, True);
end;
procedure TPenPalette.Shrink;
var WindowRect: TRect;
B.Pascal 7 & Objects/OW - 112 -
begin
GetWindowRect(HWindow, WindowRect); with WindowRect do
MoveWindow(HWindow, left, top, right - left, bottom - top - 40, True);
end;
Оба метода находят координаты границ окна, модифицируют их и сообщают
окну, что нужно использовать новые координаты границ. Функция API GetWindowRect
возвращает структуру TRect, содержащую верхнюю, нижнюю, левую и правую
координату. Grow добавляет в нижнюю область окна 40 элементов изображения,
а Shink вычитает тот же объем.
В следующем разделе вы узнаете, как вызывать методы Grow и Shrink в ответ
на нажатие командных кнопок Add Pen и Del Pen.
Реакция на события управляющих элементов
Основное различие между окном палитры и режимными диалоговыми окнами,
которые вы использовали ранее, состоит в том, что режимное диалоговое
окно манипулирует управляющими элементами, а затем считываете результаты,
если пользователь щелкает "мышью" на командной кнопке OK. В
данном безрежимном окне палитры вы имеете дело с активной, динамической
частью программы и можете активно отвечать на каждый используемый управляющий
элемент.
Пока командные кнопки выводятся в окне палитры, но щелчок кнопкой "мыши"
не дает никакого эффекта. Щелчок и выбор "мышью" являются событиями
управляющего элемента. Они аналогичны событиям меню, на которые вы отвечали
в шаге 4.
Вы отвечали на события меню, определяя методы реакции на команды. Что-то
аналогичное нужно делать с сообщениями управляющих элементов. События
управляющих элементов создают сообщения (на основе дочернего идентификатора),
аналогичные командным сообщениям, но вместо идентификатора меню содержащие
идентификатор управляющего элемента. Для идентификации заголовка метода
на основе дочернего идентификатора используйте сумму идентификаторов управляющего
элемента и констант id_First.
Примечание: Подробнее о командных сообщениях и уведомляющих сообщениях
управляющих элементов рассказывается в Главе 16 "Сообщения окон".
Имена методов реакции на сообщения управляющих элементов
Как и в случае методов реакции на сообщения, имена которым присваиваются
по сообщениям, методы, основанные на дочерних идентификаторах, также должны
именоваться по идентификаторам сообщений. Так как две командные кнопки,
на которые вы хотите реагиро-
B.Pascal 7 & Objects/OW - 113 -
вать, имеют идентификаторы id_Add и id_Del, TPenPalette нужны методы с
именами IDAdd и IDDel.
TPenPalette = object(TWindow)
AddBtn, DelBtn: PBitButton;
constructor Init(AParent: PWindowsObject; ATitle: PChar); procedure Grow;
procedure SetupWindow; virtual;
procedure Shrink;
procedure IDAdd(var Msg: TMessage); virtual
id_First + id_Add;
procedure IDDel(var Msg: TMessage); virtual
id_First + id_Del;
end;
Теперь для выполнения соответствующих действий в ответ на командные кнопки
осталось только определить методы IDAdd и IDDel. Пока что IDAdd должен
просто вызывать увеличение окна, а IDDel - его сжатие
procedure TPenPalette.IDAdd(var Msg: TMessage);
begin
Grow; end;
procedure TPenPalette.IDDel(var Msg: TMessage);
begin
Shrink; end;
Примечание: Это дополняет содержимое файла
STEP12A.PAS.
B.Pascal 7 & Objects/OW - 114 -
Добавление "кнопок" палитры
Теперь, когда у вас есть окно палитры, вам необходим просто способ вывода
на экран и выбора перьев в палитре. Для этого вы можете использовать относительно
простой потомок TWindow и набор объектов пера.
В данном разделе вы сделаете следующее:
* определите объект палитры пера;
* выберете перья по щелчку кнопкой "мыши".
Определение объекта палитры
Так как окно палитры пера может изменять свой размер, палитра в окне может
фактически оставаться фиксированной. Чтобы показать только часть палитры,
в которой отображаются перья, вы можете использовать возможности отсечения
Windows.
Самой палитре необходимы только несколько полей данных: набор перьев,
указание того, какое перо в данный момент выбрано, и описатели представляющих
перья графических образов. Описатели графических изображений представляют
собой частные поля не потому, что они должны быть секретными, а для предотвращения
их непреднамеренного изменения другим кодом.
Приведем описание объекта палитры:
TPenPic = object(TWindow)
PenSet: PCollection;
CurrentPen: Integer;
constructor Init(AParent: PWindowsObject);
destructor Done: virtual;
procedure Paint(PaintDC: HDC; var PaintInfo:
TPaintStruct); virtual; procedure AddPen(APen: PPen); procedure DeletePen;
procedure SetupWindow; virtual; procedure WMLButtonDown(var Msg: TMessage);
virtual wm_First + wm_LButtonDown; private
UpPic, DownPic: HBitMap; end;
Объекту TPenPic не требуется очень много методов. Он имеет простой конструктор
для создания набора перьев и деструктор для их уничтожения. Метод SetupWindow
просто перемещает палитру внутри ее порождающего окна. AddPen и DeletePen
включают перо в набор и удаляют перо из набора, а WMLButtonDown интерпретирует
щелчки
B.Pascal 7 & Objects/OW - 115 -
"мышью" для выбора перьев из палитры. Наконец, Paint рисует
"кнопки", представляющие перья в наборе.
Отметим также, что TPenPic является потомком TWindow, а не TControl. Хотя
поведение вашего нового объекта во многом напоминает поведение управляющего
элемента окна, он должен быть производным от TWindow, так как TControl
работает только со стандартными управляющими элементами, такими как "нажимаемые"
командные кнопки и полосы прокрутки. При создании собственных управляющих
элементов нужно начинать с TWindow.
B.Pascal 7 & Objects/OW - 116 -
Создание и уничтожение палитры
Построение и уничтожение объекта палитры выполняется достаточно просто.
Конструктор Init вызывает TWindow.Init, затем изменяет стиль окна (чтобы
оно стало видимым дочерним окном). PenSet инициализируется как набор фиксированного
размера, достаточно большой, чтобы содержать максимальное число заданных
константой MaxPens перьев, и не возрастающий. Для текущего выбранного
пера CurrentPen устанавливается в -1. Это означает, что выбранного пера
нет.
Наконец, Init загружает в UpPic и DownPic два графических образа. Они
используются в качестве фона для каждого пера палитры. DownPic рисуется
за выбранным пером, а UpPic - в качестве фона других перьев.
-------------------- --------------------
| | | |
| | | |
| | | |
-------------------- --------------------
Рис. 6.3 Фоновые образы палитры пера.
Деструктор Done перед вызовом наследуемого деструктора Done отменяет графические
образы. Вызов DeleteObject для уничтожения графических образов имеет важное
значение. Подобно контексту дисплея, графические образы являются ресурсами
Windows, поддерживаемыми в ограниченной памяти Windows. Если размещаете
их в памяти Windows и не удаляете, то ваша программа (и другие работающие
параллельно с ней программы) потеряют доступ к этой памяти.
Init и Done объекта палитры выглядят следующим образом:
constructor TPenPic.Init(AParent: PWindowsObject);
begin
inherited Init(AParent, nil);
AttrStyle := ws_Child or ws_Visible;
PenSet := New(PCollection, Init(MaxPens, 0));
CurrentPen := -1;
UpPic := LoadBitMap(HInstance, 'PAL_UP');
DownPic := LoadBitmap(HInstance, 'PAL_DOWN'); end;
destructor TPenPic.Done;
begin
DeleteObject(UpPic);
DeleteObject(DownPic);
Dispose(PenSet, Down); inherites Done;
B.Pascal 7 & Objects/OW - 117 -
end;
Размещение в порождающем окне
Как вы могли заметить, TPenPic не задает свою позицию в конструкторе так,
как это делают большинство управляющих элементов. Причина здесь в том,
что вы не можете полагаться на координаты окна, пока оно не будет реально
существовать. TPenPalette обходит эту проблему, создавая свои объекты
кнопок путем вызова для определения высоты заголовка окна функции API
GetSystemMetrics. Хотя это будет работать, существует и другой подход.
Вместо позиционирования палитры в конкретное место порождающего окна вы
можете поместить его в определенную позицию в порождающей области клиента.
Таким образом, если вы добавляете меню или изменяете рамку, либо выполняете
вне окна какое-либо другое изменение, ваш объект палитры все равно будет
правильно позиционирован.
Изменение позиции окна выполняется в SetupWindow, так как окну палитры
требуется использовать описатель своего порождающего окна, который до
вызова собственного метода SetupWindow недоступен. При достижении SetupWindow
дочернее окно может рассчитывать на допустимость описателя порождающего
окна.
procedure TPenPic.SetupWindow;
var ClientRect: TRect;
begin
inherited SetupWindow;
GetClientRect(Parent^.HWindow, ClientRect); with ClientRect do
MoveWindow(HWindow, 1, bottom - top + 1, 128, 40 * MaxPens, False;
end;
Для возврата координат области клиента окна палитры метод TPicPen использует
функцию API Windows GwetClientRect. Затем он перепозиционируется с помощью
MoveWindow непосредственно под объекты кнопок, задавая высоту, достаточную
для размещения всех перьев в наборе. Заметим, что последний параметр MoveWindow
- это значение типа Boolean, указывающее, следует ли выполнять повторное
отображение окна после перемещения. Так как палитра на экран пока не выводилась,
то заново отображать ее не имеет смысла, поэтому TPenPic.SetupWindow передает
значение False.
B.Pascal 7 & Objects/OW - 118 -
Добавление и удаление перьев
В последнем разделе вы отвечали на сообщения от Add Pen (Добавить перо)
и Del Pen (Удалить перо) изменением размера окна палитры. Теперь настало
время изменить эту реакцию и фактически добавлять или удалять перья из
палитры, что в свою очередь указывает окну палитры на необходимость изменения
размера. Вместо вызова собственных методов Grow и Shrink методы объекта
палитры AddPen и DeletePen должны вызывать соответственно, методы IDAdd
и IDDel в TPenPalette.
procedure TPenPalette.IDAdd(var Msg: TMessage);
begin
Pens^.AddPen(CommonPen); end;
procedure TPenPalette.IDDel(var Msg: TMessage);
begin
Pens^.DeletePen; end;
Метод AddPen воспринимает передаваемое перо, копирует его в набор и отмечает
перо, как текущее выбранное. Затем он разрешает кнопку Del Pen в окне
палитры пера, запрещает кнопку Add Pen, если набор полон, и сообщает порождающему
окну о необходимости увеличения размера, чтобы поместить новое перо.
procedure TPenPic.AddPen(APen: PPen);
begin
CurrentPen := PenSet^.Count;
with APen^ do PenSet^.Insert(New(PPen, Init(Style, With,
Color))); with PPenPalette(Parent)^ do begin
DelBtn^.Enable;
if PenSet^.Count >= MaxPens tnen
AddBtn^.Disable;
Grow; end;
end;
Примечание: Чтобы использовать преимущества средств, специфических для
TPenPAlette, TPenPic может выполнять приведение типа поля Parent. Большинство
оконных объектов не связаны так жестко с конкретным порождающим типом,
и поэтому не должны делать никаких предположений относительно типа порождающих
их окон.
Метод DeletePen по существу изменяет действия AddPen на обратные. При
наличии выбранного в палитре пера оно удаляется из набора, а набор уплотняется
таким образом, чтобы перья размещались непрерывно. Затем он указывает,
что в данный момент выбран-
B.Pascal 7 & Objects/OW - 119 -
ных перьев нет (поскольку выбранное перо только что удалено) и
запрещает командную кнопку Del Pen, так как Del Pen работает с
выбранным пером. Далее он разрешает кнопку Add Pen, поскольку
удаление пера автоматически освобождает место для по крайней мере
еще одного пера. Наконец, он сообщает порождающему окну на необходимость
уменьшения его размера (так выводить теперь нужно меньше перьев).
procedure TPenPic.DeletePen;
begin
if CurrentPen > -1 then
begin
PenSet^.AtFree(CurrentPen);
PenSet^.Pack;
CurrentPen := -1;
with PPenPelette(Parent)^ do
begin
AddBtn^.Enable;
DelBtn^.Disable;
Shrink; end;
end;
end;
Заметим, что AddPen и DeletePen используют преимущества того факта, что
окна палитры пера для упрощения связи с методами имеет указатели на свои
командные кнопки. Если бы TPenPalette не имел полей AddBtn и DelBtn, то
объекту палитры пришлось бы искать их по идентификаторам и посылать им
сообщения, либо нужно было бы послать сообщение порождающему окну, которое
в свою очередь должно каким-то образом связываться с командными кнопками.
B.Pascal 7 & Objects/OW - 120 -
Отображение содержимого палитры
За все, что мы насоздавали в объекте палитры, приходится расплачиваться,
когда приходит момент отображать ее на экране. Поскольку перья хранятся
в наборе, для отображения каждого пера вы легко можете выполнять итерацию.
В самом деле, метод Paint состоит только из инициализации локальной переменной-счетчика,
а затем выполняет итерацию по набору с помощью ForEach:
procedure TPenPic.Paint(PaintDC: HDC;
var PaintInfo: TPaintStruct);
var PenCount: Integer;
procedure ShowPen(P: PPen); far;
var
MemDC: HDC;
TBitmap: HBitmap; begin
MemDC := CreateCompatibleDC(PaintDC);
Inc(PenCount);
if PenCount = CurrentPen then
TheBitmap = DownPic; else TheBitmap := UpPic; SelectObject(MemDC, TheBitmap);
BitBlt(PaintDC, 0, PenCount * 40, 128, 40, MemDC, 0,
0, SrcCopy); P^.Select(PaintDC); MoveTo(PaintDC, 15, PenCount * 40 + 20);
LineTo(PaintDC, 115, PenCount * 40 + 20); P^.Delete;
DeleteDC(MemDC); end;
begin
PenCount := -1;
PenSet^.ForEach(@ShowPen); end;
Наиболее интересная часть содержится не в Paint, а во вложенной процедуре
ShowPen, которая вызывается для каждого пера в палитре. На самом деле
ShowPen состоит из двух различных частей. Первая рисует графическое изображение
фона, а вторая (которая уже должна быть вам достаточно знакома) использует
объект пера для изображения по этому фону образца линии.
Изображение графических образов предусматривает три шага: создание контекста
устройства памяти, выбор в контексте устройства графического образа и
копирование образа в контекст экрана.
Как вы видели в шаге 8, для различных видов устройств существует различные
контексты устройства. Для работы с графическими образами (битовыми массивами)
Windows позволяет создавать кон-
B.Pascal 7 & Objects/OW - 121 -
текст устройства памяти. Фактически, вы можете только выбирать
битовые массивы в контексте устройства памяти, хотя они могут копироваться
в другие контексты устройства.
Метод CreateMemoryDC создает пустой контекст устройства памяти, совместимый
с текущим PaintDC. Затем, в зависимости от того, является ли данное конкретное
перо выбранным, ShowPen выбирает в контексте устройства графические образы
UpPic или DownPic. Заметим, что в контексте устройства памяти графический
образ интерпретируется аналогично любому другому изобразительному средству.
Наконец, функция BitBlt копирует заданную часть контекста устройства памяти
в PaintDC. Заметим, что контекст устройства памяти требуется уничтожать.
После того как фон будет на месте, ShowPen использует ShowTo и LineTo
аналогично тому, как это делается при рисовании непосредственно в окне.
Выбор перьев с помощью "мыши"
Наконец. TPenPic обеспечивает реакцию на щелчок в нарисованной области
кнопкой "мыши". Заметим, что хотя размер объекта палитры никогда
не изменяется, он получает сообщение от щелчков "мышью" в области,
фактически показываемой на экране. Палитра отсекается рамкой окна палитры.
Это означает, что вы можете щелкать кнопкой "мыши" только непосредственно
в палитре.
Поскольку каждый элемент в палитре имеет один и тот же размер, WMLButton
для определения того, в каком графическом образе была нажата кнопка "мыши",
может просто разделить y-координату щелчка "мыши" (которая поступает
в LParamHi) на 40 (размер каждого графического изображения). Затем он
делает перо, на котором была нажата кнопка "мыши" текущим и
задает в качестве пера для рисования копию выбранного пера палитры. Поскольку
теперь есть выбранное перо, он разрешает кнопку Del Pen в окне палитры,
затем запрещает палитру для обеспечения ее повторного отображения для
того, чтобы показать новый выбор.
Код для WMLButtonDown имеет следующий вид (это дополняет текст STEP12B.PAS):
procedure TPenPic.WMLButtonDwon(var Msg: TMessage);
begin
CurrentPen := Msg.LParamHi div 40;
if CurrentPen <> nil then Dispose(CurrentPen, Done);
with PPen(PenSet^.At(CurrentPen))^ do
CurrentPen := New(PPen, Init(Style, With, Color)); PPenPalette(Parent)^.DelBlt^.Enable;
InvalidateRect(HWindow, nil, False);
end;
Что дальше?
B.Pascal 7 & Objects/OW - 122 -
-----------------------------------------------------------------
Есть много дополнений и изменений, которые вы можете внести в программу
Steps, чтобы сделать ее более полезной. Версию программы Steps, которая
включает в себя эти изменения, вы можете найти в файле GRAFFITI.PAS.
Программа Graffiti содержит следующие изменения:
* Многодокументальный интерфейс (MDI).
* Сглаживание линий.
* Отмена.
* Улучшает поведение окна палитры.
* Прокрутка.
Многодокументальный интерфейс
TStepWindow может очень легко работать в качестве дочернего окна MDI.
Фактически с небольшими изменениями программа Graffiti использует в качестве
своих дочерних окон те же окна, что Steps использует для основного окна.
Так как владельцем окна палитры пера является объект TStepWindow, каждый
отдельный рисунок имеет свой собственный отличный набор перьев. О многодокументальном
интерфейсе рассказывается в Главе 14 "Объекты MDI").
Сглаживание линий
Для сложных рисунков со многими длинными линиями повторное отображение
рисунка может потребовать много времени. Graffiti использует одно из преимуществ
графический функций GDI - функцию PolyLine, которая рисует сегменты каждой
линии сразу, а не по одному. Эффектом будет более быстрое и плавное отображение
окна.
Отмена
Поскольку рисунок состоит из наборов линий, для стирания последней нарисованной
линии легко использовать методы наборов. Graffiti связывает элемент меню
Edit|Undo (Редактирование|Отмена) с набором линий метода AtDelete, удаляя
последнюю линию в наборе, которая является также последней нарисованной
линией. Повторяя удаление последней линии в наборе, вы можно эффективно
отменять все изображение.
Хотя программа Graffiti этого не делает, вы можете добавить также функцию
Redo (Возобновление), сохраняя удаленные линии в другом наборе, и перемещая
их по одной в набор отображаемых ли-
B.Pascal 7 & Objects/OW - 123 -
ний, либо даже в другой рисунок.
Поведение палитры
Вы можете также отметить, что при щелчке "мышью" между палитрой
и основным окном, окно, где вы нажимаете кнопку, становится активным (получает
активную рамку), а другие окна становятся неактивными. Если вы часто перемещаетесь
между двумя окнами (что может иметь место при работе с палитрой), это
может показаться весьма раздражающим. Чтобы предотвратить это явление,
вам нужно перехватывать передачу в окна сообщений sm_NCActivate, и когда
параметр WParam сообщений равен 0 (попытка деактивизации рамки), вы можете
изменить его на 1 (активизация рамки):
procedure TPenPalette.WVNCActivate(var Msg: TMessage);
begin
if Msg.WParam = 0 then Msg.WParam := 1;
DefWndProc(Msg); end;
Вызов DefWndProc обеспечивает, что сообщение обрабатывается как обычно,
но теперь рамка палитры деактивизироваться не будет. Аналогичный перехват
вы можете добавить в TStepWindow.
Прокрутка
Наконец, так как каждое дочернее окно MDI обычно невелико по размеру,
Graffiti добавляет возможность автоматической прокрутки изображения при
рисовании. В программе Steps, когда перо выходит за границы окна, линия
продолжает рисоваться, хотя видеть ее вы больше не можете.
Часть №2
|
|
|