OpenGL в Delphi

Вывод с использованием функций GDI


В первом разделе мы рассмотрели, как, получив ссылку на чужое окно, можно производить с ним некоторые действия, например, закрыть его.
Точно так же, если необходимо нарисовать что-либо на поверхности чужого окна, первым делом нужно получить ссылку на него.
Для начала попробуем рисовать на поверхности родного окна.
Разместите еще одну кнопку, обработку щелчка которой приведите к следующему виду (проект из подкаталога Ex09):

procedure TForma2. Button2Click(Sender: TObject);
var
dc: HDC; // ссылка на контекст устройства
begin
dc: = GetDC (Handle); // задаем значение ссылки
Rectangle (dc, 10, 10, 110, 110); // рисуем прямоугольник
ReleaseDC (Handle, dc);
// освобождение ссылки DeleteDC (dc);
// удаление ссылки, освобождение памяти
end;

Запустите приложение. После щелчка на добавленной кнопке на поверхности окна рисуется квадрат.
Для рисования в этом примере используем низкоуровневые функции вывода Windows, так называемые функции GDI (Graphic Device Interface, интерфейс графического устройства). Эти функции требуют в качестве одного из своих аргументов ссылку на контекст устройства.
Тип такой величины - hdc (Handle Device Context, ссылка на контекст устройства), значение ее можно получить вызовом функции API GetDC с аргументом-ссылкой на устройство вывода. В нашем примере в качестве аргумента указана ссылка на окно.
После получения ссылки на контекст устройства обращаемся собственно к функции, строящей прямоугольник. Первым аргументом этой функции является ссылка на контекст устройства.
После использования ссылки ее необходимо освободить, а в конце работы приложения - удалить для освобождения памяти.
Поставленная "клякса" будет оставаться на окне формы при изменении размеров окна и исчезнет только при его перерисовке, для чего можно, например, минимизировать окно формы, а затем вновь его развернуть. Исчезновение квадрата после такой операции объясняется тем, что за перерисовку окна отвечает его собственный обработчик.
Теперь попробуем порисовать на поверхности чужого окна, для чего изменим только что написанный код (готовый проект находится в подкаталоге Ех10):

procedure TForm2. Button2Click(Sender: TObject);
var
dc: HDC; Window: HWND; begin
Window: = FindWindow ('TForml', 'Forml'); If Window <> 0 then begin // окно найдено
dc: = GetDC (Window); // ссылка на найденное окно
Rectangle (dc, 10, 10, 110, 110); // квадрат на чужом окне
ReleaseDC (Window, dc); // освобождение ссылки
DeleteDC (dc); // удаление ссылки
end;
end;

Теперь при щелчке на кнопке, если в системе зарегистрировано хотя бы одно окно класса 'TForm1' с заголовком 'Form1', вывод (рисование квадрата) будет осуществляться на него.
Запустите параллельно откомпилированные модули минимального и только что созданного приложений. При щелчке на кнопке квадрат рисуется на поверхности чужого окна.
Замечу, что если закрыть Projectl. exe и загрузить в Delphi соответствующий ему проект, то при щелчке на кнопке прямоугольник будет рисоваться на поверхности окна формы, что будет выглядеть необычно.
Этот эксперимент показывает, что окна, создаваемые Delphi во время проектирования, такие же равноправные окна, как и любые другие, т. e. они регистрируются в операционной системе, идентифицируются, и любое приложение может иметь к ним доступ. Если попытаться минимизировать окно класса 'TForm1', окно формы будет отрабатывать эту команду точно так же, как полученную от пользователя.
Следует обратить внимание на то, что мы не можем рисовать на поверхности вообще любого окна. Например, не получится, поменяв имя класса окна на 'TAppBuilder', поставить "кляксу" на главном окне среды Delphi.
Окно со значением ссылки, равным нулю, соответствует окну рабочего стола. В примере Exll я воспользовался этим, чтобы нарисовать квадратик на рабочем столе:

procedure TForm2. Button2Click(Sender: TObject);
var
dc: HDC;
begin
dc: = GetDC (0); // получаю ссылку на рабочий стол
Rectangle (dc, 10, 10, 110, 110);
ReleaseDC (Handle, dc);
DeleteDC (DC);
end;

Во всех примерах этого раздела я для вывода использовал функции GDI потому, что если для вывода на родном окне Delphi и предоставляет удобное средство - методы свойства формы canvas, то для вывода на чужом окне мы этими методами воспользоваться не сможем в принципе. Разберем основные детали вывода с помощью функций GDI. B проекте из подкаталога Exl2 оконная функция минимальной программы дополнилась обработкой сообщения WM_PAINT. Вывод заключен между строками с вызовом функций BeginPaint и EndPaint, первая из которых возвращает ссылку на контекст устройства, т. e. величину типа HDC, требуемую для функций вывода GDI. Еще раз повторю, что после использования ссылки ее необходимо освободить и удалить по окончании работы - это необходимо для корректной работы приложения. Смысл ссылки на контекст устройства мы подробно обсудим немного позже.
Остальные строки кода подробно прокомментированы, так что, надеюсь, особых вопросов не вызовут, разве только начинающих может в очередной раз поразить обширность кода, возникающая при отказе от удобств, предоставляемых библиотекой классов Delphi (которая выполняет за программиста всю черновую работу и превращает разработку программы в сплошное удовольствие).



Содержание раздела