Создание модального дочернего окна в Delphi 10: как предотвратить фокусирование на родительском окне и ограничить навигацию табуляцией только внутри дочернего окна
В процессе разработки приложений на Delphi часто возникает необходимость создания модальных дочерних окон. Модальные окна должны быть способны захватывать фокус и не позволять пользователю взаимодействовать с родительским окном, пока модальное окно не будет закрыто. В этой статье мы рассмотрим, как создать модальное дочернее окно в Delphi 10.2+, которое будет ограничивать навигацию табуляцией только внутри себя, а не позволять пользователю переключаться на элементы родительского окна.
Проблема: Навигация табуляцией вне дочернего окна
Если вы создаете дочернее окно в Delphi в режиме времени выполнения и устанавливаете его родителем родительского окна, нажатие клавиши Tab может переключить фокус на элементы родительского окна. Это поведение может быть нежелательным, если вы хотите, чтобы пользователь мог взаимодействовать только с элементами дочернего окна.
Решение: Использование ShowModal и корректировка фокусировки
Delphi предоставляет метод ShowModal, который создает модальное окно и блокирует доступ к родительскому окну до тех пор, пока модальное окно не будет закрыто. Однако, если вы создаете дочернее окно в режиме времени выполнения и устанавливаете его родителем родительского окна, метод ShowModal может не работать должным образом. Вместо этого можно использовать события нажатия клавиш и перехватывать нажатия клавиши Tab, чтобы ограничить навигацию только внутри дочернего окна.
Шаг 1: Создание дочернего окна и установка родителя
Для начала создадим дочернее окно и установим его родителем родительского окна:
var
GreenWindow: TForm;
begin
GreenWindow := TForm.Create(Application);
GreenWindow.Parent := Application.MainForm;
GreenWindow.Position := poDesigned; // Устанавливаем позицию окна
GreenWindow.BorderStyle := bsDialog; // Устанавливаем стиль окна для модального режима
GreenWindow.Show;
end;
Шаг 2: Перехват нажатий клавиш Tab
Для того чтобы ограничить навигацию табуляцией только внутри дочернего окна, можно перехватывать нажатия клавиш в событиях OnKeyDown родительского и дочернего окон. В родительском окне можно установить KeyPreview := True, чтобы перехватывать нажатия клавиш до того, как они будут обработаны элементами формы.
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
FocusedControl: TWinControl;
NextControl: TWinControl;
begin
if Key = VK_TAB then begin
FocusedControl := ActiveControl;
if FocusedControl <> nil then begin
NextControl := TWinControlAccess(Self).FindNextControl(FocusedControl, not (ssShift in Shift), True, True);
if Assigned(NextControl) and ((NextControl = GreenWindow) or (GetParentForm(NextControl.Parent) = GreenWindow)) then
NextControl.SetFocus;
Key := 0; // Предотвращаем стандартное обработку
end;
end;
end;
Шаг 3: Перехват сообщений окна
Для более точного контроля за навигацией табуляцией можно перехватывать сообщения окна. В родительском окне можно перехватывать сообщение CM_DIALOG_KEY и предотвращать стандартную обработку нажатия клавиши Tab:
procedure TForm1.CMDialogKey(var Message: TCMDialogKey);
begin
if GetKeyState(VK_MENU) >= 0 then begin
if Message.CharCode = VK_TAB then
Exit;
end;
inherited;
end;
Шаг 4: Использование ShowModal
Если вы хотите использовать метод ShowModal, можно создать модальное окно и установить его родителем родительского окна. Это позволит автоматически блокировать доступ к родительскому окну:
var
GreenWindow: TForm;
begin
GreenWindow := TForm.Create(Application);
GreenWindow.Parent := Application.MainForm;
GreenWindow.Position := poDesigned;
GreenWindow.BorderStyle := bsDialog;
GreenWindow.ShowModal;
end;
Шаг 5: Сохранение состояния элементов родительского окна
Для того чтобы предотвратить взаимодействие с элементами родительского окна, можно сохранить их состояние и временно отключить:
var
States: TDictionary<TControl, Boolean>;
I: Integer;
CMP: TComponent;
CTRL: TControl ABSOLUTE CMP;
begin
States := TDictionary<TControl, Boolean>.Create;
try
for I := 0 to ParentForm.ComponentCount - 1 do
begin
CMP := ParentForm.Components[I];
if CMP is TControl then
begin
States.Add(CTRL, CTRL.Enabled);
CTRL.Enabled := False;
end;
end;
try
GreenWindow.Parent := ParentForm;
GreenWindow.ShowModal;
finally
for var P in States do
P.Key.Enabled := P.Value;
end;
finally
States.Free;
end;
end;
Заключение
Создание модального дочернего окна в Delphi требует внимания к деталям, особенно если вы хотите ограничить навигацию табуляцией только внутри дочернего окна. Использование метода ShowModal и перехват нажатий клавиш позволяет добиться желаемого поведения. Важно также учитывать, что использование родительского окна как родителя для дочернего окна может привести к неожиданным результатам, поэтому лучше использовать метод ShowModal или корректно перехватывать сообщения окна.
Надеюсь, эта статья поможет вам создать модальные дочерние окна в Delphi и обеспечить правильное поведение приложения.
Context: В статье описывается создание модальных дочерних окон в Delphi, блокирующих доступ к родительскому окну и ограничивающих навигацию табуляцией только внутри дочернего окна.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS