Recent

Author Topic: Как Компоненту перехватить сообщения, адресованные окну?  (Read 3989 times)

Alexandr R

  • New Member
  • *
  • Posts: 24
 Здравствуйте.
 Есть окно (TForm), на нём, к примеру, расположен TEdit и есть ещё ErrMsg:THintWindow. ErrMSG ругается на Пользователя при вводе некорректных данных - Пользователь психует и перемещает окно (TForm) по экрану монитора. ErrMSG остаётся на месте, но должен последовать за TEdit.
 Как перехватиь сообщение WM_Move (LM_MOVE) компоненту TEdit. Использовать события TForm или послать сообщение из TForm - не вариант, использовать таймер для опроса местоположения TEdit на  мониторе - крайний случай. Отцы программирования есть мысли? Всем заранее Спасибо. 

Otto

  • Full Member
  • ***
  • Posts: 226
Hello Alexandr R.
I'm not sure I understand your problem.
If I understand correctly you could use a custom form instead of a Message-Box to report the error (surely there could be better solutions).
Try checked these links.

https://wiki.freepascal.org/Form_Tutorial#Difference_between_Show_and_ShowModal
https://www.freepascal.org/~michael/articles/customform/customform.pdf

If you could post a small project someone could respond more accurately to you.
« Last Edit: March 03, 2020, 02:02:01 pm by Otto »
Kind regards.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
ак перехватиь сообщение WM_Move (LM_MOVE) компоненту TEdit.
не надо перехватывать, надо оповещать.
При создании ErrMsg, он должен искать родительское окно (TForm) (или TForm на котором лежит TEdit)
Регистрироваться у него на оповщение о смещении.

TForm при своём передвижении (о котором TForm знает) будет оповещать список зарегестрированным компонентов, о том, что произошёл сдвиг.

Alexandr R

  • New Member
  • *
  • Posts: 24
Re Скалогрызу:
"TForm при своём передвижении (о котором TForm знает) будет оповещать список зарегестрированным компонентов, о том, что произошёл сдвиг."
 Я лет 30 не занимался программированием (мне 58), нужда заставила. Но как это сделать? Пример какой-нибудь посмотреть. Пытаюсь создать компонент TDegreeEdit в связке с THintWindows. По отдельности всё работает (орфографию исправить шероховатости убрать).
