Welcome to the new DelphiDabbler Code Library Documentation.

This is a new site that's currently running on alpha code. There are going to be bugs. If you discover any, please report them on the site's issues page (GitHub account required). Thanks.

Warning: Many URLs are going to change. Refer to the README file to discover which library project's documentation has been completed.

Console Application Runner Classes Example 11: Customising the appearance of the console

Applies to: ~>3.0

TPJConsoleApp can be used to customise the appearance of any new console window displayed by a console application. This example shows how to modify the console window’s size, position, title and foreground and background colours.

Console customisation requires a new console window. If one console application starts another and the child application shares the parent’s console then any customisation will have no effect. However, if the parent program is a GUI application then a new console window is always created.

To avoid too much complexity all in one go we will develop this example project in four stages, with each stage demonstrating one property of TPJConsoleApp:

  1. ConsoleTitle
  2. ConsoleColors
  3. WindowSize
  4. WindowPosition

Before that we’ll create the main example program framework that is required to demonstrate all the properties.

Common Code

To begin with start a new Delphi GUI application project, and add PJConsoleApp to the the main form’s uses statement.

Now drop a TButton on the form, name it btnRun and give it the following OnClick event handler:

procedure TForm1.btnRunClick(Sender: TObject);
var
  App: TPJConsoleApp;
begin
  btnRun.Enabled := False;
  try
    App := TPJConsoleApp.Create;
    try
      // [ConsoleTitle code here]
      // [ConsoleColor code here]
      // [WindowSize code here]
      // [WindowPosition code here]
      App.OnWork := WorkHandler;
      App.Visible := True;
      if not App.Execute('Timed 2') then
        raise Exception.CreateFmt(
          'Can_t execute program: error %d - "%s"',
          [App.ErrorCode, App.ErrorMessage]
        );
    finally
      App.Free;
    end;
  finally
    btnRun.Enabled := True;
  end;
end;

If you’ve worked through other examples, none of the above should come as any surprise. Note that we’ve explicitly made the console application visible so we can see the customisations! The code we add in the following sections will replace the relevant placeholder comments in the above code.

Now add the following method to handle the OnWork event. It’s the same simple implementation we’ve used before that allows the GUI to remain responsive:

procedure TForm1.WorkHandler(Sender: TObject);
begin
  Application.ProcessMessages;
end;

You can now test the application. Clicking the button will run the console app without any customisations.

Once again we’ve use Timed.exe as the console app and run it for 2 seconds, which should be long enough to notice the customisations. If it’s not then change the program’s parameter to increase the number of seconds it runs. You can substitute any console application that runs for a sufficient length of time.

Stage 1: ConsoleTitle

Add a TEdit to the form and name it edTitle. It would be useful for clarity to also add a TLabel to label the edit control as “Title”.

In the btnRunClick event handler replace the [ConsoleTitle code here] placeholder comment with:

App.ConsoleTitle := edTitle.Text;

Now run the program, type a title in the edit box and click the button. The console window should have the title you entered. Setting the title to an empty string causes the default window title to be displayed.

Stage 2: ConsoleColors

Drop a TGroupBox on the form. Inside the group box add two TColorBox controls, one named cbForeground and the other cbBackground. It may be helpful to label the colour combos “Foreground” and “Background” respectively with TLabel components.

The colour combo boxes will be used to select the background and foreground colours of the console. The possible colours are restricted to the 16 basic system colours. So set the Style property of both combos to [cbStandardColors]. You can also include cbPrettyNames if you want proper colour names.

Now replace the placeholder comment in btnRunClick with this code:

App.ConsoleColors := MakeConsoleColors(
  cbForeground.Selected, cbBackground.Selected
);

This assigns the required colours to the ConsoleColors property. Note that we can’t assign the fields of the property separately, because they are read-only. So we must assign a whole TPJConsoleColors record to the property. To do this we take advantage of the MakeConsoleColors routine to construct the required TPJConsoleColors record.

There are two overloaded versions of MakeConsoleColors. The first takes TPJConsoleColor parameters and the second takes TColor parameters. We’ve used the second version to avoid the hassle of converting the TColor values read from the combo boxes to the TPJConsoleColor values needed by the TPJConsoleColors record. The routine does the conversion for us.

Rebuild and run the GUI application. Select some colours and click the Run button. Notice the colours are used in the console window.

Stage 3: WindowSize

Drop another TGroupBox on the form. In the group box add a TCheckBox named cbDefWindowSize with caption 'Use default' along with two TEdit_s, named edWindowWidth and edWindowHeight. Label the edit controls “Width” and “Height” using _TLabel components.

Select both edit controls and add the same OnKeyPress event handler, named EdNumberFilter, to both of them. Code the event handler as follows:

procedure TForm1.EdNumberFilter(Sender: TObject; var Key: Char);
begin
  {$IFDEF UNICODE}
  if not CharInSet(Key, ['0'..'9', #8]) then
  {$ELSE}
  if not (Key in ['0'..'9', #8]) then
  {$ENDIF}
    Key := #0;
end;

We will use the same event handler again later.

This event handler ensures that only digits can be entered in the edit controls because we use them to specify the width and height of the console window in pixels. (The #8 character represents a backspace character and is there to allow the backspace key to work.)

Finally, replace the placeholder commment in btnRunClick with this code:

if not cbDefWindowSize.Checked then
  App.WindowSize := MakeSize(
    StrToInt(edWindowWidth.Text), StrToInt(edWindowHeight.Text)
  );

This simply sets the WindowSize property to the width and height entered in the edit controls providing the check box is not checked. When the check box is checked no property value is set and its default value is used.

Here we have used the MakeSize helper routine that constructs a TSize record, setting its fields to the value of the two parameters. This is helpful since it is not possible to assign the fields of the WindowSize property individually; we must assign a complete record to the property.

Rebuild and run the application. Make sure the Use default check box is cleared and enter some sensible values for width and height (say 640 by 480) in the edit controls. Click the Run button. Notice the size of the window. Now repeat with the check box ticked. The values in the edit controls will be ignored and the console will have its default size.

Entering zero in either the width or height edit controls will cause the size to be ignored and the default console size to be used.

Stage 4: WindowPosition

The code to demonstrate WindowPosition is very similar to that for WindowSize. You again need a TGroupBox containing two TEdit controls and a TCheckbox. The check box caption should again be 'Use default' but name it cbDefWindowPos. Name the edit controls edWindowLeft and edWindowTop. Use TLabel components to label the edit controls “Left” and “Top”.

Connect both edit controls’ OnKeyPress events to the same EdNumberFilter event handler shown above.

Replace the placeholder commment in btnRunClick with this code:

if not cbDefWindowPos.Checked then
  App.WindowPosition := Point(
    StrToInt(edWindowLeft.Text), StrToInt(edWindowTop.Text)
  );

This works pretty much the same as the similar code in stage 3 above. The main difference being that, because WindowPosition has type TPoint, we construct the record value assigned to the property using the Point function from the Delphi VCL.

Rebuild the application one last time and run it. Clear the checkbox and enter values for the console window’s top left corner in screen co-ordinates. Click the Run button and observe the position of the console window. Run again and note that the window appears in the same position. Now tick the checkbox and run again. The console window appears in a default position. Run a few more times and you’ll notice the window’s default position moves each time.