Recent

Author Topic: change fonts going to printer  (Read 7204 times)

DesJardins

  • New member
  • *
  • Posts: 20
change fonts going to printer
« on: August 15, 2018, 01:26:27 am »
I want to send the following simple spreadsheet to a modern printer. (only a few lines of the whole print out are shown to keep this inquiry short, but you get the idea of what I am trying to do)

The font used by either the program, the computer, or the printer (I don't know which it is) is proportionally spaced, so formatting does not let me line it all into nice clean columns. If I use something like "Courier New" which I use to open it from a file that I saved so I can open it in Word or Notes then the length of each cell works fine.  But I have not figured out how to format it for transmittal directly to a printer.  To see a picture of the full screen you can visit my website @ www.rjdesjardins.com.  All I want to do is print it without saving to a file and using Notes or Word to print it.  In Python you can write a program to save to a file and then print the file all with one click..  I still have not found where I can do in FP. 
Note that the program is strictly Free Pascal.  It does not use Lazarus controls, like grid, Can I combine FP and Laz and use font controls from Laz?

This is what Courier New spacing looks like:  (actually I had to modify this to get it to line up for this demo, it is not perfect).  The object is pretty columns.

HOT WATER        95.00   STACK HT.        10.00                   PRESSURE DROPS
COLD WATER      85.00   STACK DIA        19.04   INLET LVRS       0.284    PLEN HT W
WET BULB          78.00   FAN DIA            18.00   FILL                  0.388              3.00
DRY BULB           95.00   HUB DIA             4.00   ELIMINATOR      0.038    PLEN HT L
ALTITUDE            0.00   FAN TYPE     HUDSON     PLENUM            0.025              6.00
FILL TYPE   OF21MA       NO BLADES          9.00    SUBTTL<hs>    0.735               1.3
FILL HT.              4.00    MOTOR RPM   1750.00    EXTNL<hs>      0.035              1.44
INLET HT.            5.00    GEAR RATIO        8.50   TOTAL<hs>       0.770   FANDK HT L

This is Arial or something like Arial that goes to the printer.  nothing lines up in columns. 

HOT WATER        95.00   STACK HT.         10.00                   PRESSURE DROPS
COLD WATER       85.00   STACK DIA         19.04   INLET LVRS        0.284   PLEN HT W
WET BULB         78.00   FAN DIA           18.00   FILL              0.388         3.00
DRY BULB         95.00   HUB DIA            4.00   ELIMINATOR        0.038   PLEN HT L
ALTITUDE          0.00   FAN TYPE     HUDSON       PLENUM            0.025         6.00
FILL TYPE   OF21MA       NO BLADES          9.00   SUBTTL<HS>        0.735          1.3
FILL HT.          4.00   MOTOR RPM       1750.00   EXTNL<HS>         0.035         1.44
INLET HT.         5.00   GEAR RATIO         8.50   TOTAL<HS>         0.770   FANDK HT L

How do I change the font?
I have tried a lot of Format controls fmt, setlength, strLength, etc.  I have tried repeat/until, adding spaces to give me 12 wide, etc.  Sometimes I get some really weird results. 
 
Here is what I am using to send to find a default printer and print it:

Unit myPrinterUnit5;   {last update 8/26/17  from C:\psy\psy\psy_11_30_17}
 {$mode objfpc}{$H+}
 interface

procedure BeginPrinting(const sPrinter: string);
{procedure myPrintLn(const S: String);}
procedure PageReady;
function GetDefaultPrinter: string;
{procedure testprint;}
procedure PU(const S: string);

var   hdcPrint: hDc;   DocInfo: TDocInfo;   PenPos: TPoint;    PrintRes: TPoint;

implementation

function GetDefaultPrinter: string;
var    DefaultPrinter: array [0 .. 79] of Char;     I: Integer;
begin
  GetProfileString('windows', 'device', '', DefaultPrinter, SizeOf(DefaultPrinter) - 1);
  I := Pos(',', DefaultPrinter);
  if I = 0 then I := Length(DefaultPrinter) + 1;
  GetDefaultPrinter := Copy(DefaultPrinter, 1, I - 1);
end;

procedure BeginPrinting(const sPrinter: string);
begin
  hdcPrint := CreateDC(pchar('WINSPOOL'), pchar(sPrinter), nil, nil);
  FillChar(DocInfo, SizeOf(DocInfo), #0);
  DocInfo.cbSize := SizeOf(DocInfo);
  DocInfo.lpszDocName := 'Myprogram';
  if StartDoc(hdcPrint, DocInfo) = 0 then Exit;
  if not StartPage(hdcPrint) = 0 then
  begin
    EndDoc(hdcPrint);
  end;
  PrintRes.X := GetDeviceCaps(hdcPrint, LOGPIXELSX);
  PrintRes.Y := GetDeviceCaps(hdcPrint, LOGPIXELSY);
  PenPos.X := round((0.5 * PrintRes.X) / 2.54); // margin 0.5 cm
  PenPos.Y := round((0.5 * PrintRes.Y) / 2.54);
end;

procedure PageReady;
begin
  EndPage(hdcPrint);
  EndDoc(hdcPrint);
  DeleteDc(hdcPrint);
end;

procedure PU(const S: string);
begin
  if S <> '' then
    TextOut(hdcPrint, PenPos.X, PenPos.Y, @S[1], Length(S));
    PenPos.Y := PenPos.y + round((1 / 6) * PrintRes.Y); // 6 lines per inch
end;

end.


This is the code for reading the cells:

  for J:=1 to FYmax do
  begin
    Line:='';
    for I:='A' to FXmax do
    begin
      with Sheet[I,J] do
      begin
        while (Length(Line)<XPOS-4) do Line:=Line+' ';
        if (Constant in CellStatus) or (Formula in CellStatus) then
        begin
          if not (Locked in CellStatus) then
          begin
            Str(Value:FW:DEC,P);                        {FW does usually set the width of a cell properly}
            Line:=Line+P;
          end;
        end else Line:=Line+Contents;           {Contents is type AnyString;} 
              {EVERY TIME I TRY TO SET WIDTH OF CONTENTS IT GIVES UNEVEN WIDTH OF CELL}
      end; { With }
    end; { One line }
    PU(Line);                  {PU calls myPrinterUnit5}
    end; { End Column }
  PageReady;               {this sends it to the default printer}
  Grid;
  LowVideo;
  update;
  GotoCell(FX,FY);
end
______

UNIT CF20_2;
(* Program cf20_2.pas
  This is the spread sheet portion of the counterflow program
which is included in Cflow11.pas  LAST UPDATE 1/10/93 *)
{$mode objfpc}{$H+}
INTERFACE
USES crt,dos, sysutils,  Cf20Var, CF20error, CF20Fan, CF20fan1, CF20psychro, myPrinterUnit5;
const
  FXMax: Char  = 'G';    FYMax  = 21;
type
  Anystring   = string[70];
  String3 = string[3];
  SheetIndex  = 'A'..'G';
  Attributes=(Constant,Formula,Txt,OverWritten,Locked,Calculated);
  CellRec    = record
      CellStatus: set of Attributes;
      Contents:   Anystring;
      Value:      Real;
      DEC,FW:     0..20;      {number of decimals  width}
  end;
  Cells      =  array[SheetIndex,1..FYMax] of CellRec;
const                      { (3,14,25,36,47,58,69);}
  XPOS: array[SheetIndex] of integer = (3,16,29,42,55,68,81);
  BFX: SheetIndex = 'B';
  DFX: SheetIndex = 'D';
  FFX: SheetIndex = 'F';
  GFX: SheetIndex = 'G';
var
  FileName: anystring;
  Line: string[100];
Var S1, S2 : AnsiString;  {used with date time}

var
  Sheet:         Cells;
  FX:            SheetIndex;
  FY:            Integer;
 { Ch:            Char; } {Ch now in CFLOWVAR as a master}
  RDFile:        file of CellRec;
  AutoCalc:      boolean;
  AutoSave:      boolean;
  Temp:          real;  {a holding value for NewData}
{  S:  anystring;} { this was not here in the original}

The length of “Value” for numbers seems to work properly.  But “Contents” and other text does not.

 Am I wrong in thinking I need to change the font to one that has evenly spaced characters?

Thanks for reading.
Richard

440bx

  • Sr. Member
  • ****
  • Posts: 387
Re: change fonts going to printer
« Reply #1 on: August 15, 2018, 02:23:50 am »
Hello Richard,

I didn't study your code in full detail but, I get the impression from what I saw, that the reason things are not aligning is because you don't set the alignment before calling TextOut.

Usually, when using a proportionally spaced font, you want to set the alignment to the right.   That allows you to calculate one coordinate and all text is output to the right of that coordinate causing it to be neatly aligned (the text ends at the coordinate, instead of starting at the coordinate, which usually makes a jumble.)

In the code you presented, it seems that just setting the alignment would go quite a ways to getting closer to getting things to align properly.

HTH.



DesJardins

  • New member
  • *
  • Posts: 20
Re: change fonts going to printer
« Reply #2 on: August 15, 2018, 09:37:09 pm »
If I use the Format function it allows me to use the "-" sign to align left, but then it does not seem to allow me to set the cell width.  I would prefer to align the text to the left and the numbers to the right because it reads better.  I still think the key would be to change the font to a monospaced font (like Courier New), then I can set the width in characters.  With proportional spacing this doesn't work.  Is there a way to set the spacing in pixels?  Can I use the Laz fonts with FPC?  If so, how do I do that?

What do you mean by setting a coordinate?  How do I set the coordinates across several cells in a line at print time?  I guess I could do this for each cell (each cell has a name, like C6 for row and column), with a bunch of code, but somehow I don't think that should be necessary.

440bx

  • Sr. Member
  • ****
  • Posts: 387
Re: change fonts going to printer
« Reply #3 on: August 16, 2018, 04:28:19 am »
If I use the Format function it allows me to use the "-" sign to align left, but then it does not seem to allow me to set the cell width.  I would prefer to align the text to the left and the numbers to the right because it reads better.  I still think the key would be to change the font to a monospaced font (like Courier New), then I can set the width in characters.  With proportional spacing this doesn't work.  Is there a way to set the spacing in pixels?  Can I use the Laz fonts with FPC?  If so, how do I do that?

What do you mean by setting a coordinate?  How do I set the coordinates across several cells in a line at print time?  I guess I could do this for each cell (each cell has a name, like C6 for row and column), with a bunch of code, but somehow I don't think that should be necessary.
What you're doing at this time depends on the width of the string being determined by the number of characters in the string.  That is only true when using a Monospaced font.   You are correct that if you change to a monospace font, your code will probably work.

As far as being able to set the spacing in pixels, the answer is, you do that "manually".   For instance, if you decide you are going to output your first label at point (X:100; Y:100), you tell TextOut that you want left alignment (TA_LEFT) and TextOut will output the label starting at that coordinate.  For the value that is associated with that label, you calculate a different point, say (X:400; Y:100) (same Y so it is horizontally aligned) and you tell TextOut that you want right alignment (TA_RIGHT), that will cause TextOut to output the value in such a way that it _ends_ at that coordinate.  By varying the Y coordinate, you write the following lines repeating the same method.

You calculate the spacing by using GetTextExtentPoint32 to determine the maximum width of all your labels.  Call that MaxLabelWidth.  Do the same for the values, calculate the maximum width of the values, call that MaxValueWidth.  If you had picked (X:100; Y:100) as the coordinate of the first label then, the coordinate of the first value would be something along the lines of (X:100 + MaxLabelWidth + MaxValueWidth + SomeWhiteSpaceInPixels; Y:100).

Once you've got that, and you output with the correct alignment, everything will be neatly aligned.

I attached a little program that gives the idea.  The output is relative to the red crosshair (I picked the center of the screen for this example.  You'd pick something to the left of that for the labels and to the right for the values.)  Look at the source to see how to use TextOut and GetTextExtentPoint32 to have the string output exactly where you want it.

The most important thing is to pick the starting point (coordinate) for the labels, from that, you calculate the coordinate of a point for the values that will result in output being visually appealing, after that it's all calls to SetTextAlign and TextOut while varying the Y coordinate.

HTH.



DesJardins

  • New member
  • *
  • Posts: 20
Re: change fonts going to printer
« Reply #4 on: August 16, 2018, 07:19:51 am »
thanks for your comments.  I know it took you some time.   

I read that there is no way to change the fonts.   It was a 2013 article.   Is that correct?  I saw there were font programs for sale for FPC, but I suspect they are just for the screen, and not the printer.  I have not yet had time to look into them.

Richard

engkin

  • Hero Member
  • *****
  • Posts: 2127
Re: change fonts going to printer
« Reply #5 on: August 16, 2018, 07:23:43 am »
As 440bx have shown, there are a few solutions.

If you want to try changing the font, simply create the fonts you want to use and select one of them:
Code: Pascal  [Select]
  1. function CreateFontObject(AFontName: string): HFONT;
  2. var
  3.   LDataFont: LOGFONT;
  4. begin
  5.   FillChar(LDataFont, SizeOf(LDataFont), 0);
  6.   with LDataFont do
  7.   begin
  8.     lfHeight := -MulDiv(10, GetDeviceCaps(hdcPrint, LOGPIXELSY), 72);
  9.     lfCharSet:=ANSI_CHARSET;
  10.     lfFaceName := AFontName;
  11.   end;
  12.   Result := CreateFontIndirect(LDataFont);
  13. end;
  14. ...
  15. var
  16.   fontCourierNew, fontArial: HFONT;
  17. ...
  18.   fontCourierNew := CreateFontObject('Courier New');
  19.   fontArial := CreateFontObject('Arial');
  20. ...
  21.   oldFont := SelectObject(hdcPrint, fontCourierNew);
  22.   TextOut(hdcPrint,....
  23. ...
  24.   SelectObject(hdcPrint, fontArial);
  25.   TextOut(hdcPrint,...
  26.  

When done, select the original font, and delete the rest:
Code: Pascal  [Select]
  1.   SelectObject(hdcPrint, oldFont);
  2.   DeleteObject(fontCourierNew);
  3.   DeleteObject(fontArial);

440bx

  • Sr. Member
  • ****
  • Posts: 387
Re: change fonts going to printer
« Reply #6 on: August 16, 2018, 08:04:09 am »
thanks for your comments.  I know it took you some time.   

I read that there is no way to change the fonts.   It was a 2013 article.   Is that correct?  I saw there were font programs for sale for FPC, but I suspect they are just for the screen, and not the printer.  I have not yet had time to look into them.

Richard
You're welcome.  I'm pleased to help in the measure I can.

As far as the fonts, Engkin above provided the code needed to use any installed font. 

As far as the article, that sounds "strange".  You can pretty much use any font installed on the system.  Windows will render the font as it is needed by the device context (that's pretty much what selecting the font into the device context does.)

As far as screen fonts and printer fonts, some fonts, usually bitmapped fonts, are meant for screen output and render poorly on a printer but, those are few now.  If you stick to TrueType fonts, you can use any font that is installed in the system.  A TrueType font should render well on just about any printer.

For now, you probably want to keep it simple.  Use a font like Arial or Verdana.  A font that is almost guaranteed to be installed in the system.  Once you get your program working with Arial (for instance) then you can get a list of available fonts with EnumFontFamiliesEx and play with the various fonts you get from it.

HTH.