title: Delphi: Creating a TComboBox in a dynamically created form at runtime
body: <p>Okay, I am working in a project that was originally done in D7.  And I am doing double duty here as I am working on fixing bugs in the original code and attempting to port it over to XE3/4.  Kinda hard when the original author used some none-open source kits for the project.</p>
  
  <p>But anyways, the app is a scripting/macroing program.  As part of the custome scripting/macroing language. There is a ability to create very simple basic forms for user input.  The forms are created dynamically at runtime based on the script/macro the script/macro author has created.  I have already fixed some bugs in the code for the creation of the forms.  But, there is one that I just can not figure out.</p>
  
  <p>When creating a TComboBox for the parent form and setting the Text property AT component creation.  The text in the Text property is not displayed.</p>
  
  <p><strong>Here is the code to create the form:</strong></p>
  
  <pre><code>procedure CreateForm(var wFrm: TForm; sName: String);
  var
    iLoop, iPos, iLen: Integer;
    iFormHeight, iFormWidth: Integer;
    lh, hresult1, hresult2: Integer;
    sWork, sWork2, sLine, CmdName: String;
    lstForm, lst: TStringList;
    pnl: TPanel;
  
  begin
    iFormHeight := 80;
    iFormWidth := 400;
    hresult1 := 0;
    lst := TStringList.Create;
  
    iLoop := lstForms.IndexOf(Trim(UpperCase(sName)));
    if iLoop &lt; 0 then
    begin
      AbortError('Form "' + sName + '" could not be found!');
      Exit;
    end;
  
    lstForm := TStringList(lstForms.Objects[iLoop]);
  
    for iLoop := 0 to lstForm.Count - 1 do
    begin
      sLine := lstForm[iLoop];
      iPos := Pos('=', sLine);
      iLen := Length(sLine);
      if iPos = 0 then
        continue;
  
      CmdName := Uppercase(Trim(Copy(sLine, 1, iPos - 1)));
      sWork2 := Trim(Copy(sLine, iPos + 1, iLen));
  
      if CmdName = 'FORMCAPTION' then
      begin
        with wfrm do
        begin
          Caption := Trim(Copy(sLine, iPos + 1, iLen));
          Name := Trim(sName);
          Height := iFormHeight;
          Width := iFormWidth;
          Tag := 10;
          BorderStyle := bsSizeable;
          BorderIcons := [biSystemMenu];
          Position := poDesktopCenter;
          pnl := TPanel.Create(wfrm);
          with pnl do
          begin
            Parent := wfrm;
            Caption := '';
            Align := alBottom;
            BevelInner := bvNone;
            BevelOuter := bvNone;
            Height := 30;
          end;
          with TButton.Create(wfrm) do
          begin
            Parent := pnl;
            Caption := '&amp;OK';
            Default := True;
            ModalResult := mrOK;
            Left := 235;
            Top := 0;
          end;
          with TButton.Create(wfrm) do
          begin
            Parent := pnl;
            Caption := '&amp;Cancel';
            Cancel := True;
            ModalResult := mrCancel;
            Left := 310;
            Top := 0;
          end;
          pnl := TPanel.Create(wfrm);
          with pnl do
          begin
            Parent := wfrm;
            Caption := '';
            Align := alClient;
            BevelInner := bvRaised;
            BevelOuter := bvNone;
            BorderWidth := 5;
          end;
        end;
      end
      else
      begin
        lst.Clear;
        StringToList(sWork2, lst, ':');
        if UpperCase(lst[0]) = 'EDITBOX' then
          CreateEditBox
        else if UpperCase(lst[0]) = 'CHECKBOX' then
          CreateCheckBox
        else if UpperCase(lst[0]) = 'COMBOBOX' then
          CreateComboBox
        else if UpperCase(lst[0]) = 'LABEL' then
          CreateLabel;
      end;
    end;
  
    with wfrm do
    begin
      if hresult1 &gt; 1 then
        hresult2 := 5
      else
        hresult2 := 9;
      Tag := Tag + hresult2;
      Height := Height + hresult2;
    end;
  
    lst.Free;
  end;
  </code></pre>
  
  <p><strong>And here is the specific code to create the TComboBox, w/ TLabel, for the form:</strong></p>
  
  <pre><code>  procedure CreateComboBox;
    var
      iPos: Integer;
    begin
      with TLabel.Create(wfrm) do
      begin
        Parent := pnl;
        Caption := lst[1];
        Left := 15;
        if hresult1 &gt; 1 then
          hresult2 := 5 * hresult1
        else
          hresult2 := 3 * hresult1;
        Top := wfrm.Tag + hresult2;
        Name := 'lbl' + CmdName;
        Width := 150;
        WordWrap := True;
        AutoSize := True;
        lh := Height;
      end;
      hresult1 := Trunc(lh/13);
      with TComboBox.Create(wfrm) do
      begin
        Parent := pnl;
        Left := 170;
        Width := 200;
        if hresult1 &gt; 1 then
          hresult2 := 5 * hresult1
        else
          hresult2 := 3 * hresult1;
        Top := wfrm.Tag + hresult2;
        Style := csDropDownList;
        Name := UpperCase(CmdName);
        Text := 'Test Text';
        sWork := lst[3];
        lst.Clear;
        StringToList(sWork, lst, ',');
        for iPos := 0 to lst.Count - 1 do
          lst[iPos] := lst[iPos];
        Items.Assign(lst);
  //      ItemIndex := 0;
      end;
      wfrm.Tag := wfrm.Tag + ((hresult1 * 13)+ 13);
      wfrm.Height := wfrm.Height + ((hresult1 * 13)+ 13);
      TComboBox(wfrm
    end;
  </code></pre>
  
  <p>NOTE: the above procedure is a child procedure of the CreateForm procedure.</p>
  
  <p>The app uses TStringList lists to store the form definition at script/macro runtime.  Then the above code retrieves that information to create to form when the author wants the form to be shown.  And then creates the form and places the form object into another temporary TStringList list prior to being shown.  This is done so that when the user runs the script/macro and enters the information/settings as requested in the form.  The author may retrieve the requested information/settings from the form before the form is destroyed.</p>
  
  <p><strong>The form is deleted (if previously created) from tmp TStringList list, created, stored in tmp TStringList list, and shown modally with the following code:</strong></p>
  
  <pre><code>    iPos := lstForms.IndexOf(UpperCase(sWVar2));
      if iPos &lt; 0 then
      begin
        AbortError('Could not find form "' + Trim(sWVar2) + '" defined!');
        Exit;
      end;
  
      iPos := lstFormsTMP.IndexOf(UpperCase(sWVar2));
      if iPos &gt; -1then
      begin
        TForm(lstFormsTMP.Objects[iPos]).Free;
        lstFormsTMP.Delete(iPos);
        frm.Free;
        iPos := lstFormsTMP.IndexOf(UpperCase(sWVar2));
        if iPos &gt; -1 then
        begin
          AbortError('Form "' + Trim(sWVar2) + '" was not removed from the lstFormsTMP TStringList.');
          Exit;
        end;
      end;
  
      frm := TForm.Create(frmMain);
      CreateForm(frm, sWVar2);
      lstFormsTMP.AddObject(Uppercase(sWVar2), frm);
    end;
  
    iPos := lstFormsTMP.IndexOf(UpperCase(sWVar2));
    if iPos &lt; 0 then
    begin
      AbortError('Could not find form "' + Trim(sWVar2) + '" defined!');
      Exit;
    end;
  
    hndHold := SwitchToHandle(frmMain.Handle);
    try
      Result := TForm(lstFormsTMP.Objects[iPos]).ShowModal = mrOK;
    finally
      SwitchToHandle(hndHold);
    end;
  </code></pre>
  
  <p>With the above sets of code the form defined in the running script is created and shown, without to many bugs/errors.  But, even though I have hardcoded the text for the TComboBox.Text property. It is not shown.  Can anyone shed some lite on why this is the case for me?  All other form components, TCheckBox, TEditBox, TLabel, are displayed without any issues, so far.  It is just the TComboBox that is causing me to scratch my head in confusion.</p>
  
  <p>NOTE: Eventually the TComboBox.Text property will be dynamically set based on the authors setting for that property in the form component's definition.</p>
  
  <p>Thanks in advance.</p>
  
  <p>EDITED 8/18/2013, to include the following:</p>
  
  <p>The original code also includes the ability to save/load the form component's settings by way of the TIniFile object. The following code is used to save the setting for the TComboBox:</p>
  
  <pre><code>  if frm.Components[i] is TCombobox then
      iniWork.WriteString(frm.Name, TCombobox(frm.Components[i]).Name, TCombobox(frm.Components[i]).Text)
    else
  </code></pre>
  
  <p>and the following to load the TComboBox setting:</p>
  
  <pre><code>  if frm.Components[i] is TCombobox then
    begin
      TCombobox(frm.Components[i]).ItemIndex := TCombobox(frm.Components[i]).Items.IndexOf(
        iniWork.ReadString(frm.Name, TCombobox(frm.Components[i]).Name, TCombobox(frm.Components[i]).Text));
    end
  </code></pre>
  
  <p>With the above code it looks to me like the setting is being save from and loaded back into the TComboBox's Text property. Now when the TComboBox setting is loaded, the form is changed after it has been created and placed, as an object, into the tmp TStringList list and prior to being shown modally.  Yet, when the form is shown the <strong>Text</strong> property, as set by the above load code above, is shown.</p>
  
  <p>It is because of the above that I am confused.  Why does it work at this point, after the form is created.  Yet not when the form is created?</p>