| 
| 
 | Вопрос # 977/ вопрос открыт / | 
 |  Доброго времени суток, уважаемые эксперты!Как реализовать "Click pass though" ( т.е. чтобы форма пропускала щелчки под себя) ?
 
|  |   Вопрос задал: 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!Попробуйте примеры из Приложений... Может какой-то и подойдет.
 Приложение:Переключить в обычный режим   <code>unit transpar_frm; interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls;typeTForm1 = class(TForm)   Button1: TButton;   Button2: TButton;   CheckBox1: TCheckBox; protected   procedure RebuildWindowRgn;   procedure Resize; override;public   constructor Create(AOwner: TComponent); override;end;varForm1 : TForm1;implementation {$R *.DFM} constructor TForm1.Create(AOwner: TComponent);begininherited; FormStyle:=fsStayOnTop;  HorzScrollBar.Visible:= False;VertScrollBar.Visible:= False; RebuildWindowRgn;end;procedure TForm1.Resize;begininherited; RebuildWindowRgn;end;procedure TForm1.RebuildWindowRgn;varFullRgn, Rgn: THandle;ClientX, ClientY, I: Integer;begin ClientX:= (Width - ClientWidth) div 2;ClientY:= Height - ClientHeight - ClientX; FullRgn:= CreateRectRgn(0, 0, Width, Height);  Rgn:= CreateRectRgn(ClientX, ClientY, ClientX + ClientWidth, ClientY +ClientHeight);CombineRgn(FullRgn, FullRgn, Rgn, rgn_Diff); for I:= 0 to ControlCount -1 do   with Controls[I] do begin     Rgn:= CreateRectRgn(ClientX + Left, ClientY + Top, ClientX + Left +Width, ClientY + Top + Height);     CombineRgn(FullRgn, FullRgn, Rgn, rgn_Or);   end; SetWindowRgn(Handle, FullRgn, True);end;end.</code>///////////////////////////////////////////////////////////////////////////////////   <code>type TForm1 = class(TForm)   procedure FormCreate(Sender: TObject);protected   procedure CreateParams (var Params: TCreateParams); override;end; varForm1: TForm1; implementation ... procedure TForm1.FormCreate(Sender: TObject);beginSetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);SetLayeredWindowAttributes(Handle, 0, Byte(196), 2);end; procedure TForm1.CreateParams(var Params: TCreateParams);begininherited CreateParams (Params);Params.ExStyle := Params.ExStyle or   WS_EX_TRANSPARENT;end;</code>////////////////////////////////////////////////////////////////////////////////     <code>setWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or
WS_EX_TRANSPARENT);</code>  <code>setWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) and not
WS_EX_TRANSPARENT);</code>////////////////////////////////////////////////////     <code>procedure TForm1.HandleMessage(var Msg: tagMSG;var Handled: Boolean);VarP:TPoint;S,R:HRGN;beginInherited;Case Msg.message Of   WM_MOUSEFIRST..WM_MOUSELAST:   Begin     P.X:=ScreenToClient(Msg.pt).X+ClientOrigin.X-Left;     P.Y:=ScreenToClient(Msg.pt).Y+ClientOrigin.Y-Top;     R:=CreateRectRgn(P.X,P.Y,P.X+1,P.Y+1);     S:=CreateRectRgn(0,0,Width,Height);     CombineRgn(S,S,R,RGN_XOR);     SetWindowRgn(Handle,S,True);     SendMessage(WindowFromPoint(Msg.pt),Msg.message,Msg.wParam,Msg.lParam);     DeleteObject(R);     DeleteObject(S);     Handled:=True;   End;End;end; procedure TForm1.FormCreate(Sender: TObject);beginApplication.OnMessage:=HandleMessage;end;</code>
|  | Ответ отправил: Feniks (статус: Бакалавр)Время отправки: 15 октября 2007, 10:44
 Оценка за ответ: 5
 Комментарий к оценке: Особенно, мне понравился третий пример, таких глюков я давно не видел :) |  
 Мини-форум вопросаВсего сообщений: 4; последнее сообщение — 15 октября 2007, 11:19; участников в обсуждении: 3. 
|   | Dron (статус: Студент), 14 октября 2007, 11:05 [#1]:Вам нужны именно щелчки, или перемещение курсора при нажатой кнопке мыши (т.е. выделение) тоже требуется? С уважением. |  
|   | 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 (статус: Посетитель), 15 октября 2007, 11:19 [#4]:Всем большое спасибо ! 
 Вот это , именно то, что нужно  SetWindowLong(Handle, GWL_EXSTYLE, $8080028);
  
 Прекрасно работает )
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |