Search code examples
delphicanvasprinting

Delphi printing with Canvas, align text to the right


I'm printing using TPrinter.Canvas and am trying to align the text to the right due to money displaying numbers.

The text is printed with this code:

Printer.Canvas.Textout(800, 100, 250.00); //charge1
Printer.Canvas.Textout(800, 200,  10.00); //charge2
Printer.Canvas.Textout(800, 300, 260.00); //Total Amount

Sample image

How can I align the lines to display correctly?


Solution

  • You could use the lower level device context Api's to more accurately control the text output, such as DrawText() as suggested by Jerry. However, doing this will require that you pre-calculate/set the bounding rectangle for your text output so that Windows knows the area which any alignment is relative to.

    There are two potentially simpler alternatives:

    Option 1 - For Fixed Width Fonts ONLY

    This may be appropriate for you since you appear to be using a fixed-width font.

    All we do here is introduce padding to your strings prior to output. This may be simpler than the calculations required for the output rectangles etc.

    To do this, decide on the longest string you will accept for output and then add whatever spaces you need to the left of each string to ensure they are all the same length. With a fixed width font, a space takes up the same horizontal space as any other character so by making all strings the same length you will achieve "right alignment":

    procedure PrintRightJustified(const aX, aY, aMaxLen: Integer; aValue: String);
    var
      s: String;
    begin
      s := aValue;
    
      // Pad the string with spaces to the maximum length
      if Length(s) < aMaxLen then
        s := StringOfChar(' ', aMaxLen - Length(s)) + s;
    
      Printer.Canvas.Textout(aX, aY, s);
    end;
    

    Then call this method to output your strings right-justified to a consistent maximum length, e.g. if 6 is your maximum length (999.99):

    PrintRightJustified(800, 100, 6, '250.00'); //charge1
    PrintRightJustified(800, 200, 6, '10.00'); //charge2
    PrintRightJustified(800, 300, 6, '260.00'); //Total Amount
    

    How to handle scenarios where the specified string is longer than the maximum width is left as an exercise.

    Option 2 - For Any Font

    Another way, which would work for fixed width or variable width fonts (e.g. Arial) would be to choose the position of the rightmost edge of the strings and calculate the X position relative to this based on the device width calculated for each string you are outputting:

    procedure PrintRightJustified(const aRightX, aY; aValue: String);
    var
      leftX: Integer;
    begin
      leftX := aRightX - Printer.Canvas.TextWidth(aValue);
    
      Printer.Canvas.Textout(leftX, aY, aValue);
    end;
    

    You don't need to specify a maximum width for this version, it works regardless of font being used:

    PrintRightJustified(900, 100, '250.00'); //charge1
    PrintRightJustified(900, 200, '10.00'); //charge2
    PrintRightJustified(900, 300, '260.00'); //Total Amount
    

    This does mean that text may potentially "bleed" too far to the left without some mechanism to detect and handle this. Again, If that is a concern then either move the right-edge further across or you will have to come up with a way of handling it (left as an exercise for you since we don't know what your precise requirements are).