I am writing a set of routines to print my visual component (TStringGrid descendant) with an ability to see its print preview. The preview is done using TPaintBox. I want that drawing utilized my component font.
So, basically I have several procedures:
Measuring all required sizes taking
Printerpage size and the component font as a basis.Drawing the component. It takes a
Canvasas input parameter. I want this to be a common drawing procedure forPrinter.CanvasandTPaintBox.Canvas.Scaling the
TPaintBoxdrawing usingSetGraphicsModeandSetWorldTransformso that it considers screen DPI / printer DPI ratio (in fact, 96 / 600).
procedure InitDrawingParams;
var
TextHeight: Integer;
begin
FPageWidth := Printer.PageWidth;
FPageHeight := Printer.PageHeight;
//actually, calculating the scale is a bit more complex,
//but this is just a simplification to illustrate the idea
FScale := 96 / 600;
Printer.Canvas.Font.Assign(MyStringGrid.Font); //in fact, Tahoma, 8
TextHeight := Printer.Canvas.TextHeight('I');
FDataOffset := TextHeight div 5;
FRowHeight := TextHeight + FDataOffset;
PaintBox.Width := Round(FPageWidth * FScale);
PaintBox.Height := Round(FPageHeight * FScale);
end;
procedure DrawPage(ACanvas: TCanvas);
var
R: TRect;
PageMargin, RectWidth, RectHeight: Integer;
begin
PageMargin := FPageWidth div 25;
//Drawing the rectangle at the top of the page
//and fill it with the text:
RectWidth := FPageWidth - 2 * PageMargin;
RectHeight := FRowHeight;
ACanvas.Rectangle(
PageMargin,
PageMargin,
PageMargin + RectWidth,
PageMargin + RectHeight
);
R.left := PageMargin + FDataOffset;
R.top := PageMargin;
R.right := PageMargin + RectWidth - FDataOffset;
R.bottom := PageMargin + RectHeight;
ACanvas.Font.Assign(MyStringGrid.Font);
DrawText(
ACanvas.Handle,
PChar(MyStringGrid.Cells[0, 0]),
-1,
R,
DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX
);
end;
procedure TMyForm.PaintBoxPaint(Sender: TObject);
var
XForm: TXForm;
XFormOld: TXForm;
GMode: Integer;
dc: HDC;
begin
dc := PaintBox.Canvas.Handle;
XForm.eM11 := FScale;
XForm.eM12 := 0;
XForm.eM21 := 0;
XForm.eM22 := FScale;
XForm.eDx := 0;
XForm.eDy := 0;
GMode := SetGraphicsMode(dc, GM_ADVANCED);
try
if GetWorldTransform(dc, XFormOld) then
try
SetWorldTransform(dc, XForm);
PaintBox.Canvas.Brush.Color := clWhite;
PaintBox.Canvas.FillRect(Rect(0, 0, FPageWidth, FPageHeight));
DrawPage(PaintBox.Canvas);
finally
SetWorldTransform(dc, XFormOld);
end;
finally
SetGraphicsMode(dc, GMode);
end;
end;
Everything is perfect when I start printing and call DrawPage(Printer.Canvas). But DrawPage(PaintBox.Canvas) draws very small text. It is about 96 / 600 smaller than I expected. The rectangle is drawn correctly in both ways.
Using SetGraphicsMode and SetWorldTransform, I expected that I will have a common drawing procedure and all needed scaling for rectangle and text will be done automatically.
I also tried to adjust the Font.Height like
ACanvas.Font.Height := Round(ACanvas.Font.Height / FScale);
but the result is very poor especially when I change the size of PaintBox thus changing the FScale.
So, my questions:
Is it possible to have one universal drawing procedure for printing and for previewing?
What am I missing in my code and how it can be improved to render the font correctly?
UPDATE:
Just discovered that
Printer.Canvas.Font.Assign(MyStringGrid.Font);
and
PaintBox.Canvas.Font.Assign(MyStringGrid.Font);
work differently. In the first case, printer font height is adjusted automatically probably due to different printer PixelsPerInch and the grid PixelsPerInch (or, more precisely, PixelsPerInch of their fonts), while there is no such a difference between the grid Canvas and PaintBox Canvas.
That's why I get so small font in the preview.
So, it seems, when drawing to the PaintBox.Canvas, it is absolutely necessary to add this code after the font assigning:
if Preview then
ACanvas.Font.Height :=
MulDiv(
ACanvas.Font.Height,
FPrinterPixelsPerInchX,
Screen.PixelsPerInch
);
With those lines, the font in the preview mode is scaled more or less well. But another problem appears:
When drawing the text over the previously drawn cell rectangle, the text margins sometimes overlap the rectangle's border, especially when the preview size gets smaller.
For larger preview resolution, everything is much better:
How can I fix that for smaller resolution?


ModifyWorldTransformandSetGraphicsModeor one of them), and I see no change in the behavior. I think, setting it back cannot change the drawing done prior to that call.