Skip to content

Delphi 2010 DirectWrite "Hello World" Example

In my previous post I have translated Windows 7 SDK Direct2D "Advanced Geometries" example from C++ to Delphi 2010 code. That was a lot of fun, so I have decided to continue the adventure in the realm of Direct2D programming and this time converted one of the DirectWrite examples - DirectWrite sample "Hello World".

Delphi 2010 Hello World DirectWrite sample app

Delphi 2010 Hello World DirectWrite sample app

In order to avoid writing over and over again the same Direct2D-specific code for creating TDirect2DCanvas instance and implementing "Resize" and "WMEraseBkgnd" methods, I have decided to refactor this common code into a reusable base class called "TFormD2D".


unit D2DUtils;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, D2D1, Direct2D;

type
  TFormD2D = class(TForm)
  private
    FD2DCanvas: TDirect2DCanvas;
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  protected
    procedure Resize; override;
    procedure Paint; override;
    procedure CreateD2DResources; virtual;
    procedure PaintD2D; virtual;
    function rt: ID2D1RenderTarget; // conveniency function
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property D2DCanvas: TDirect2DCanvas read FD2DCanvas;
  end;

implementation

constructor TFormD2D.Create(AOwner: TComponent);
begin
  inherited;

  if not TDirect2DCanvas.Supported then
    raise Exception.Create('Direct2D not supported!');

  FD2DCanvas := TDirect2DCanvas.Create(Handle);

  CreateD2DResources;
end;

destructor TFormD2D.Destroy;
begin
  FD2DCanvas.Free;
  inherited;
end;

procedure TFormD2D.CreateD2DResources;
begin
  // create Direct2D resources in descendant class
end;

function TFormD2D.rt: ID2D1RenderTarget;
begin
  Result := D2DCanvas.RenderTarget;
end;

procedure TFormD2D.Resize;
var
  HwndTarget: ID2D1HwndRenderTarget;
begin
  inherited;

  if Assigned(D2DCanvas) then
    if Supports(
      rt, ID2D1HwndRenderTarget, HwndTarget) then
        HwndTarget.Resize(D2D1SizeU(ClientWidth, ClientHeight));

  Invalidate;
end;

procedure TFormD2D.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  // avoid flicker as described here:
  // http://chrisbensen.blogspot.com/2009/09/touch-demo-part-i.html
  Message.Result := 1;
end;

procedure TFormD2D.Paint;
begin
  inherited;
  D2DCanvas.BeginDraw;
  try
    PaintD2D;
  finally
    D2DCanvas.EndDraw;
  end;
end;

procedure TFormD2D.PaintD2D;
begin
  // implement painting code in descendant class
end;

end.

Using this base Direct2D class is simple. If you want to "Direct2D-enable" a VCL form class, just add "D2DUtils" unit to your project, add "D2DUtils" to the "uses" clause in the interface section of your form’s unit, and change your form’s base class from "TForm" to "TForm2D".
Now you only need to override "CreateD2DResources" and "PaintD2D" virtual methods and declare private members for different resources used for painting. In the first step you should create all Direct2D resources needed for painting like brushes, fonts, pens, geometries, and assign them to private variables in your form class. The second step is to implement "PaintD2D" that will include your painting code, most likely using "rt" convenience method that returns "D2DCanvas.RenderTarget" interface.

This is the actual code that paints "‘Hello World using DirectWrite in Delphi 2010". Note that the form class derives from "TFormD2" and not "TForm".


unit Unit38;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, D2DUtils, D2D1, Direct2D;

type
  // http://msdn.microsoft.com/en-us/library/ee264320(VS.85).aspx
  TForm38 = class(TFormD2D)
  private
    FBlackBrush: ID2D1SolidColorBrush;
    FTextFormat: IDWriteTextFormat;
  protected
    procedure PaintD2D; override;
    procedure CreateD2DResources; override;
  public

    { Public declarations }
  end;

var
  Form38: TForm38;

implementation

{$R *.dfm}

{ TForm38 }

procedure TForm38.CreateD2DResources;

begin
  inherited;

  rt.CreateSolidColorBrush(
    D2D1ColorF(clBlack, 1),
    nil,
    FBlackBrush
    );

  DWriteFactory.CreateTextFormat(
    PWideChar('Gabriola'),
    nil,
    DWRITE_FONT_WEIGHT_REGULAR,
    DWRITE_FONT_STYLE_NORMAL,
    DWRITE_FONT_STRETCH_NORMAL,
    72,
    PWideChar('en-us'),
    FTextFormat
   );

   FTextFormat.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
   FTextFormat.SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
end;

procedure TForm38.PaintD2D;
var
  aDisplayText: string;
  aRect: TD2D1RectF;
begin

  // fill with white color the whole window
  rt.Clear(D2D1ColorF(clWhite));

  aDisplayText := 'Hello World using DirectWrite in Delphi 2010';

  rt.DrawText(
    PWideChar(aDisplayText),
    Length(aDisplayText),
    FTextFormat,
    D2D1RectF(0, 0, ClientWidth, ClientHeight),
    FBlackBrush
    );
end;

end.

The "TForm38" class derives from "TFormD2" class. We need two Direct2D resources to render "Hello World": a text format reference and a black brush. That’s why the first thing to do is to define two fields in our form class:

FBlackBrush: ID2D1SolidColorBrush;
FTextFormat: IDWriteTextFormat;

In the "D2DCreateResource" method both fields are initialized and they are used in "PaintD2D" for rendering text on the form. In order to simplify code that needs to be there for painting surrounding calls to "D2DCanvas.BeginDraw" and "D2DCanvas.EndDraw" have been moved to the ancestor class and very frequently used calls to "D2DCanvas.RenderTarget. …" have been replaced with "rt" function that returns the same thing, but with fewer lines of code.

The source code for this application can be downloaded from EDN CodeCentral.

{ 4 } Comments

  1. David | December 14, 2009 at 8:34 pm | Permalink

    Perhaps it should be obvious but what are the main benefits of using Direct2D. I mean why would we want to do it rather than just a standard Delphi Canvas?

    Is it a case of extra power from extra drawing commands? A more object oriented approach to drawing? Extra speed, and if so under what conditions? Or all of the above?

    Sorry if I’m being dense here! The benefits of OpenGL or Direct3D are obvious in the 3D arena I’m just less certain about 2D.

  2. Paweł Głowacki | December 15, 2009 at 7:19 am | Permalink

    @David,
    Direct2D is based on Direct3D and as such takes advantage of the GPU instead of the CPU (as GDI).
    D2D provides more graphical functionality including anitaliasing. Check out this links for more info: http://blogs.technet.com/thomasolsen/archive/2008/10/29/introducing-the-microsoft-direct2d-api.aspx and http://msdn.microsoft.com/en-us/magazine/dd861344.aspx

  3. daliy computer tutorial | May 15, 2012 at 6:34 pm | Permalink

    Hi there, simply was alert to your blog thru Google, and found that it’s really informative. I’m gonna watch out for brussels. I’ll appreciate if you proceed this in future. Lots of folks will probably be benefited from your writing. Cheers!

  4. Ra | May 15, 2013 at 5:24 pm | Permalink

    Please explain: How to scroll this text in loop? Like a teleprompter

Post a Comment

Your email is never published nor shared. Required fields are marked *

Bad Behavior has blocked 2 access attempts in the last 7 days.

Close