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

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

Жанры

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

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

Шрифт:

// Вызываем старый обработчик WM_PAINT. Его нужно

// вызывать обязательно до того, как мы начнем рисовать

// на поверхности что-то свое, т.к. в противном случае

// это что-то будет закрашено стандартным обработчиком.

POldPanelWndProc(Msg);

// При использовании графических функций API самое

// неудобное - это вручную создавать и уничтожать кисти,

// карандаш и т.п. Поэтому здесь создается экземпляр

// класса TCanvas для рисования на контексте устройства

//
с дескриптором, полученным при вызове BeginPaint.

PanelCanvas := TCanvas.Create;

try

PanelCanvas.Handle := Msg.WParam;

FanelCanvas.Pen.Style := psClear;

PanelCanvas.Brush.Style := bsSolid;

PanelCanvas.Brush.Color := clWhite;

PanelCanvas.Ellipse(10, 10, Panel.Width - 10, Panel.Height - 10);

PanelCanvas.Brush.Color := clYellow;

PanelCanvas.Rectangle(100, 100, Panel.Width - 100, Panel.Height - 100);

finally

PanelCanvas.Free;

end;

// В данном случае панель содержит визуальный неоконный

// компонент TLabel. Отрисовка неоконных компонентов

// происходит при обработке WM_PAINT родительского

// компонента, т.е. здесь она была выполнена при вызове

// стандартного обработчика. Таким образом, сделанный

// рисунок закрасил не только фон панели, но и

// неоконные компоненты. Чтобы компоненты были поверх

// рисунка, их приходится перерисовывать еще раз,

// вызывая protected-метод PaintControls. Это не очень

// эффективно, т.к. получается, что компоненты рисуются

// дважды: в стандартном обработчике и здесь. Но

// другого способа решить проблему, видимо, нет. Если

// бы на панели лежали только оконные компоненты,

// вызывать PaintControls не понадобилось, поскольку то, что

// мы рисуем на панели, не может затереть поверхность

// лежащих на этой панели других окон.

TFakePanel(Panel).PaintControls(Msg.WParam, nil);

// Если мы получали контекст устройства, мы же должны

// освободить его.

if NeedDC then

begin

EndPaint(Panel.Handle, PS);

Msg.WParam := 0;

end;

 end

 else FOldPanelWndProc(Msg);

end;

Так как в наш обработчик поступают все сообщения, передающиеся в оконную процедуру панели, начинается он с проверки того, какое сообщение пришло. Сначала реализуем реакцию на

WM_RBUTTONDBLCLK
просто перемещаем метку
Label1
на то место, где пользователь щелкнул мышью. Затем обнуляем результат, давая понять системе, что сообщение полностью обработано. Вызов унаследованного обработчика в данном случае не выполняем, потому что никакая унаследованная реакция на данное событие нам не нужна. Обработка сообщения
WM_PAINT
сложнее. Сначала необходимо разобраться с контекстом устройства, на котором будет производиться рисование. Вообще говоря, обработчик
WM_PAINT
должен получать этот контекст с помощью функции
BeginPaint
. Но если до написанного нами кода сообщение
WM_PAINT
уже
начало обрабатываться, то контекст устройства уже получен, а вызывать
BeginPaint
два раза нельзя. В этом случае контекст устройства передаётся через параметр сообщения
WParam
. Соответственно, обработка сообщения
WM_PAINT
начинается с того, что мы проверяем, равен ли нулю параметр
wParam
, и если равен, то получаем контекст устройства, а если не равен, используем то, что передано.

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

FOldPanelWndProc
. Только после этого можно что-то рисовать.

Примечание

Перекрывая обработку сообщения

WM_PAINT
, мы лишаем код VCL возможности полностью контролировать процесс перерисовки. В частности, это означает что значение свойства
DoubleBuffered
будет игнорироваться, двойной буферизации не будет. Поэтому еще раз напоминаем, что программа
PanelMsg
 — это учебный пример, помогающий разобраться с механизмами взаимодействия VCL и Windows API, но не являющийся образцом для подражания. Если в реальной жизни потребуется рисовать что-то непосредственно на панели, нужно порождать от класса
