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

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

Жанры

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

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

Шрифт:

 procedure HookParentMessage(var Msg: TMessage);

end;

...

procedure TCoordLabel.SetParent(AParent: TWinControl);

begin

 if Assigned(Parent) and Assigned(FOldProc) then Parent.WindowProc := FOldProc;

 inherited;

 if Assigned(Parent) then

 begin

FOldProc := Parent.WindowProc;

Parent.WindowProc := HookParentMessage;

 end;

end;

procedure TCoordLabel.HookParentMessage(var Msg: TMessage);

begin

 if Msg.Msg = WM_LBUTTONDOWN then

Caption := '(' + IntToStr(Msg.LParamLo) + ', ' + IntToStr(Msg.LParamHi) + ')';

 FOldProc(Msg);

end;

Класс

TLabel
,
предок
TCoordLabel
, является визуальным компонентом и сам может получать и обрабатывать сообщения, поэтому метод
Dispatch
у него уже "занят". Соответственно, мы не можем диспетчеризовать с его помощью перехваченные сообщения и должны обрабатывать их внутри метода
HookParentMessage
.

Сам перехват осуществляется не в конструкторе, т.к. на момент вызова конструктора родитель компонента еще неизвестен. Он устанавливается позже, через свойство

Parent
, которое приводит к вызову виртуального метода
SetParent
. Мы перекрываем этот метод и выполняем в нем как восстановление обработчика старого родителя, так и перехват сообщений нового. Это позволяет компоненту менять родителя во время работы программы. Писать отдельно деструктор для восстановления оригинального обработчика родителя в данном случае нужды нет, поскольку деструктор, унаследованный от
TControl
, содержит вызов метода
SetParent
с параметром
nil
. Так как мы уже перекрыли
SetParent
, это приведет к восстановлению оригинального обработчика, т.е. к тому, что нам нужно.

Если на форму, содержащую

TCoordLabel
, поместить другие компоненты можно заметить, что
TCoordLabel
отлавливает нажатия мыши, сделанные на неоконных компонентах, но игнорирует те, которые сделаны на оконных. Это происходит потому, что неоконные компоненты получают сообщения через оконную процедуру родителя (которая перехвачена), а оконные имеют свою оконную процедуру, никак не связанную с оконной процедурой родителя. И, разумеется, компонент
TCoordLabel
имеет те же проблемы с восстановлением оригинального обработчика, что и
TLine
, если на одном родителе расположены несколько компонентов. Соответственно, применять
TCoordLabel
необходимо аккуратно, с учетом возможных последствий.

1.2.4. Пример PanelMsg

Программа PanelMsg показывает, как можно перехватить оконные сообщения, поступающие компоненту, лежащему на форме. В данном случае этим компонентом будет

TPanel
. Для перехвата сообщений используется свойство
WindowProc
панели.

Мы будем обрабатывать два сообщения, приходящих с панели:

WM_RBUTTONDBLCLK
и
WM_PAINT
. Таким образом, наша панель получит возможность реагировать на двойной щелчок правой кнопки мыши, а также рисовать что-то на своей поверхности. С помощью одной только библиотеки VCL это сделать нельзя.

Примечание

Для рисования на поверхности

панели
, вообще говоря, существует более простой и правильный способ: нужно положить
на панель компонент
TPaintBox
, растянуть его на всю область панели и рисовать в его событии OnPaint. Мы здесь используем более сложный способ перехвата сообщения
WM_PAINT
только в учебных целях.

При перехвате сообщения

WM_PAINT
любого компонента, на котором расположены неоконные визуальные компоненты, может возникнуть проблема с перерисовкой этих компонентов. Чтобы продемонстрировать способ решения этих проблем, разместим на панели компонент TLabel, который заодно будет показывать пользователю реакцию на двойной щелчок правой кнопкой мыши. В результате получается окно, показанное на рис. 1.9. При двойном щелчке правой кнопкой мыши на панели надпись Сделайте двойной щелчок правой кнопкой перемещается в то место, где находится курсор. Чтобы перехватить оконную процедуру панели, следует написать метод, который ее подменит, а адрес старого метода сохранить в предназначенном для этого поле. Сам перехват будем осуществлять в обработчике события
OnCreate
формы (листинг 1.29).

Рис. 1.9.
Окно программы PanelMsg

Листинг 1.29. Перехват обработчика сообщений панели

type

 TForm1 = class(TForm)

Panel: TPanel;

Label1: TLabel;

procedure FormCreate(Sender: TObject);

 private

// Здесь будет храниться исходный обработчик сообщений

// панели

FOldPanelWndProc: TWndMethod;

// Этот метод будет перехватывать сообщения,

// предназначенные панели

procedure NewPanelWndProc(var Msg: TMessage);

 end;

...

procedure TForm1.FontCreate(Sender: TObject);

begin

 FOldPanelWndProc := Panel.WindowProc;

 Panel.WindowProc := NewPanelWndProc;

end;

Сам перехватчик выглядит так, как показано в листинге 1.30.

Листинг 1.30. Метод-перехватчик сообщений панели

procedure TForm1.NewPanelWndProc(var Msg: TMessage);

var

 NeedDC: Boolean;

 PS: TPaintStruct;

 PanelCanvas: TCanvas;

begin

 if Msg.Msg = WM_RBUTTONDBLCLK then

 begin

Label1.Left := Msg.LParamLo;

Label1.Top := Msg.LParamHi;

Msg.Result := 0;

 end

 else if Msg.Msg = WM_PAINT then

 begin

// Проверяем, был ли запрошен контекст устройства

// обработчиком, стоящим раньше по цепочке, и если не

// был, то запрашиваем его.

NeedDC := Msg.WParam = 0;

if NeedDC then Msg.WParam := BeginPaint(Panel.Handle, PS);

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

Сама себе хозяйка

Красовская Марианна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Сама себе хозяйка

Ученичество. Книга 2

Понарошку Евгений
2. Государственный маг
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Ученичество. Книга 2

Надуй щеки!

Вишневский Сергей Викторович
1. Чеболь за партой
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Надуй щеки!

На границе империй. Том 9. Часть 4

INDIGO
17. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 4

Эволюционер из трущоб. Том 6

Панарин Антон
6. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Эволюционер из трущоб. Том 6

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

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

Гарем на шагоходе. Том 1

Гремлинов Гриша
1. Волк и его волчицы
Фантастика:
боевая фантастика
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Гарем на шагоходе. Том 1

Академия проклятий. Книги 1 - 7

Звездная Елена
Академия Проклятий
Фантастика:
фэнтези
8.98
рейтинг книги
Академия проклятий. Книги 1 - 7

Беглец

Бубела Олег Николаевич
1. Совсем не герой
Фантастика:
фэнтези
попаданцы
8.94
рейтинг книги
Беглец

Сломанная кукла

Рам Янка
5. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сломанная кукла

Офицер-разведки

Поселягин Владимир Геннадьевич
2. Красноармеец
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Офицер-разведки

Имя нам Легион. Том 9

Дорничев Дмитрий
9. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 9

(Не)нужная жена дракона

Углицкая Алина
5. Хроники Драконьей империи
Любовные романы:
любовно-фантастические романы
6.89
рейтинг книги
(Не)нужная жена дракона

Этот мир не выдержит меня. Том 2

Майнер Максим
2. Первый простолюдин в Академии
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Этот мир не выдержит меня. Том 2