Re Отто, Скалогрызу:
ССылка  присуствует ( https://yadi.sk/d/tSgE1a9vRbc-Lg  ), создать окно с сообщением не проблема но хотелось бы использовать Hint.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
а в чём проблема с текущим подходом? вполне себе нормально работает.
я бы только SetBounds переписал бы следующим образом:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
  2. begin
  3.  inherited;
  4.  if Form1.IsVisible then
  5.   begin
  6.    if MsgError <> '' then
  7.      SetRectHint(MsgError)       //и включаем если подсказка существует}
  8.    else if (FMyHintWindow<>nil) then
  9.      FMyHintWindow.Hide;
  10.   end;
  11. end;
  12.  
и все места, где FMyHintWindow.ReleaseHandle, заменить на FMyHintWindow.Hide;

да, и вместо SetBounds лучше исползовать событие фотрмы OnChangeBounds.

Otto

  • Full Member
  • ***
  • Posts: 226
Hello Alexandr.
I've tried your software, the problem is in the tool-tip (or equivalent) that stays in the foreground when you minimize the software and that flickers when you drag the form, right?
If so, as a temporary solution, you could replace the tool-tip with a TPanel.
I also suggest you follow the great advice of skalogryz.
As soon as I have some free time I will check your code to look for a specific solution to your problem.

Otto.
Kind regards.

Alexandr R

  • New Member
  • *
  • Posts: 24
Спасибо Отто, Спасибо Скалогрыз. Я Вам очень благодарен.
Thank you Otto, thank you Skalogryz. I am very grateful to you.

Alexandr R

  • New Member
  • *
  • Posts: 24
Итак, есть виджет-компонент, который помещают на форму. Пускай называется TDegreeEdit или ТHintEdit.
TDegreeEdit состоит из редактора и всплывающей подсказки извещающей об ошибках ввода данных. По отношению к своему владельцу он должен быть "чёрным ящиком", то есть виджет принимает входные данные (параметры определяющие поведение виджета и собственно данные, которые он обрабатывает) и возвращает результат их обработки. В качестве всплывающей подсказки решил использовать THintWindos. Но THint это отдельное окно "поверх всех". Поначитался разных книг ну и вот такое решение в голову пришло. (наверно это бред, и как насчёт кросспратвормености? В данный момент не могу проверить).


Code: Pascal  [Select][+][-]
  1. type
  2.  THintEdit = class(TCustomEdit)
  3.   private
  4.    FMyParent: TComponent;//владелец может меняться в процессе выполнения программы
  5.    FHint: THintWindow;
  6.    FOldProc: TWndMethod; //Старый обработчик.
  7.   protected
  8.    //новый обработчик сообщений владельца
  9.    procedure SetParent(AParent: TWinControl); override;
  10.    procedure HookParentMessage(var Msg: TMessage);
  11.  end;
  12. ...
  13. procedure THintEdit.SetParent(AParent: TWinControl);
  14. begin
  15.  if Assigned(FMyParent) and Assigned(FOldProc) then Parent.WindowProc := FOldProc;
  16.  inherited;
  17.  if Assigned(FMyParent) then
  18.   begin
  19.    FOldProc := Parent.WindowProc;
  20.    Parent.WindowProc := HookParentMessage;
  21.   end;
  22. end;
  23. ...
  24. procedure THintEdit.HookParentMessage(var Msg: TMessage);
  25. begin
  26.  begin
  27.  //что-то делаем с FHint
  28.  Case Msg.Msg of
  29.   LM_Move:     ...;
  30.   LM_ACTIVATE: ...;
  31.   SC_MINIMIZE,
  32.   SC_MAXIMIZE: ...;
  33.  end;
  34.  FMyParent.WindowProc := FOldProc(Msg);
  35.  inherited;
  36. end;
  37.  
« Last Edit: March 06, 2020, 05:20:26 pm by Alexandr R »

Otto

  • Full Member
  • ***
  • Posts: 226
Hello Alexandr.
I'm checking your software.
I would recommend that you hide the FMyHintWindow during the OnDeactivate event of the main form.
This will allow the form to be minimized and the "Tool-Tip" will be hidden.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormDeactivate(Sender: TObject);
  2. begin
  3.   FMyHintWindow.Hide;
  4. end;  
  5.  

I didn't quite understand this phrase from your last post.
(наверно это бред, и как насчёт кросспратвормености? В данный момент не могу проверить).

I haven't finished studying your software yet.
I hope what's reported helps you.
Kind regards.

Alexandr R

  • New Member
  • *
  • Posts: 24
Re Otto
Good night Otto (we have a night)
  "(наверно это бред, и как насчёт кросспратворменности? В данный момент не могу проверить)." - The automatic translation of the meaning (essence) of this phrase into English is probably incorrectly made - do not pay attention.
Well, in Delphi, you can replace the widget's message handler with the parent's message handler (the widget's host). This is probably wrong. (The meaning of the quote is,"В данный момент не могу проверить" - there is no access to the computer, only a smartphone).
In principle, I solved the problem of displaying input errors (it works like in an Exel cell), but I'm interested in fighting THintWindos.
There will be success - I will unsubscribe to You.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
There will be success - I will unsubscribe to You.
"я тебе отпишусь" переводится как "i will let you know", ну или "will keep you posted!"

Поначитался разных книг ну и вот такое решение в голову пришло.
ну более менее решение. Там только тонкость в том, когда убирать WindowProc. Если таких DegreeEdit будет несколько, то узнать в каком порядке они ссылаются на FOldProc может быть сложно.

Задачу можно решить немного иным способом.
На момент первого показа THintWindow выполнять следующее.
1. от DegreeEdit нужно проходить по йерархии Parent пока не найдётся TCustomForm
Code: Pascal  [Select][+][-]
  1. var
  2.   c : TControl;
  3.  
  4.   c:=DegreeEdit.parent;
  5.   while Assigned(c) and not (c is TCustomForm) do c := c.Parent;
  6.  

2. если c нашёлся. (c<>nil), до добавлять к нему обработчик, по изменению положения
Code: Pascal  [Select][+][-]
  1.   c.AddHandlerOnChangeBounds( @hintwindow.HostWindowChangeBounds );
  2.  
3. а в HostWindowChangeBounds соответственно менять координаты. Параметр "Sеnder" будет является тем самым окном
Code: Pascal  [Select][+][-]
  1. procedure TDegreeEditHintWindow.HostWindowChangeBounds(Sender: TObject);
  2. var
  3.  Rect: TRect;
  4.   ...
  5. begin
  6.  Point:= ClientToScreen(TPoint.Create(EditDmsToDeg.Left, EditDmsToDeg.Top));
  7.   ... вся та магия из примера...
  8.  Rect.Left  := Point.x;
  9.  Rect.Top   := Point.y-HeightStrInPixsel;
  10.  Rect.Right := Point.x+LenStrInPixel;
  11.  Rect.Bottom:= Point.y;;
  12.   Bounds := REct;
  13. end;

4. ВАЖНО! при закрытии/уничтожении THintWindow обязательно нужно отписываться о нотификации сообщений
Code: Pascal  [Select][+][-]
  1.   c.RemoveHandlerOnChangeBounds( @hintwindow.HostWindowChangeBounds );

 

TinyPortal © 2005-2018