А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
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
формы.

Рис. 1.11.Окно программы GDIDraw
Основная работа выполняется в обработчике события OnPaint
формы. Мы здесь будем разбирать этот обработчик не целиком, а по частям в соответствии с тем, что каждая часть рисует. Начнем с надписи Delphi Kingdomв левом верхнем углу окна (листинг 1.34).
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);
Если присмотреться к надписи, видно, что внутренняя часть контуров букв содержит тот самый рисунок, который был загружен в обработчик OnCreate
(как будто мы нарисовали этот рисунок через трафарет, имеющий форму надписи). По сути, так оно и есть, только называется это не трафарет, а регион отсечения. Регион — это специальный объект, который хранит область произвольной формы. Способы применения регионов различны (см. разд. 1.3.3 ), и один из них — это использование региона для отсечения графического вывода. Если установить регион отсечения для контекста устройства, то, что бы мы ни выводили потом в данный контекст, все, что лежит за пределами региона отсечения, игнорируется.
Интервал:
Закладка: