Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как обработать клик за пределами модального окна в Delphi, если стандартные события мыши не работают за его границами?

Delphi , ОС и Железо , Сообщения Windows

 

Проблема обработки кликов вне модального окна

При работе с модальными окнами в Delphi разработчики часто сталкиваются с проблемой: стандартные события мыши (OnMouseDown, OnMouseUp) не срабатывают, когда пользователь кликает за пределами модальной формы. Как отмечает пользователь Squall_FF8, попытки использовать MouseMove возвращают координаты <-1,-1>, что не является надежным индикатором, так как такие же значения могут возвращаться при других операциях, например, при изменении размера окна.

Решение с использованием Windows Hooks

Один из предложенных вариантов решения - использование системных хуков Windows. Пользователь limelect предоставил пример кода, демонстрирующий установку хука для отслеживания событий мыши:

function MouseHook(Code: integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  ClientPt: TPoint;
begin
  if (GlobData <> nil) and
     (Code = HC_ACTION) and
     ((wParam = WM_MOUSEMOVE) or (wParam = WM_NCMOUSEMOVE)) then
  begin
    with PMouseHookStruct(lParam)^ do
    begin
      PostMessage(GlobData^.ActiveHandle, WM_APP+2, Pt.X, Pt.Y);

      ClientPt := Pt;
      ScreenToClient(hwnd, ClientPt);
      PostMessage(GlobData^.ActiveHandle, WM_APP+3, ClientPt.X, ClientPt.Y);
    end;
  end;
  Result := CallNextHookEx(0, Code, wParam, lParam);
end;

function InstallMouseHook(Wnd: HWND): Boolean; stdcall;
begin
  Result := False;
  if (GlobData = nil) then Exit;
  if (GlobData^.THook = 0) then
  begin
    GlobData^.THook := SetWindowsHookEx(WH_MOUSE, @MouseHook, HInstance, 0);
    if GlobData^.THook = 0 then Exit;
  end;
  GlobData^.ActiveHandle := Wnd;
  Result := True;
end;

function UninstallMouseHook: Boolean; stdcall;
begin
  Result := True;
  if (GlobData = nil) then Exit;
  if (GlobData^.THook <> 0) then
  begin
    if not UnhookWindowsHookEx(GlobData^.THook) then Exit;
    GlobData^.THook := 0;
  end;
  GlobData^.ActiveHandle := 0;
  Result := True;
end;

Для использования этого кода вам потребуется определить структуру GlobData:

type
  PGlobalData = ^TGlobalData;
  TGlobalData = record
    THook: HHOOK;
    ActiveHandle: HWND;
  end;

var
  GlobData: PGlobalData;

Альтернативное решение с проверкой активного окна

Если вам нужно только определить, что пользователь кликнул вне модального окна (без точных координат), можно использовать более простой подход:

procedure TModalForm.FormDeactivate(Sender: TObject);
begin
  // Закрываем модальное окно при потере фокуса
  Close;
end;

Или более сложный вариант с проверкой координат:

procedure TModalForm.FormCreate(Sender: TObject);
begin
  // Установка таймера для проверки позиции курсора
  Timer := TTimer.Create(Self);
  Timer.Interval := 100;
  Timer.OnTimer := CheckMousePosition;
  Timer.Enabled := True;
end;

procedure TModalForm.CheckMousePosition(Sender: TObject);
var
  MousePos: TPoint;
begin
  MousePos := Mouse.CursorPos;
  if not PtInRect(BoundsRect, MousePos) then
  begin
    // Курсор вне модального окна
    // Можно добавить дополнительную логику здесь
  end;
end;

Кросс-платформенное решение для FMX

Если ваш проект использует FireMonkey (FMX) и должен работать на разных платформах (Windows, Android, iOS), системные хуки Windows не подойдут. В этом случае можно использовать следующий подход:

procedure TModalForm.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char;
  Shift: TShiftState);
begin
  // Обработка нажатия Escape для закрытия окна
  if Key = vkEscape then
    Close;
end;

procedure TModalForm.TouchOutside(Sender: TObject; const Point: TPointF);
begin
  // FMX-специфичное событие для кликов вне формы
  Close;
end;

Для FMX также можно использовать прозрачный фоновый прямоугольник, который будет перехватывать клики:

procedure TModalForm.ShowModalWithBackground;
var
  BackgroundRect: TRectangle;
begin
  BackgroundRect := TRectangle.Create(Self);
  BackgroundRect.Parent := Self;
  BackgroundRect.Align := TAlignLayout.Client;
  BackgroundRect.Fill.Color := TAlphaColorRec.Black;
  BackgroundRect.Fill.Kind := TBrushKind.Solid;
  BackgroundRect.Opacity := 0.5;
  BackgroundRect.OnClick := BackgroundClick;

  ShowModal;
end;

procedure TModalForm.BackgroundClick(Sender: TObject);
begin
  Close;
end;

Заключение

Выбор метода обработки кликов за пределами модального окна зависит от ваших конкретных требований:

  1. Windows Hooks - наиболее мощное решение для VCL приложений, но требует осторожности при реализации.
  2. Проверка активного окна или позиции курсора - проще в реализации, но может быть менее надежным.
  3. FMX-специфичные решения - необходимы для кросс-платформенных приложений.

Для большинства случаев в VCL-приложениях рекомендуется использовать либо системные хуки (если нужны точные координаты), либо обработку события FormDeactivate (если достаточно просто определить клик вне окна). В FMX-приложениях лучше использовать встроенные механизмы вроде TouchOutside или прозрачный фоновый элемент.

Создано по материалам из источника по ссылке.

Обработка кликов вне модального окна в Delphi с использованием системных хуков или проверки активного окна.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Сообщения Windows ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-05-01 10:14:31/0.0038888454437256/0