Как узнать какая форма сейчас на переднем плане под курсором?

Как узнать какая форма сейчас на переднем плане под курсором? так верно будет или есть ситуации где это не будет работать? может цикл с нуля начать. не знаю в каком порядке в листе 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;
  1. Как определить что 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 шт):

Автор решения: kami

Судя по исходному коду - вы используете не особо старую версию 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;
→ Ссылка