MyBooks.club
Все категории

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

На сайте mybooks.club вы можете бесплатно читать книги онлайн без регистрации, включая А. Григорьев - О чём не пишут в книгах по Delphi. Жанр: Программирование издательство -,. Доступна полная версия книги с кратким содержанием для предварительного ознакомления, аннотацией (предисловием), рецензиями от других читателей и их экспертным мнением.
Кроме того, на сайте mybooks.club вы найдете множество новинок, которые стоит прочитать.

Название:
О чём не пишут в книгах по Delphi
Издательство:
-
ISBN:
-
Год:
-
Дата добавления:
17 сентябрь 2019
Количество просмотров:
244
Читать онлайн
А. Григорьев - О чём не пишут в книгах по Delphi

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

А. Григорьев - О чём не пишут в книгах по Delphi - описание и краткое содержание, автор А. Григорьев, читайте бесплатно онлайн на сайте электронной библиотеки mybooks.club
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.Для программистов

О чём не пишут в книгах по Delphi читать онлайн бесплатно

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

Чтобы пользователь мог перемещать концы линии, нужно перехватывать и обрабатывать сообщения, связанные с перемещением мыши и нажатием и отпусканием ее левой кнопки (листинг 1.26).

Листинг 1.26. Обработка сообщений мыши

procedure TLine.WMLButtonDown(var Msg: TWMLButtonDown);

var

 DC: HDC;

 OldMode: Integer;

begin

 if PTInRect(Rect(FCoords[0] - 3, FCoords[1] - 3, FCoords[0] + 4, FCoords[1] + 4), Point(Msg.XPos, Msg.YPos)) then

 begin

  FStartMoving := True;

  FDrawLine := False;

  FWinOwner.Refresh;

  FDrawLine := True;

  DC := GetDC(FWinOwner.Handle);

  OldMode := SetROP2(DC, R2_NOT);

  SelectObject(DC, GetStockObject(BLACK_PEN));

  MoveToEx(DC, FCoords[0], FCoords[1], nil);

  LineTo(DC, FCoords[2], FCoords[3]);

  SetROP2(DC, OldMode);

  ReleaseDC(FWinOwner.Handle, DC);

  SetCapture(FWinOwner.Handle);

  Msg.Result := 0;

 end

 else

  if PTInRect(Rect(FCoords[2] - 3, FCoords[3] - 3, FCoords[2] + 4, FCoords[3] + 4), Point(Msg.XPos, Msg.YPos)) then

  begin

   FEndMoving := True;

   FDrawLine := False;

   FWinOwner.Refresh;

   FDrawLine := True;

   DC := GetDC(FWinOwner.Handle);

   OldMode := SetROP2(DC, R2_NOT);

   SelectObject(DC, GetStockObject(BLACK_PEN));

   MoveToEx(DC, FCoords[0], FCoords[1], nil);

   LineTo(DC, FCoords[2], FCoords[3]);

   SetROP2(DC, OldMode);

   ReleaseDC(FWinOwner.Handle, DC);

   SetCapture(FWinOwner.Handle);

   Msg.Result := 0;

  end

else inherited;

end;


procedure TLine.WMLButtonUp(var Msg: TWMLButtonUp);

begin

 if FStartMoving then

 begin

  FStartMoving := False;

  ReleaseCapture;

  FWinOwner.Refresh;

  Msg.Result := 0;

 end

 else if FEndMoving then

 begin

  FEndMoving := False;

  ReleaseCapture;

  FWinOwner.Refresh;

  Msg.Result := 0;

 end

 else inherited;

end;


procedure TLine.WMMouseMove(var Мsg: TWMMouseMove);

var

 DC: HDC;

 OldMode: Integer;

begin

 if FStartMoving then

 begin

  DC := GetDC(FWinOwner.Handle);

  OldMode := SetROP2(DC, R2_NOT);

  SelectObject(DC, GetStockObject(BLACK_PEN));

  MoveToEx(DC, FCoords[0], FCoords[1], nil);

  LineTo(DC, FCoords[2], FCoords[3]);

  FCoords[0] := Msg.XPos;

  FCoords[1] := Msg.YPos;

  MoveToEx(DC, FCoords[0], FCoords[1], nil);

  LineTo(DC, FCoords[2], FCoords[3]));

  SetROP2(DC, OldMode);

  ReleaseDC(FWinOwner.Handle, DC);

  Msg.Result := 0;

 end

 else if FEndMoving then

 begin

  DC := GetDC(FWinOwner.Handle);

  OldMode := SetROP2(DC, R2_NOT);

  SelectObject(DC, GetStockObject(BLACK_PEN));

  MoveToEx(DC, FCoords[0], FCoords[1], nil);

  LineTo(DC, FCoords[2], FCoords[3]);

  FCoords[2] := Msg.XPos;

  FCoords[3] := Msg.YPos;

  MoveToEx(DC, FCoords[0], FCoords[1], nil);

  LineTo(DC, FCoords[2], FCoords[3]);

  SetROP2(DC, OldMode);

  ReleaseDC(FWinOwner.Handle, DC);

  Msg.Result := 0;

 end

 else inherited;

end;

