Григорьев Антон Борисович - О чём не пишут в книгах по Delphi стр 34.

Шрифт
Фон

Листинг 1.33. Модуль главной формы программы ButtonDel

unit BDMain;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

// Определяем свое сообщение. Константа, добавляемая к

// WM_USER, может иметь произвольное значение в диапазоне

// от 0 до 31743.

const

WM_DELETEBUTTON = WM_USER + 1;

type TForm1 = class(TForm)

BtnDeleteSelf: TButton;

procedure BtnDeleteSelfClick(Sender: TObject);

private

// Определяем метод - обработчик событий WM_DELETEBUTTON.

// Ему будет передано управление через Dispatch.

procedure WMDeleteButton(var Msg: TMessage); message WM_DELETEBUTTON;

public

{ Public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BtnDeleteSelfClick(Sender: TObject);

begin

// Помещаем сообщение WM_DELETEBUTTON в очередь формы.

// Указатель на объект, который нужно удалить, помещаем

// в LParam. В 32-разрядных версиях Windows указатель

// можно помещать как в wParam, так и в lParam, но по

// традиции, берущей начало в 16-разрядных версиях,

// указатель обычно передают через lParam.

PostMessage(Handle, WM_DELETEBUTTON, 0, LParam(BtnDeleteSelf));

// Здесь принципиально использование PostMessage, а не

// SendMessage. SendMessage в данном случае привел бы к

// немедленному вызову оконной процедуры, и метод

// WMDeleteButton был бы вызван до завершения работы

// BtnDeleteSelfClick. Это привело бы к тому же

// результату, что и прямой вызов BtnDeleteSelf.Free.

end;

procedure TForm1.WMDeleteButton(var Msg: TMessage);

begin

// Просто удаляем объект, указатель на который передан

// через lParam.

TObject(Msg.LParam).Free;

end;

end.

Приведенный здесь способ хорошо работает в такой простой ситуации, но в более сложных случаях может не дать результата. Рассмотрим, например, ситуацию, когда на форме лежат две кнопки: Button1 и Button2. Обработчик нажатия Button1 содержит длительную операцию, и поэтому в нем вызывается Application.ProcessMessages. Обработчик нажатия Button2 содержит строку Button1.Free. Если после запуска программы сразу нажать Button2, проблем не возникнет и объект Button1 будет благополучно удален. Но если сначала нажать Button1, а затем - Button2, возникнет ошибка. Это произойдёт потому, что нажатие Button2 будет в данном случае обработано локальной петлей сообщения, и после обработки управление вернется Button1Click, а оттуда - в методы уже не существующего объекта Button1. Посылка в Button2Click сообщения форме здесь не поможет, потому что это сообщение также будет извлечено и обработано локальной петлей. Общего решения таких проблем, видимо, не существует. В сложных случаях можно посоветовать не удалять объект, а просто прятать его (Visible := False) - видимый результат для пользователя будет тот же самый.

1.2.7. Пример GDIDraw

Программа GDIDraw демонстрирует некоторые возможности GDI, которые не поддерживаются классом TCanvas. Выбраны только те возможности, которые поддерживаются не только в Windows NT/2000/XP, но и в 9x/ME. Окно программы показано на рис. 1.11.

В своей работе программа использует рисунок из стандартных картинок Delphi, предполагая, что эти картинки установлены в папку "С:\Program Files\Common Files\Borland Shared\Images". Если у вас эти картинки установлены в другую папку, или по каким-то причинам вы хотите выбрать другой рисунок, измените обработчик события OnCreate формы так, чтобы он загружал рисунок из нужного вам файла. Загруженный рисунок сохраняется в поле FBitmap формы.

Антон Григорьев - О чём не пишут в книгах по Delphi

Рис. 1.11. Окно программы GDIDraw

Основная работа выполняется в обработчике события OnPaint формы. Мы здесь будем разбирать этот обработчик не целиком, а по частям в соответствии с тем, что каждая часть рисует. Начнем с надписи Delphi Kingdom в левом верхнем углу окна (листинг 1.34).

Листинг 1.34. Вывод надписи Delphi Kingdom

var

R: TRect;

...

// Формируем регион, использующийся для отсечения.

// Формируем его только при первом вызове метода, а при

// дальнейших используем созданный ранее. Поле FRgn

// содержит дескриптор этого региона

if FRgn = 0 then

begin

Canvas.Font.Name := 'Times New Roman';

Canvas.Font.Style := [fsBold];

Canvas.Font.Height := 69;

// Начинаем рисование траектории. Все вызовы

// графических функций, находящиеся между BeginPath

// и EndPath, не будут приводить к выводу на экран.

// Вместо этого информация о том, что рисуется, будет

// сохраняться а специальном объекте GDI - траектории.

BeginPath(Canvas.Handle);

R := Rect(10, 10, 10 + FBitmap.Width, 10 + FBitmap.Height);

// Если не установить с помощью SetBkMode прозрачный

// фон, в траекторию попадут не только контуры букв,

// но и контуры содержащих их прямоугольных знакомест.

SetBkMode(Canvas.Handle, TRANSPARENT);

// Выводим текст "Delphi Kingdom", выравнивая его по

// центру по вертикали и горизонтали.

DrawText(Canvas.Handle, 'Delphi'#13#10'Kingdom', -1, R,

DT_CENTER or DT_VCENTER);

EndPath(Canvas.Handle);

// Превращаем траекторию в регион. В результате вызова

// этой функции получится регион, контуры которого

// совпадают с контурами надписи "Delphi Kingdom",

// сделанной в указанных координатах выбранным шрифтом.

FRgn := PathToRegion(Canvas.Handle);

end;

// Устанавливаем регион отсечения. Все, что не будет

// попадать в выбранный регион, при выводе будет

// игнорироваться.

SelectClipRgn(Canvas.Handle, FRgn);

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

// региона, отсекается. Таким образом, получаем надпись

// "Delphi Kingdom", подсвеченную выбранным изображением.

Canvas.Draw(10, 10, FBitmap);

// Отменяем отсечение по региону

SelectClipRgn(Canvas.Handle, 0);

Ваша оценка очень важна

0
Шрифт
Фон

Помогите Вашим друзьям узнать о библиотеке