Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 977

/ вопрос открыт /

Доброго времени суток, уважаемые эксперты!
Как реализовать "Click pass though" ( т.е. чтобы форма пропускала щелчки под себя) ?

Legat Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: Legat (статус: Посетитель)
Вопрос отправлен: 13 октября 2007, 15:15
Состояние вопроса: открыт, ответов: 2.

Ответ #1. Отвечает эксперт: Матвеев Игорь Владимирович

Здравствуйте, Legat!
Довольно интересный вопрос, хотя в принципе алгоритм действий довольно прост:
1. Определить экранные координаты клика (WM_LBUTTONDOWN/WM_LBUTTONUP/WM_MOUSEMOVE);
2. Найти окно, находящееся в Z-Order ниже Вашего и, в то же время, попадающего под координаты клика;
3. Перебрать дочерние окна найденного ранее окна в поисках контрола, в который попадает клик (кнопка, поле ввода и т.д), ели не найденно, считать целевым окном окно, найденное в п.2;
4. Передать сообщение WM_LBUTTONDOWN/WM_LBUTTONUP/WM_MOUSEMOVE) целевому окну.

К сожалению у меня нет достаточно времени, чтобы реализовать все полностью, но я подготовил для Вас каркас. См. Приложение.

В архиве исходники двух проектов: первый - log - монитор "мышиных" сообщений, второй - собственно сам пример, полупрозрачная форма (чтобы было видно куда нажимаешь) пропускает клики на окна ниже, но не кликает по дочерним контролам (кнопки, поля ввода и т.д.), Вам предстоит доделать это самому. Также Вам нужно изменить код перевода абсолютных координат клика в относительные координаты клиентской области целевого окна (нужно учитывать заголовок и толщину границ окна). Эти места отмечены комментариями в коде.

Также необходимо сделать еще одно замечание:
Если целевое окно будет непрямоугольной формы и именно в месте клика окажется пустая область - клик все-равно будет передан этому окну т.к. "принаждежность" клика определяется по принадлежности прямоугольной области окна (GetWindowRect). В этом случае можно использовать GetWindowRgn()/PtInRegion();
К ответу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки ответа)

Ответ отправил: Матвеев Игорь Владимирович (статус: Студент)
Время отправки: 14 октября 2007, 14:46
Оценка за ответ: 2

Комментарий к оценке: Это очень-очень-очень неправильный сопособ..... Очень!
Тем не менее, спасибо за ответ, и то приятнее, чем когда вообще на вопрос не отвечают...

Ответ #2. Отвечает эксперт: Feniks

Здравствуйте, Legat!
Попробуйте примеры из Приложений... Может какой-то и подойдет.

