Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

Функции

DialogВохХХХХ
создают диалоговое окно и сразу же показывают его в модальном режиме. Данные функции завершают свое выполнение только тогда, когда модальное окно будет закрыто. Внутри модальных функций организуется собственная петля сообщений. Все прочие окна на время показа модального диалога запрещаются (как если бы для них была вызвана функция
EnableWindow
с параметром
FALSE
), т.е. перестают реагировать на сообщения от мыши и клавиатуры. При этом они сохраняют способность реагировать на другие сообщения, благодаря чему могут, например, обновлять свое содержимое по таймеру (в справке написано, что ничто не мешает программисту вставить в диалоговую процедуру вызов функций, разрешающих запрещенные системой окна, но
при этом теряется смысл модальных диалогов). Если в очереди нет сообщений, модальная петля посылает родительскому окну диалога сообщение
WM_ENTERIDLE
, обработка которого позволяет этому окну выполнять фоновые действия. Разумеется, что обработчик
WM_ENTERIDLE
не должен выполняться слишком долго, иначе модальное окно зависнет. Обычно окно использует оконную процедуру, которая задана при создании соответствующего оконного класса. Однако допускается создание так называемых подклассов — переопределение оконной процедуры после того, как окно создано. Это переопределение касается только заданного окна и не оказывает влияния на остальные окна, принадлежащие данному оконному классу. Осуществляется оно с помощью функции
SetWindowLong
с параметром
GWL_WNDPROC
(другие значения этого параметра позволяют менять другие свойства окна, такие как стиль и расширенный сталь). Изменять оконную процедуру можно только у окон, созданных самим процессом.

Новая оконная процедура, которая устанавливается при создании подкласса, все необработанные сообщения должна передавать не функции

DefWindowProc
, а той оконной процедуре, которая была установлена ранее.
SetWindowLong
при изменении оконной процедуры возвращает дескриптор старой процедуры (этот же дескриптор можно получить, заранее вызвав функцию
GetWindowLong
с аргументом
GWL_WINDOWPROC
). Обычно значение дескриптора численно совпадает с адресом старой оконной процедуры, поэтому в некоторых источниках можно встретить рекомендации использовать этот дескриптор непосредственно как указатель процедурного типа. И это даже будет работать для оконных классов, созданных самой программой. Но безопаснее все же вызов старой оконной процедуры реализовать с помощью системной функции
CallWindowProc
, предоставив ей "разбираться", является ли дескриптор указателем.

В качестве примера рассмотрим создание подкласса для некоторого окна, дескриптор которого содержится в переменной

Wnd
. Пусть нам потребовалось для этого окна нестандартным образом обрабатывать сообщение
WM_KILLFOCUS
.

Тогда код новой оконной процедуры и код ее установки будет выглядеть так, как показано в листинге 1.7.

Листинг 1.7. Создание подкласса для особой обработки сообщения
WM_KILLPFOCUS

var

 OldWndProc: TFNWndProc;

function NewWindowProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM) : LRESULT; stdcall;

begin

 if Msg = WM_KILLFOCUS then

// Обработка события

 else

Result := CallWindowProc(OldWndProc, hWnd, Msg, wParam, lParam);

end;

...

// Установка новой оконной процедуры окну Wnd

OldWndProc := TFNWndProc(SetWindowLong(Wnd, GWL_WNDPROC, Longint(@NewWindowProc)));

...

Примечание

MSDN называет функции

GetWindowLong
и
SetWindowLong
устаревшими и рекомендует использовать вместо них
GetWindowLongPtr
и
SetWindowLongPtr
, совместимые с 64-разрядными версиями Windows. Однако до 2007-й
версии Delphi включительно эти функции отсутствуют в модуле Windows, и при необходимости их следует импортировать самостоятельно.

Переопределять оконную процедуру с помощью

SetWindowLong
можно и у тех окон, оконная процедура которых была переопределена ранее. Таким образом создаются цепочки оконных процедур, каждая из которых вызывает предыдущую.

1.1.7. Создание окон средствами VCL

