如何阻止AutoComplete弹窗窗口获取输入焦点?
解决AutoComplete下拉弹窗抢焦点问题的方案
1. 给弹窗窗体添加WS_EX_NOACTIVATE扩展样式
直接从窗体属性上限制它获取激活状态,这是最根本的一步。在弹窗Form的CreateParams方法里,除了完成要求的阴影和父窗口设置,加上不激活的扩展样式:
procedure TAutoCompletePopupForm.CreateParams(var Params: TCreateParams); var DropShadowEnabled: BOOL; begin inherited; // 检查系统是否支持下拉阴影并设置样式 DropShadowEnabled := False; SystemParametersInfo(SPI_GETDROPSHADOW, 0, @DropShadowEnabled, 0); if DropShadowEnabled then Params.WindowClass.Style := Params.WindowClass.Style or CS_DROPSHADOW; // 关键:添加不激活扩展样式,阻止窗体获取激活状态 Params.ExStyle := Params.ExStyle or WS_EX_NOACTIVATE; // 绑定父窗口到输入框所在窗体 Params.WndParent := FEditOwnerForm.Handle; end;
注:FEditOwnerForm是你提前保存的、承载TEdit的窗体引用,弹窗创建时传入即可。
2. 处理WM_MOUSEACTIVATE消息阻断激活
即使加了WS_EX_NOACTIVATE,点击窗体区域时仍可能触发激活逻辑,直接在消息响应里返回MA_NOACTIVATE,同时强制把焦点切回原输入框:
procedure TAutoCompletePopupForm.WMMouseActivate(var Message: TWMMouseActivate); begin // 告诉系统不要激活当前窗体 Message.Result := MA_NOACTIVATE; // 强制将焦点归还给原输入框 if Assigned(FEditControl) then SetFocus(FEditControl.Handle); end;
FEditControl是原TEdit控件的引用,弹窗初始化时保存好。
3. 拦截WM_SETFOCUS消息彻底阻止焦点转移
如果还有漏网的焦点获取情况,直接拦截WM_SETFOCUS,不让弹窗拿到焦点:
procedure TAutoCompletePopupForm.WMSetFocus(var Message: TWMSetFocus); begin // 跳过默认的焦点处理逻辑 if Assigned(FEditControl) then SetFocus(FEditControl.Handle); end;
4. 列表项点击后立刻归位焦点
在下拉列表的点击事件里,完成文本赋值后立刻把焦点切回输入框,同时关闭弹窗:
procedure TAutoCompletePopupForm.ListBox1Click(Sender: TObject); begin if Assigned(FEditControl) and (ListBox1.ItemIndex <> -1) then FEditControl.Text := ListBox1.Items[ListBox1.ItemIndex]; Close; // 强制切回输入框焦点 SetFocus(FEditControl.Handle); end;
内容的提问来源于stack exchange,提问作者Ian Boyd
相关产品推荐
相关产品推荐

