|
Вопрос # 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;
-
- interface
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls;
- type
- TForm1 = class(TForm)
- Button1: TButton;
- Button2: TButton;
- CheckBox1: TCheckBox;
-
- protected
- procedure RebuildWindowRgn;
- procedure Resize; override;
- public
- constructor Create(AOwner: TComponent); override;
- end;
- var
- Form1 : TForm1;
- implementation
-
- {$R *.DFM}
-
- constructor TForm1.Create(AOwner: TComponent);
- begin
- inherited;
-
- FormStyle:=fsStayOnTop;
-
-
- HorzScrollBar.Visible:= False;
- VertScrollBar.Visible:= False;
-
- RebuildWindowRgn;
- end;
- procedure TForm1.Resize;
- begin
- inherited;
-
- RebuildWindowRgn;
- end;
- procedure TForm1.RebuildWindowRgn;
- var
- FullRgn, 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;
-
- var
- Form1: TForm1;
-
- implementation
-
- ...
-
- procedure TForm1.FormCreate(Sender: TObject);
- begin
- SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
- SetLayeredWindowAttributes(Handle, 0, Byte(196), 2);
- end;
-
- procedure TForm1.CreateParams(var Params: TCreateParams);
- begin
- inherited 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);
- Var
- P:TPoint;
- S,R:HRGN;
- begin
- Inherited;
- 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);
- begin
- Application.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); 
Прекрасно работает )
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|