TPanel
наследника и перекрывать в нем метод
Paint
.

Теперь можно нарисовать что-то свое. Здесь мы рисуем большой белый круг, а на его фоне — желтый прямоугольник. Для этого используем класс

TCanvas
способом, который был продемонстрирован в листинге 1.17 (см. разд. 1.1.11). Если бы мы остановились на этом, то увидели бы интересную картину: нарисованные фигуры лежат поверх текста метки
Label1
. Объяснение этому очень простое: метка является неоконным визуальным компонентом и рисуется на поверхности своего родительского компонента при обработке его сообщения
WM_PAINT
. А поскольку стандартный обработчик у нас вызывается до того, как рисуются круг и прямоугольник, любой неоконный компонент будет перекрыт ими. К оконным компонентам это, разумеется, не относится, они лежат над родительской панелью, и то, что мы рисуем на этой панели, не может оказаться над ними.

Мы не можем вставить свой код между рисованием непосредственно поверхности панели и рисованием компонентов на ней. Поэтому после отработки нашего кода приходится рисовать неоконные компоненты еще раз. Проще всего это сделать, вызвав метод

PaintControls
, который и используется стандартным обработчиком. Конечно, получится, что неоконные компоненты рисуются дважды: в стандартном обработчике и в нашем, и это не очень хорошо. Но повторим еще раз, что программа
PanelMsg
— не образец для подражания, а что-то вроде зонда для исследования особенностей работы VCL.

Вызов метода

PaintControls
затруднен тем, что он объявлен в разделе
protected
, а потому не может быть вызван из метода
NewPanelWndProc
, который относится к классу формы. Чтобы обойти это ограничение, нужно породить наследника от
TPanel
TFakePanel
. Этот наследник ничего не добавляет к классу
TPanel
и ничего не переопределяет в нем. Но раз он объявлен в нашем модуле, все его
protected
– члены, в том числе и унаследованный метод
PaintControls
, становятся доступными в нем. После этого мы можем привести поле, содержащее ссылку на панель, к этому типу и вызвать
PaintControls
. Так как структуры типов
TPanel
и
TFakePanel
идентичны, это приведет к вызову нужного метода.

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

Тринадцатый VIII

NikL
8. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Тринадцатый VIII

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

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

Архил…? Книга 3

Кожевников Павел
3. Архил...?
Фантастика:
фэнтези
попаданцы
альтернативная история
7.00
рейтинг книги
Архил…? Книга 3

Неудержимый. Книга VIII

Боярский Андрей
8. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
6.00
рейтинг книги
Неудержимый. Книга VIII

Контртеррор

Валериев Игорь
6. Ермак
Фантастика:
альтернативная история
5.00
рейтинг книги
Контртеррор

Княжья Русь

Мазин Александр Владимирович
6. Варяг
Приключения:
исторические приключения
9.04
рейтинг книги
Княжья Русь

Казачий князь

Трофимов Ерофей
5. Шатун
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Казачий князь

Я еще не барон

Дрейк Сириус
1. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я еще не барон

Низший - Инфериор. Компиляция. Книги 1-19

Михайлов Дем Алексеевич
Фантастика 2023. Компиляция
Фантастика:
боевая фантастика
5.00
рейтинг книги
Низший - Инфериор. Компиляция. Книги 1-19

Господин следователь. Книга 4

Шалашов Евгений Васильевич
4. Господин следователь
Детективы:
исторические детективы
5.00
рейтинг книги
Господин следователь. Книга 4

Жена неверного маршала, или Пиццерия попаданки

Удалова Юлия
Любовные романы:
любовно-фантастические романы
4.25
рейтинг книги
Жена неверного маршала, или Пиццерия попаданки

Возвышение Меркурия. Книга 4

Кронос Александр
4. Меркурий
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Возвышение Меркурия. Книга 4

Я — Легион

Злобин Михаил
3. О чем молчат могилы
Фантастика:
боевая фантастика
7.88
рейтинг книги
Я — Легион

Изменяющий-Механик. Компиляция. Книги 1-18

Усманов Хайдарали
Собрание сочинений
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
Изменяющий-Механик. Компиляция. Книги 1-18