Lazarus

Free Pascal => Windows => Topic started by: DesJardins on April 29, 2017, 06:55:22 pm

Title: Print
Post by: DesJardins on April 29, 2017, 06:55:22 pm
Looking for simple text to printer.  LST does not seem to work like it did in old Turbo 4.  I don't need a canvas or buttons- just text print.
Python has a quick way to print to a file on disk, then send the file to a printer--open a file, write to it, close the file, then use operating system "startfile" to print it instantly.  Seems to work with all printers
Like this:

import sys
import os
print('check your printer')
sys.stdout = open('log.txt','w')
print('hey')
print( 'this is a test')
print('12356')
sys.stdout. close()

os.startfile("log.txt", "print")

Does FPC have something like this that I have not yet found?
Title: Re: Print
Post by: Thaddy on April 29, 2017, 07:11:41 pm
Well, what are your problems with LST? .... because it is still supported:
Code: Pascal  [Select][+][-]
  1. program testprint;
  2. uses printer;
  3. begin
  4. writeln(LST, 'Hello world');
  5. end.

Title: Re: Print
Post by: DesJardins on April 29, 2017, 09:25:07 pm
I got the following:

Debugger Exception Notification
Project testprint raised exception class 'RunError(103)'
in file 'testprint.lpr' at line 4
Title: Re: Print
Post by: Thaddy on April 29, 2017, 09:35:17 pm
On Windows it should include apptype:
Code: Pascal  [Select][+][-]
  1. program testprint;
  2. {$APPTYPE CONSOLE}
  3. uses printer;
  4. begin
  5. writeln(LST, 'Hello world');
  6. end.
Title: Re: Print
Post by: DesJardins on April 29, 2017, 09:56:04 pm
Project testprint raised exception class 'unknown'

at line 5

The printer is working.  I can use ctrl "P" and the printer prints out a copy of the whole program.

is there something that needs to be set in the "project options"?
Title: Re: Print
Post by: Thaddy on April 29, 2017, 10:06:47 pm
That should be impossible, because that code does not even rely on object pascal modes. Which is necessary for "Exception class".....
I tested this code....
Maybe try this, because if there isn't any printer...:
Code: Pascal  [Select][+][-]
  1. program testprint;
  2. {$APPTYPE CONSOLE}
  3. uses printer;
  4. begin
  5.   if IsLstAvailable then
  6.      writeln(LST, 'Hello world')
  7.   else
  8.      writeln('There is no printer associated with the default PRN printer device');
  9. end.

If you have a Windows printer this may fail, but these cheapo printers are rare nowadays (because it was a bad idea).

Also note that TP4 executables would crash if there wasn't a printer.... Hence the check.
Title: Re: Print
Post by: DesJardins on April 29, 2017, 10:18:03 pm
the 'else' kicked in.

It's a modern, high-quality Brother printer.  How about some option that needs to be turned on? or off?

I'm using Windows 10
Title: Re: Print
Post by: marcov on April 29, 2017, 10:56:03 pm
Did you check if the driver supports old dos compatibility devices?

Are you absolutely sure this setup works with TP4 ?
Title: Re: Print
Post by: DesJardins on April 30, 2017, 05:00:21 am
You can't run TP4 on 32 bit machine, but it worked on 16 bit for the last 25 years.  I'm trying to re-write for modern computer.

printer is working from computer, so it is in the compile.  How do I get it to recognize the printer?  Is there a test I can run?  What needs to change?

I couldn't get it to run on a Canon dot matrix printer either (both direct wired. )

Title: Re: Print
Post by: Thaddy on April 30, 2017, 07:20:58 am
Has nothing to do with TP4. It has to do with the fact that your printer is probably not connected to LPT1 (which is aliased PRN by definition) , but to another USB LPT. LPT3, maybe?
Check in the device manager. If that is the case, you can use InitPrinter to set the printer to a different name. In DOS days, there usually was just 1 printer device connected to the parallel port, not through a USB layer.

Example that prints to LPT3:
Code: Pascal  [Select][+][-]
  1. program testprint;
  2. {$APPTYPE CONSOLE}
  3. uses printer;
  4. begin
  5.   InitPrinter('LPT3');
  6.   if IsLstAvailable then
  7.      writeln(LST, 'Hello world')
  8.   else
  9.      writeln('There is no printer associated with the default PRN printer device');
  10.   readln;
  11. end.

