Как получить элемент управления, который находится под курсором в Delphi? - PullRequest
3 голосов
/ 16 июля 2011

Мне нужна противоположная информация, которую задает вопрос «Как получить позицию курсора на элементе управления?» .

Учитывая текущую позицию курсора, как я могу найти форму (вмое приложение) и контроль над курсором в данный момент?Мне нужна ручка, чтобы я мог использовать Windows.SetFocus(Handle).

Для справки, я использую Delphi 2009.

Ответы [ 3 ]

3 голосов
/ 16 июля 2011

Я думаю FindVCLWindow удовлетворит ваши потребности. Когда у вас есть оконный элемент управления под курсором, вы можете пройти родительскую цепочку, чтобы найти форму, в которой живет окно.

3 голосов
/ 17 декабря 2014

У меня возникли некоторые проблемы с предлагаемыми решениями (Delphi XE6 / Windows 8.1 x64):

  • FindVCLWindow не выполняет поиск отключенных элементов управления (Enabled = False).
  • TWinControl.ControlAtPos не ищет элементы управления, если они отключены косвенно (например, если Button.Enabled = True, но Button.Parent.Enabled = False).

В моем случае это была проблема, потому что мне нужно найти любой видимый элемент управления под курсором мыши, поэтому я должен использовать собственную реализацию функции FindControlAtPos:

function FindSubcontrolAtPos(AControl: TControl; AScreenPos, AClientPos: TPoint): TControl;
var
  i: Integer;
  C: TControl;
begin
  Result := nil;
  C := AControl;
  if (C=nil) or not C.Visible or not TRect.Create(C.Left, C.Top, C.Left+C.Width, C.Top+C.Height).Contains(AClientPos) then
    Exit;
  Result := AControl;
  if AControl is TWinControl then
    for i := 0 to TWinControl(AControl).ControlCount-1 do
    begin
      C := FindSubcontrolAtPos(TWinControl(AControl).Controls[i], AScreenPos, AControl.ScreenToClient(AScreenPos));
      if C<>nil then
        Result := C;
    end;
end;

function FindControlAtPos(AScreenPos: TPoint): TControl;
var
  i: Integer;
  f,m: TForm;
  p: TPoint;
  r: TRect;
begin
  Result := nil;
  for i := Screen.FormCount-1 downto 0 do
    begin
      f := Screen.Forms[i];
      if f.Visible and (f.Parent=nil) and (f.FormStyle<>fsMDIChild) and 
        TRect.Create(f.Left, f.Top, f.Left+f.Width, f.Top+f.Height).Contains(AScreenPos) 
      then
        Result := f; 
    end;
  Result := FindSubcontrolAtPos(Result, AScreenPos, AScreenPos);
  if (Result is TForm) and (TForm(Result).ClientHandle<>0) then
  begin
    WinAPI.Windows.GetWindowRect(TForm(Result).ClientHandle, r);
    p := TPoint.Create(AScreenPos.X-r.Left, AScreenPos.Y-r.Top);
    m := nil;
    for i := TForm(Result).MDIChildCount-1 downto 0 do
    begin
      f := TForm(Result).MDIChildren[i];
      if TRect.Create(f.Left, f.Top, f.Left+f.Width, f.Top+f.Height).Contains(p) then
        m := f; 
    end;
    if m<>nil then
      Result := FindSubcontrolAtPos(m, AScreenPos, p);
  end;
end;
2 голосов
/ 16 июля 2011

Если вы хотите знать элемент управления внутри формы с определенной координатой x, y

Используйте

function TWinControl.ControlAtPos(const Pos: TPoint; AllowDisabled: Boolean;
        AllowWinControls: Boolean = False; AllLevels: Boolean = False): TControl;

Учитывая тот факт, что вам кажется интересным только формы внутри приложения, вы можете просто запросить все формы.

Как только вы получите результат, отличный от nil, вы можете запросить элемент управления для его дескриптора с кодом, подобным следующему

Псевдокод

function HandleOfControlAtCursor: THandle;
const
  AllowDisabled = true;
  AllowWinControls = true;
  AllLevels = true;
var
  CursorPos: TPoint
  FormPos: TPoint;
  TestForm: TForm;
  ControlAtCursor: TControl;
begin
  Result:= THandle(0);
  GetCursorPos(CursorPos);
  for each form in my application do begin
    TestForm:= Form_to_test;
    FormPos:= TestForm.ScreenToClient(CursorPos);
    ControlAtCursor:= TestForm.ControlAtPos(FormPos,  AllowDisabled,
                                            AllowWinControls, AllLevels);
    if Assigned(ControlAtCursor) then break;
  end; {for each}
  //Break re-enters here
  if Assigned(ControlAtCursor) then begin
    while not(ControlAtCursor is TWinControl) do 
      ControlAtCursor:= ControlAtCursor.Parent;
    Result:= ControlAtCursor.Handle;
  end; {if}
end;

Это также позволяет исключить некоторые формы из рассмотрения, если вы того пожелаете. Если вы ищете простоту, я бы пошел с Дэвидом и использовал FindVCLWindow.

P.S. Лично я бы использовал goto вместо перерыва, потому что при переходе сразу становится ясно, где перерыв повторяется, но в этом случае это не большая проблема, потому что между перерывом и повторением нет никаких утверждений. точка входа.

...