0
votes

I have a TEdit in a Delphi VCL form app (contained in a TFrame instance, if it matters). After a user indicates they are finished editing, by clicking elsewhere on the form, the caret and focus remain on this control until I click on another control, which then takes the focus. However, I want the TEdit to loose focus regardless of where the user clicks. I expect I can use ActiveControl := nil to end focus on the selected control, but I am uncertain where to invoke it.

What I want is for the focus to leave the selected control without necessarily having to transfer it to another control. I could end focus in the form's OnClick event, but that will not work if the user selects any of the other controls (also contained in frames) on my form, since the form's OnClick event is not triggered. It seems inelegant and tedious to provide separate OnClick events for each additional item on the form.

What is the global solution to achieve this behavior?

1
Why would you want this? It's just going to make the user experience worse because it is non standard.David Heffernan
@DavidHeffernan The program presents a game board and the editors are mostly used by the user during initial setup. Once the game begins the user gives input including the keyboard and that input that is managed and displayed by the program independent of these editors. In the user's view the focus has simply changed to other components consisting of frames containing images and tlabel text displays.Ashlar

1 Answers

7
votes

Try using the TApplication(Events).OnMessage event to look for WM_LBUTTONDOWN messages.

You can use the VCL's FindVCLWindow() or FindDragTarget() function (both in the Vcl.Controls unit) to see if there is a TWinControl located at the click coordinates. Or simpler, you can use the VCL's FindControl() function (also in the Vcl.Controls unit) to get an TWinControl directly from the message's target HWND.

If no control exists under the mouse, or if the control is not focusable (its CanFocus() method returns False), then set ActiveControl=nil. Otherwise, do nothing, and let the clicked control take focus on its own when the message is processed.