FMX应用实现聚焦友好弹窗:解决标签功能的焦点与弹窗关闭问题
解决FMX弹窗焦点与关闭逻辑问题(类似Teams标签功能)
1. 基础配置TForm属性
先把弹窗窗体的基础属性调整到位,适配需求:
- 设置
FormStyle为fsStayOnTop,确保弹窗始终悬浮在主窗口上方 - 设置
BorderStyle为bsNone,模拟无框弹窗的样式(按需调整) - 调整
Position、Size等属性,让弹窗显示在目标Memo控件的合适位置
2. 弹窗显示时不抢占Memo焦点
不要用默认的Show()方法,改用Windows原生API让弹窗显示但不激活,同时强制把焦点还给Memo:
uses Winapi.Windows, FMX.Platform.Win; procedure TMainForm.ShowTagPopup; var PopupHwnd: HWND; begin if not TagPopupForm.Visible then begin // 定位弹窗到Memo下方(可根据需求调整坐标计算逻辑) TagPopupForm.Left := Memo1.Left + (Memo1.Width - TagPopupForm.Width) div 2; TagPopupForm.Top := Memo1.Top + Memo1.Height + 8; // 获取弹窗的Windows句柄 PopupHwnd := FmxHandleToHWND(TagPopupForm.Handle); // 显示窗体但不激活,避免抢占焦点 ShowWindow(PopupHwnd, SW_SHOWNOACTIVATE); // 强制将焦点放回Memo Memo1.SetFocus; end; end;
3. 实现点击外部自动关闭弹窗
通过监听全局鼠标点击事件,判断点击位置是否在弹窗范围内,不在则关闭弹窗:
uses FMX.Platform; procedure TTagPopupForm.FormCreate(Sender: TObject); var MouseService: IFMXMouseService; begin // 注册全局鼠标点击事件 if TPlatformServices.Current.SupportsPlatformService(IFMXMouseService, IInterface(MouseService)) then MouseService.OnMouseDown := MouseDownHandler; end; procedure TTagPopupForm.MouseDownHandler(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); var ScreenClickPos: TPointF; PopupScreenRect: TRectF; begin ScreenClickPos := Screen.MousePos; PopupScreenRect := Self.AbsoluteRect; // 点击位置不在弹窗范围内时关闭弹窗,并将焦点放回Memo if not PopupScreenRect.Contains(ScreenClickPos) then begin Self.Close; MainForm.Memo1.SetFocus; end; end; procedure TTagPopupForm.FormDestroy(Sender: TObject); var MouseService: IFMXMouseService; begin // 销毁时取消事件注册,避免内存泄漏 if TPlatformServices.Current.SupportsPlatformService(IFMXMouseService, IInterface(MouseService)) then MouseService.OnMouseDown := nil; end;
4. 补充优化:避免弹窗内控件焦点切换误关闭
如果遇到弹窗内控件获取焦点时触发窗体Deactivate导致误关闭的情况,可以添加如下逻辑:
procedure TTagPopupForm.FormDeactivate(Sender: TObject); begin // 延迟判断,避免焦点在弹窗内部切换时误触发关闭 TThread.Queue(nil, procedure begin if (Screen.FocusedControl = nil) or not Screen.FocusedControl.IsDescendantOf(Self) then Self.Close; end); end;
最终效果:
- 弹窗显示后,Memo保持焦点
- 点击弹窗内的TEdit时,焦点自动转移到编辑框,弹窗保持打开
- 点击弹窗外部任意位置,弹窗自动关闭,焦点回到Memo
内容的提问来源于stack exchange,提问作者bas
相关产品推荐
相关产品推荐