Теперь поговорим о том, как в VCL создаются окна. Речь здесь будет идти не о написании кода для создания окна с помощью VCL (предполагается, что читатель это и так знает), а о том, какие функции API и в какой момент вызывает VCL при создании окна.

Если смотреть код методов класса

TWinControl
, которые вызываются при создании и отображении окна, то найти там то место, когда окно создается, удается не сразу. На первый взгляд все выглядит так, будто этот код вообще не имеет отношения к созданию окна, как будто оно создается где-то совсем в другом месте, а
TWinControl
получает уже готовый дескриптор. На самом деле окно создает, конечно же, сам
TWinControl
, а спрятано его создание в свойстве
Handle
. Метод
GetHandle
, который возвращает значение свойства
Handle
, выглядит следующим образом (листинг 1.8).

Листинг 1.8. Реализация метода
TWinControl.GetHandle

procedure TWinControl.HandleNeeded;

begin

 if FHandle = 0 then

 begin

if Parent <> nil then Parent.HandleNeeded;

CreateHandle;

 end;

end;

function TWinControl.GetHandle: HWnd;

begin

 HandleNeeded;

 Result := FHandle;

end;

При каждом обращении к свойству

Handle
вызывается метод
HandleNeeded
, который проверяет, создано ли уже окно, и если нет, создает его, попутно создавая, при необходимости, родительское окно. Таким образом, окно создается при первом обращении к свойству
Handle
.

Метод

CreateHandle
, который вызывается из
HandleNeeded
, выполняет непосредственно лишь несколько вспомогательных операций, а для создания окна вызывает еще один метод —
CreateWnd
(листинг 1.9).

Листинг 1.9. Реализация метода
CreateWnd

procedure TWndControl.CreateWnd;

var

 Params: TCreateParams;

 TempClass: TWndClass;

 ClassRegistered: Boolean;

begin

 CreateParams(Params);

 with Params do

 begin

if (WndParent = 0) end (Style and WS_CHILD <> 0) then

if (Owner <> nil) end (csReading in Owner.ComponentState) and (Owner is TWinControl) then

WndParent TWinControl(Owner).Handle

else

raise EInvalidOperation.CreateFmt(SParentRequired, [Name]);

FDefWndProc := WindowClass.lpfnWndProc;

ClassRegistered := GetClassInfo(WindowClass.hInstance, WinClassName, TempClass);

if not ClassRegistered or (TempClass.lpfnWndProc <> @InitWndProc) then

Поделиться:
Популярные книги

Адвокат Империи 3

Карелин Сергей Витальевич
3. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 3

Кротовский, может, хватит?

Парсиев Дмитрий
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Кротовский, может, хватит?

Дурная жена неверного дракона

Ганова Алиса
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Дурная жена неверного дракона

Вонгозеро

Вагнер Яна
1. Вонгозеро
Детективы:
триллеры
9.19
рейтинг книги
Вонгозеро

Ведьма Вильхельма

Шёпот Светлана
Любовные романы:
любовно-фантастические романы
8.67
рейтинг книги
Ведьма Вильхельма

Папина дочка

Рам Янка
4. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Папина дочка

Законы Рода. Том 6

Flow Ascold
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 6

Как я строил магическую империю 7

Зубов Константин
7. Как я строил магическую империю
Фантастика:
попаданцы
постапокалипсис
аниме
фантастика: прочее
5.00
рейтинг книги
Как я строил магическую империю 7

Лучший из худший 3

Дашко Дмитрий
3. Лучший из худших
Фантастика:
городское фэнтези
попаданцы
аниме
6.00
рейтинг книги
Лучший из худший 3

Штурмовик из будущего 3

Политов Дмитрий Валерьевич
3. Небо в огне
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Штурмовик из будущего 3

Последний попаданец 2

Зубов Константин
2. Последний попаданец
Фантастика:
юмористическая фантастика
попаданцы
рпг
7.50
рейтинг книги
Последний попаданец 2

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Вдова на выданье

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Вдова на выданье