Как узнать какая форма сейчас на переднем плане под курсором?
Как узнать какая форма сейчас на переднем плане под курсором? так верно будет или есть ситуации где это не будет работать? может цикл с нуля начать. не знаю в каком порядке в листе Screen.CustomForm хранятся формы
дополнение Под курсором может быть что угодно на переднем плане. Но надо найти форму своего приложения которая выше всех и под курсором.
function GetFormAtPointScreen:TCustomForm;
var P,P2:TPoint;
R2:TRect;
i:integer;
begin
GetCursorPos(P);
Result:=nil;
for I := Screen.CustomFormCount-1 downto 0 do
begin
P2:=Screen.CustomForms[i].ClientOrigin;
R2:=Screen.CustomForms[i].ClientRect;
R2.Offset(P2);
if R2.Contains(P) then
begin
Result:= Screen.CustomForms[i];
break;
end;
end;
//Screen.
end;
- Как определить что FormDop Выше FormMain и наоборот если я захочу FormMain.FormStyle:= fsStayOnTop;
Пока рещил так вернуть список форм как они расположены по z координате
{function Title(h:Cardinal):string;
var str:array[0..256-1] of char;
begin
GetWindowText(h,@str,256);
Result:= str;
end; }
class function AmWinApiSup.GetListZForm():TArray<Cardinal>;
var Forms,ListZ:TList<Cardinal>;
I: Integer;
H: Cardinal;
//s:string;
begin
// TArray [0] содержит handle самой высокой формы
// TArray [length-1] самой низкой
// это вариант более гибче чем вернуть просто форму по координатам
// после выполения можно добавить свои фильтры или что
// а сопоставить координаты мыши с handel
//if GetWindowRect(TArray [i], Rect) then
// Result := Rect.Contains(Point) true значит курсор под формой с этим ханделом
SetLength(Result,0);
if (Application=nil)
or (Application.MainForm = nil)
or not Application.MainForm.HandleAllocated then
exit;
Forms:=TList<Cardinal>.Create;
ListZ:= TList<Cardinal>.Create;
try
for I := 0 to Screen.CustomFormCount-1 do
if Screen.CustomForms[i].HandleAllocated then
Forms.Add( Screen.CustomForms[i].Handle);
H:= Application.MainForm.Handle;
if IsWindowVisible(h) and (Forms.IndexOf(h)>=0) then
ListZ.Add(h);
h :=GetWindow(h, GW_HWNDNEXT);
while (h<>0) do
begin
h :=GetWindow(h, GW_HWNDNEXT);
if IsWindowVisible(h) and (Forms.IndexOf(h)>=0) then
ListZ.Add(h);
end;
H:= Application.MainForm.Handle;
while (h<>0) do
begin
h :=GetWindow(h, GW_HWNDPREV);
if IsWindowVisible(h) and (Forms.IndexOf(h)>=0) then
ListZ.Insert(0,h);
end;
{ for I := 0 to ListZ.Count-1 do
begin
S:=Title(ListZ[i]);
end; }
SetLength(Result,ListZ.Count);
TArray.Copy<Cardinal>(ListZ.List,Result,0,0,ListZ.Count);
finally
Forms.Free;
ListZ.Free;
end;
end;
Ответы (1 шт):
Судя по исходному коду - вы используете не особо старую версию Delphi, посему - код создан с расчетом на наличие дженериков.
Вкратце:
требуется пройтись по z-координате окон (всех-всех, не только своих - иначе z-order не поймать, google by windows z-order enumerate), проверяя на вхождение координаты курсора границам окна, и как только итератор дойдет до окна, принадлежащего "нашему" приложению - задача выполнена.
procedure FillHandles(OwnedFormHandles: TDictionary<THandle, TCustomForm>);
var
i: Integer;
begin
// здесь заполняем словарик, чтобы не пробегать на каждый чих по всем формам
// и иметь очень быстрый доступ к окну по ключу.
for i := 0 to Screen.CustomFormCount - 1 do
if Screen.CustomForms[i].Visible then
OwnedFormHandles.add(Screen.CustomForms[i].Handle, Screen.CustomForms[i]);
end;
function IsWindowHandleInPoint(Handle: THandle; Point: TPoint): Boolean;
var
lpRect: TRect;
begin
// надеюсь, что здесь комментарии излишни.
if GetWindowRect(Handle, lpRect) then
Result := lpRect.Contains(Point)
else
Result := False;
end;
function GetFormAtPointScreen: TCustomForm;
var
OwnedFormHandles: TDictionary<THandle, TCustomForm>;
Window: HWND;
Point: TPoint;
begin
GetCursorPos(Point);
Result := nil;
OwnedFormHandles := TDictionary<THandle, TCustomForm>.Create;
try
FillHandles(OwnedFormHandles); // заполним "реестр" наших окон
Window := GetTopWindow(GetDesktopWindow());
while Window <> 0 do // и пройдемся по всем
begin
if IsWindowHandleInPoint(Window, Point) then // в поиске вхождения координаты в границы окна
if OwnedFormHandles.ContainsKey(Window) then // и принадлежания нашему приложению.
//Для ускорения обработки условия следует поменять местами.
begin
Result := OwnedFormHandles[Window];
break;
end;
Window := GetWindow(Window, GW_HWNDNEXT); // видимо не нашли - двигаемся дальше
end;
finally
OwnedFormHandles.Free; // не забываем: "я тебя породил - я тебя и убью"
end;
end;