Приложение:
  1.  
  2.  
  3. <code>unit transpar_frm;
  4.  
  5. interface
  6. uses
  7. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  8. StdCtrls;
  9. type
  10. TForm1 = class(TForm)
  11. Button1: TButton;
  12. Button2: TButton;
  13. CheckBox1: TCheckBox;
  14.  
  15. protected
  16. procedure RebuildWindowRgn;
  17. procedure Resize; override;
  18. public
  19. constructor Create(AOwner: TComponent); override;
  20. end;
  21. var
  22. Form1 : TForm1;
  23. implementation
  24.  
  25. {$R *.DFM}
  26.  
  27. constructor TForm1.Create(AOwner: TComponent);
  28. begin
  29. inherited;
  30.  
  31. FormStyle:=fsStayOnTop;
  32.  
  33.  
  34. HorzScrollBar.Visible:= False;
  35. VertScrollBar.Visible:= False;
  36.  
  37. RebuildWindowRgn;
  38. end;
  39. procedure TForm1.Resize;
  40. begin
  41. inherited;
  42.  
  43. RebuildWindowRgn;
  44. end;
  45. procedure TForm1.RebuildWindowRgn;
  46. var
  47. FullRgn, Rgn: THandle;
  48. ClientX, ClientY, I: Integer;
  49. begin
  50.  
  51. ClientX:= (Width - ClientWidth) div 2;
  52. ClientY:= Height - ClientHeight - ClientX;
  53.  
  54. FullRgn:= CreateRectRgn(0, 0, Width, Height);
  55.  
  56.  
  57. Rgn:= CreateRectRgn(ClientX, ClientY, ClientX + ClientWidth, ClientY +
  58. ClientHeight);
  59. CombineRgn(FullRgn, FullRgn, Rgn, rgn_Diff);
  60.  
  61. for I:= 0 to ControlCount -1 do
  62. with Controls[I] do begin
  63. Rgn:= CreateRectRgn(ClientX + Left, ClientY + Top, ClientX + Left +
  64. Width, ClientY + Top + Height);
  65. CombineRgn(FullRgn, FullRgn, Rgn, rgn_Or);
  66. end;
  67.  
  68. SetWindowRgn(Handle, FullRgn, True);
  69. end;
  70. end.</code>
  71. ///////////////////////////////////////////////////////////////////////////////////
  72.  
  73.  
  74.  
  75. <code>type
  76.  
  77. TForm1 = class(TForm)
  78. procedure FormCreate(Sender: TObject);
  79. protected
  80. procedure CreateParams (var Params: TCreateParams); override;
  81. end;
  82.  
  83. var
  84. Form1: TForm1;
  85.  
  86. implementation
  87.  
  88. ...
  89.  
  90. procedure TForm1.FormCreate(Sender: TObject);
  91. begin
  92. SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
  93. SetLayeredWindowAttributes(Handle, 0, Byte(196), 2);
  94. end;
  95.  
  96. procedure TForm1.CreateParams(var Params: TCreateParams);
  97. begin
  98. inherited CreateParams (Params);
  99. Params.ExStyle := Params.ExStyle or
  100. WS_EX_TRANSPARENT;
  101. end;</code>
  102. ////////////////////////////////////////////////////////////////////////////////
  103.  
  104.  
  105.  
  106.  
  107.  
  108. <code>setWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_TRANSPARENT);</code>
  109.  
  110.  
  111. <code>setWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) and not WS_EX_TRANSPARENT);</code>
  112. ////////////////////////////////////////////////////
  113.  
  114.  
  115.  
  116.  
  117.  
  118. <code>procedure TForm1.HandleMessage(var Msg: tagMSG;var Handled: Boolean);
  119. Var
  120. P:TPoint;
  121. S,R:HRGN;
  122. begin
  123. Inherited;
  124. Case Msg.message Of
  125. WM_MOUSEFIRST..WM_MOUSELAST:
  126. Begin
  127. P.X:=ScreenToClient(Msg.pt).X+ClientOrigin.X-Left;
  128. P.Y:=ScreenToClient(Msg.pt).Y+ClientOrigin.Y-Top;
  129. R:=CreateRectRgn(P.X,P.Y,P.X+1,P.Y+1);
  130. S:=CreateRectRgn(0,0,Width,Height);
  131. CombineRgn(S,S,R,RGN_XOR);
  132. SetWindowRgn(Handle,S,True);
  133. SendMessage(WindowFromPoint(Msg.pt),Msg.message,Msg.wParam,Msg.lParam);
  134. DeleteObject(R);
  135. DeleteObject(S);
  136. Handled:=True;
  137. End;
  138. End;
  139. end;
  140.  
  141. procedure TForm1.FormCreate(Sender: TObject);
  142. begin
  143. Application.OnMessage:=HandleMessage;
  144. end;</code>


Ответ отправил: Feniks (статус: Бакалавр)
Время отправки: 15 октября 2007, 10:44
Оценка за ответ: 5

Комментарий к оценке: Особенно, мне понравился третий пример, таких глюков я давно не видел :)

Мини-форум вопроса

Всего сообщений: 4; последнее сообщение — 15 октября 2007, 11:19; участников в обсуждении: 3.
Dron

Dron (статус: Студент), 14 октября 2007, 11:05 [#1]:

Вам нужны именно щелчки, или перемещение курсора при нажатой кнопке мыши (т.е. выделение) тоже требуется?
С уважением.
Legat

Legat (статус: Посетитель), 14 октября 2007, 22:07 [#2]:

>Вам нужны именно щелчки, или перемещение курсора при
>нажатой кнопке мыши (т.е. выделение) тоже требуется?

Желательно и то и другое,
Подобные окна есть в плагине Winamp-a toaster при поставленной галочке click pass through и часто встречаются в рабочем столе Aston (там они ока-приведения - "Ghost window")

Я думаю поиск окна и посылка ему сообщения - неправильное решение. Уверен, что Aston и toaster делают по другому.
Мне удается создавать подобные окана, только к сожалению прозрачные. У меня есть подазрение, что это делается функцией setWindowLong с какими-то неизвестными мне параметрами. Кстати, как-то мне попадался пример на делфи, там было всего пара строк... Жаль не сохранился :( ....
Матвеев Игорь Владимирович

Матвеев Игорь Владимирович (статус: Студент), 15 октября 2007, 07:50 [#3]:

SetWindowLong(Handle, GWL_EXSTYLE, $8080028);
Пропускает все сквозь форму, курсор мыши также меняется в соответствии с приложением ниже. Стиль устанавливайте после появления формы.
Legat

Legat (статус: Посетитель), 15 октября 2007, 11:19 [#4]:

Всем большое спасибо !

Вот это , именно то, что нужно SetWindowLong(Handle, GWL_EXSTYLE, $8080028); :)

Прекрасно работает )

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:28
Выполнено за 0.03 сек.