Search code examples
delphic++builder

TForm created dynamically won't set focus to edit control when calling ShowModal()


I created a TForm in the IDE of C++Builder with BorderStyle=bsDialog and made it available following this tutorial:

Dynamically Creating a VCL Modal Form.

I then POST a custom message in the MainForm::OnShow() event, which then sets a FireDAC connection to true which has the LoginPrompt property enabled and uses the OnLogin() event, which then opens up my form.

My issue is that my TEdit field does not get the focus when the dialog is opened. The form contains a TImage using an icon, a TGradientLabel, a TEdit, a TStaticText, and two TButtons for Ok (default) and Cancel. When the form is first opened, pressing Tab makes the focus go to the Ok button, but without the dashed line to indicate input focus; using Shift-Tab goes to the Cancel button, but without the dashed line to indicate input focus. After pressing Tab or Shift-Tab, the next Tab or Shift-Tab works and has the dashed line (when on a button). When the form is first opened, if you Tab then Shift-Tab, or Shift-Tab then Tab, the TEdit field has the cursor and input like it should have from the start.

Here's basically how I setup / start the form:

MyForm=new TMyForm(MainForm);
MyForm->ActiveControl=MyForm->EditName;
MyForm->ShowModal();
MyForm->Free();

I found that if I click another Window then click back to my Main Window (or even if I just click on itself on the Taskbar), it also works and the TEdit control has the cursor.

I even tried setting up an event for OnShow for the dialog, and used ::SetForegroundWindow(), ::SetActiveWindow() for the Form, and tried again setting ActiveControl, and even using MyForm->SetFocus(), but nothing is working.

I'm using Windows 10, is there something else that needs to be done (clearly there is)?


Solution

  • I'm not sure of the details of what is going on internally (not sure how to get spy++ to watch the messages of a Window before the Window exist), but I solved the issue by simply retrying the custom message (UWM_MAINDIALOGSHOWN) again multiple times, I got it down that even 1 time is enough. I put this at the top of my custom message:

    static int redo=1;
    if (redo) {
        redo--;
        PostMessage(Handle, UWM_MAINDIALOGSHOWN, 0, 0);
        return;
    }
    

    If someone has more details on the internals, that be great, but at least there is something that works if someone else runs in to this.