You must use WMI (WBem object) to list, connect printers and ports.
The printer needs to support the LPR protocol, not just RAW.
It is by definition a lot more work than in the olden days if you do not manually set up the printer for every computer you run your software on...
Title: Re: Print
Post by: DesJardins on April 30, 2017, 05:05:34 pm
Thaddy, Thanks for the help.  I don't have time to check it out this morning, but I do have a couple of other questions.

I want to write this to be and executable program that has a chance of running on almost anybody's modern printer.  It seems to me that not everybody will be using the same ports.  It seems like I need be getting to a USB port.  I don't think that is happening. 

That is one reason I was originally looking for code that would direct printing from a results file that I had just sent to the disk. Like I was doing in Python as described in my first post. (I save a file to the disk anyway because I use it be available to reload if somebody makes a mistake typing and they don't want to re-enter a lot of data to run it again -- saves them a lot of time). 
Now I am concerned that I don't have a "path" set to get from FPC or Lazarus to my printer.  Is "path" a problem?

So maybe the proper code for me is to not use the LST function.  Now what?  What is the simple way to send text output to any printer?

If you want to see the first program I am updating, check my web page www.rjdesjardins.com and look at the bottom for Psychrometric program.  Right now I am not even trying to use objects like buttons.  Just get it running.

thanks again, Richard
Title: Re: Print
Post by: Thaddy on April 30, 2017, 05:18:24 pm
Last first: You don't need TButton etc objects..., you will need a COM object under windows (easy. There are already .vbs scripts on windows 10 that show you how)
Then:
- Yes, on a modern computer the default printer is obtainable, but not always where it used to be.
- A more modern approach, which will do much of the hard work, is using the printers unit (with an s, not printer without s that is needed just for LPT) and use the printer canvas. I will see if I can come up with an example for both.
Title: Re: Print
Post by: DesJardins on May 01, 2017, 05:42:54 pm
I sent an email to Brother printer people.  No response, yet.

I have been trying to use printer4lazarus, but can't that to work either. 

Seems there has to be an easy way to use FPC to tell the computer to print a text file that is on disk.

Is there a way to get FPC to search for a printer?

What is in the Printer and Printers codes?  What is in the printer4lazarus code? Are there any parameters that can be transmitted that will get things started?

Frustration
Title: Re: Print
Post by: Thaddy on May 01, 2017, 06:12:09 pm
You think on the one hand too lazy (try to get things working the dos way without effort) and too complex.. Printing is harder than with DOS, but not THAT hard...
Again, if I have some time (left) I will give you two examples (one old skool, one printer canvas) . Can take two days, because it is busy here.
Title: Re: Print
Post by: sky_khan on May 01, 2017, 11:20:22 pm
I wrote a proprietary text-mode reporting library long years ago for a company I worked for, using this approach
https://support.microsoft.com/en-us/help/138594/howto-send-raw-data-to-a-printer-by-using-the-win32-api (https://support.microsoft.com/en-us/help/138594/howto-send-raw-data-to-a-printer-by-using-the-win32-api)
So, you can use "raw" mode to bypass processing and send whatever you like to printer, still using windows spooler.
But I have no experience on Linux or other OSes.
Title: Re: Print
Post by: DesJardins on May 02, 2017, 02:55:07 am
Thanks SkyKhan,
Seems I am asking too much, and I know Thaddy will likely reply some time soon. 
I have a Windows 10 computer with a Brother MFC  laserjet printer operating on wifi, but it can be hard wired is necessary.  The Cannon Ink jet printer uses the USB port.  Neither one works with FPC.  I see others with new HP and other printers.
All I was looking for is a PROGRAM that prints "hello world".
Program Hi
interface
uses  whatever
Implementation
var f: textfile
begin
  rewrite f;
      print (f, 'hello world');
  close f;
end.

and have it go to the printer and actually print. 

or as an alternative have it save f to a text file on disk and use FPC to tell the computer to print the text file, like I could do with Python.  I'm just trying to not re-write 24,000 lines of code in Python.  I'm not looking at graphics or anything fancy.  Just print text that is the result of my program calculations.

I have been reading for 3 days and still don't find a workable example.

I can't be the only one.  Himie has had over 1000 views of his first post.

Richard
Title: Re: Print
Post by: sky_khan on May 02, 2017, 05:04:19 am
Sorry, I realized I have not pay attention to your original question. I assumed that you still want to send text/binary data directly to printer but as I see now, you just want to write text to a lazer/inkjet printers.
The thing is these printers do not print text anymore, they draw text as graphic. So you can not send raw text to print. You need to draw on them. Like below,

Code: Pascal  [Select][+][-]
  1. uses
  2.   classes, printers, osprinters, math;
  3.  
  4. const
  5.   LineCount = 50;  // Adjust font size to fit 50 lines on page
  6.  
  7. procedure PrintStrings(aLines:TStrings);
  8. var
  9.   PrintArea,
  10.   LineRect : TRect;
  11.   I,
  12.   LineHeight : Integer;
  13. begin
  14.   // half of an inch margin for each side
  15.   with PrintArea do
  16.   begin
  17.     Left:=Printer.XDPI div 2;
  18.     Top:=Printer.YDPI div 2;
  19.     Right:=Printer.PageWidth-Printer.XDPI div 2;
  20.     Bottom:=Printer.PageHeight-Printer.YDPI div 2;
  21.   end;
  22.  
  23.   LineRect.Left:=PrintArea.Left;
  24.   LineRect.Right:=PrintArea.Right;
  25.   LineRect.Top:=PrintArea.Top;
  26.  
  27.   Printer.Title:='My Report';
  28.   Printer.BeginDoc;
  29.   try
  30.     Printer.Canvas.Font.Height:=(PrintArea.Bottom-PrintArea.Top) div LineCount;
  31.     for I:=0 to Min(aLines.Count-1,LineCount-1) do
  32.     begin
  33.       if Trim(aLines[I])='' then LineHeight:=Printer.Canvas.TextHeight('X')
  34.       else LineHeight:=Printer.Canvas.TextHeight(aLines[I]);
  35.       LineRect.Bottom:=LineRect.Top+LineHeight;
  36.       Printer.Canvas.TextRect(LineRect,LineRect.Left,LineRect.Top,aLines[I]);
  37.       LineRect.Top:=LineRect.Bottom;
  38.     end;
  39.   finally
  40.     Printer.EndDoc;
  41.   end;
  42. end;

In order to use this procedure you need to add Printer4Lazarus package to your project as dependancy. (Select Menu->Project->Project Inspector->Required Packages and click "Add >>" button)
You can put a TMemo component on your form and call this procedure as "PrintStrings(Memo1.Lines);" in a button click event for example.
Title: Re: Print
Post by: Thaddy on May 02, 2017, 11:39:46 am
The thing is these printers do not print text anymore, they draw text as graphic.
That is simply not true anymore. There are very few printers nowadays that are true Windows only printers. These are a relic of the past.
It used to be the case for cheapo's around 5-8 years ago. Most printers can be used as a line printer and will even select a fixed font in that mode.

Also: OP has a real matrix printer available as he wrote.
The issue is that you simply need some extra code - compared to DOS -  to determine where the default printer is. It is often NOT at LPT1 because everything is USB.
Under windows it is in theory not much more than retrieving it through GetDefaultPrinter and THEN call InitPrinter with the name obtained from that call.
As I said, I will prepare an example.
Title: Re: Print
Post by: sky_khan on May 02, 2017, 09:52:20 pm
Well, I looked at source code for printers and winprinters and i noticed that it does support rawmode and it is easy to use like below.
But note that this will not work on virtual printers (like PDF printer drivers) or cheap printers which does not support text directly.

Code: Pascal  [Select][+][-]
  1. procedure RawPrintStrings(aLines:TStrings);
  2. const
  3.   CRLF = #13#10;
  4. var
  5.   I : Integer;
  6. begin
  7.   Printer.Title:='My Report';
  8.   Printer.RawMode:=true;
  9.   Printer.BeginDoc;
  10.   try
  11.     for I:=0 to aLines.Count-1 do
  12.       Printer.Write(aLines[I]+CRLF);
  13.   finally
  14.     Printer.EndDoc;
  15.   end;
  16. end;
  17.  
Title: Re: Print
Post by: DesJardins on May 30, 2017, 06:46:19 pm
Thaddy,

I finally have the rest of my first program re-write almost completed, and it sure would be nice if you could give an example of how to call a modern prin ter as you suggested using  GetDefaultPrinter and THEN call InitPrinter with the name obtained from that call. 

If it helps, I can save results to a file, and then just have the program tell the computer to choose that file and print it, like I could do with Python.  I want results saved to a file anyway, because I can use it to restart the program without re-entering a bunch of data.
TinyPortal © 2005-2018