Search code examples
formsuser-interfacedelphiinputbox

InputQuery Formatting Issues


I'm having trouble with InputQuery/InputBox on Delphi XE2.

The input area is out of place (should be under text).

Is there a way to re-align it before making my own input form?

enter image description here

Thank you!


Solution

  • InputQuery() is not designed to be used in this manner. The prompt text is meant to be a short label displayed to the left of the text field (similar to TLabeledEdit). It is not designed to display instructions above the prompts, like you are attempting. This situation would be much better handled by simply creating your own custom Form using whatever controls and layouts you want. For instance, using TDateTimePicker for dates and times, TCheckBox or TRadioGroup to indicate repeats, etc.

    However, that being said, InputQuery() is implemented using a custom VCL TForm, so it is technically possible to accomplish what you are trying to achieve. You can use the TScreen.OnActiveFormChange event to gain access to the Form object when it becomes visible, and then you can manipulate it however you want. For example:

    procedure TMyForm.ActiveFormChanged(Sender: TObject);
    var
      Form: TCustomForm;
      Prompt: TLabel;
      Edit: TEdit;
      Ctrl: TControl;
      I, J, ButtonTop: Integer;
    begin
      Form := Screen.ActiveCustomForm;
      if (Form = nil) or (Form.ClassName <> 'TInputQueryForm') then Exit;
    
      for I := 0 to Form.ControlCount-1 do
      begin
        Ctrl := Form.Controls[i];
        if Ctrl is TLabel then
        begin
          Prompt := TLabel(Ctrl);
        end
        else if Ctrl is TEdit then
        begin
          Edit := TEdit(Ctrl);
        end;
      end;
    
      Edit.SetBounds(Prompt.Left, Prompt.Top + Prompt.Height + 5, Prompt.Width, Edit.Height);
      Form.ClientWidth := (Edit.Left * 2) + Edit.Width;
      ButtonTop := Edit.Top + Edit.Height + 15;
    
      J := 0;
      for I := 0 to Form.ControlCount-1 do
      begin
        Ctrl := Form.Controls[i];
        if Ctrl is TButton then
        begin
          Ctrl.SetBounds(Form.ClientWidth - ((Ctrl.Width + 15) * (2-J)), ButtonTop, Ctrl.Width, Ctrl.Height);
          Form.ClientHeight := Ctrl.Top + Ctrl.Height + 13;
          Inc(J);
        end;
      end;
    end;
    
    procedure TMyForm.DoSomething;
    var
      value: string;
    begin
      Screen.OnActiveFormChange := ActiveFormChanged;
      try
        InputQuery('Enter New Schedule', 'Format: <Second> <Minute> <Hour> <Day_of_the_Month> <Month_of_the_Year> <Day_of_the_Week> <Year>.'#10'Use * for repeating cycles. ex: 0 0 7 * * * * (trigger at 7AM everyday)', value);
      finally
        Screen.OnActiveFormChange := nil;
      end;
    end;
    

    image

    Alternatively:

    class procedure TScreenEvents.ActiveFormChanged(Sender: TObject);
    var
      Form: TCustomForm;
      Instructions: TLabel;
      Ctrl: TControl;
      I, J, K, Offset: Integer;
    begin
      Form := Screen.ActiveCustomForm;
      if (Form = nil) or (Form.ClassName <> 'TInputQueryForm') then Exit;
    
      for I := 0 to Form.ControlCount-1 do
      begin
        Ctrl := Form.Controls[I];
        if Ctrl is TLabel then
        begin
          Instructions := TLabel.Create(Form);
          Instructions.Parent := Form;
          Instructions.Caption := 'Format: <Second> <Minute> <Hour> <Day_of_the_Month> <Month_of_the_Year> <Day_of_the_Week> <Year>.'#10'Use * for repeating cycles. ex: 0 0 7 * * * * (trigger at 7AM everyday)';
          Instructions.SetBounds(Ctrl.Left, Ctrl.Top, Instructions.Width, Instructions.Height);
    
          Offset := Instructions.Top + Instructions.Height + 5;
          Form.ClientWidth := Instructions.Width + (Instructions.Left * 2);
    
          K := 0;
          for J := 0 to Form.ControlCount-1 do
          begin
            Ctrl := Form.Controls[J];
            if Ctrl <> Instructions then
            begin
              Ctrl.Top := Ctrl.Top + Offset;
              if Ctrl is TEdit then
              begin
                Ctrl.Width := (Form.ClientWidth - Ctrl.Left - Instructions.Left);
              end
              else if Ctrl is TButton then
              begin
                Ctrl.Left := (Form.ClientWidth - (Ctrl.Width + 5) * (2-K));
                Inc(K);
              end;
            end;
          end;
    
          Form.ClientHeight := Form.ClientHeight + Offset;
          Break;
        end;
      end;
    end;
    
    procedure TMyForm.DoSomething;
    var
      value: string;
    begin
      Screen.OnActiveFormChange := ActiveFormChanged;
      try
        InputQuery('Enter New Schedule', 'Value', value);
      finally
        Screen.OnActiveFormChange := nil;
      end;
    end;
    

    image