Здесь реализован инверсный способ создания "резиновой" линии, когда при рисовании линии все составляющие ее пикселы инвертируются, а при стирании инвертируются еще раз. Этот способ подробно описан в разд. 1.3.4.2. Перехват сообщений родителя — дело относительно простое, гораздо хуже обстоят дела с удалением компонента, перехватившего сообщения родителя. Пока такой компонент один, проблем не возникает, но когда их несколько приходится обращаться с ними очень аккуратно. Рассмотрим, например, такой код (листинг 1.27).

Листинг 1.27. Пример кода, вызывающего ошибку

Line1 := TLine.Create(Form1);

Line2 := TLine.Create(Form2);

...

Line1.Free;

...

Line2.Free;

Проанализируем, что происходит при выполнении этого кода. Для простоты предположим, что других компонентов, перехватывающих сообщения, здесь нет, и перед выполнением этого кода Form1.WindowProc ссылается на Form1.WndProc, т.е. на собственный обработчик сообщений формы. При создании объекта Line1 он перехватывает обработчик, и Form1.WindowProc начинает ссылаться на Line1.HookOwnerMessage, а ссылка на Form1.WndProc сохраняется в Line1.FOldProc. Объект Line2 также перехватывает обработчик сообщений, и после его создания Form1.WindowProc будет ссылаться на Line2.HookOwnerMessage, a Line2.FOldProc — на Line1.HookOwnerMessage.

Теперь удалим Line1. При удалении объект восстановит ссылку на тот обработчик сообщений, который был установлен на момент его создания, т.е. Form1.WindowProc вновь станет указывать на Form1.WndProc. Соответственно, компонент Line2 потеряет способность реагировать на сообщения владельца. Поле Line2.FOldProc при этом останется без изменений. Но самое неприятное начнется при удалении объекта Line2. Он тоже восстановит ссылку на обработчик, который был назначен на момент его создания, т.е. запишет в свойство Form1.WindowProc ссылку на Line1.HookOwnerMessage. Но поскольку объекта Line1 уже не существует, это будет ссылка в никуда, и обработка первого же сообщения, пришедшего форме, даст ошибку Access violation.

Примечание

Аналогичная проблема возникнет и в режиме проектирования, если на форму положить два компонента TLine, удалить первый, a затем — второй. В этом случае ошибки возникнут в самой среде Delphi, и ее придется перезапускать. Вообще говоря, компоненты, перехватывающие сообщения владельца, должны делать это только во время выполнения программы, чтобы не "уронить" среду. Здесь мы для наглядности опустили соответствующие проверки.

Проблема не возникает, если удалять объекты в порядке, обратном порядку их создания. Но в общем случае это не может быть решением проблемы, т.к. объекты должны создаваться и удаляться в том порядке, который требуется логикой работы программы. Соответственно, единственное решение — все перехватывающие сообщения владельца компоненты должны знать друг о друге и уведомлять друг друга о своем создании и удалении. Но и этот способ не дает полной гарантии. Пока один разработчик пишет компонент или библиотеку компонентов, он может обеспечить взаимодействие всех экземпляров компонентов в программе. Но если в одной программе будут использованы две такие библиотеки от разных разработчиков, они так же будут конфликтовать друг с другом, и универсального решения проблемы, судя по всему, не существует. Пользователю библиотек остается только соблюдать порядок удаления компонентов. Но, с другой стороны, есть ряд задач, в которых без перехвата сообщений владельца не обойтись, поэтому иногда приходится идти на это.

1.2.3. Пример CoordLabel

CoordLabel — это пример визуального компонента, перехватывающего сообщения своего родителя. Компонент TCoordLabel отслеживает нажатие левой кнопки мыши на своем родителе и отображает координаты точки, в которой произошло нажатие. Для перехвата сообщений родителя используется тот же способ через свойство WindowProc, что и в предыдущем примере, но т.к. теперь перехватываются сообщения родителя, а не владельца, появляются некоторые нюансы.

Установка компонента TCoordLabel полностью аналогична установке компонента TLine из предыдущего раздела. На прилагаемом компакт-диске находится также проект LineCoordSample для того, чтобы работу компонента можно было увидеть без установки в палитру компонентов. На форме проекта LineCoordSample находится панель, кнопка Переместить и компонент TLineCoordSample, который по нажатию кнопки меняет родителя с формы на панель и обратно.

Код компонента TCoordLabel приведен в листинге 1.28.

Листинг 1.28. Компонент TCoordLabel

type

 TCoordLabel = class(TLabel)

private

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

 // сообщений, бывший до перехвата.

 FOldProc: TWndMethod;

protected

 procedure SetParent(AParent: TWinControl); override;

 // Этот метод будет новым обработчиком

 // сообщений владельца

 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.


А. Григорьев читать все книги автора по порядку

А. Григорьев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки mybooks.club.


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

Отзывы читателей о книге О чём не пишут в книгах по Delphi, автор: А. Григорьев. Читайте комментарии и мнения людей о произведении.

Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*
Все материалы на сайте размещаются его пользователями.
Администратор сайта не несёт ответственности за действия пользователей сайта..
Вы можете направить вашу жалобу на почту librarybook.ru@gmail.com или заполнить форму обратной связи.