Lazarus

Programming => General => Topic started by: J-G on August 14, 2022, 08:55:51 pm

Title: Printer Paper Orientation
Post by: J-G on August 14, 2022, 08:55:51 pm
I've used Printers4Lazarus to great effect in the past but never had the need to change from 'Portrait' to 'View'. With my current Project this has become necessary so I've reviewed the Wiki page 'Using the printer' along with the 'Printers' Unit. The former makes no reference to changing the orientation and although I do find a reference to SetOrientation (and Get...) in the Unit, I'm not having any joy in impementing a change.

Using the 'auto-complete' facility, I can access the property - Printer.SetOrientation - which requires a 'Value' which I assume may be 0 or 1 or something else entirely, but the compiler returns an 'Identifier not found' for SetOrientation() or a wierd (to me) 'Syntax error, "EXCEPT" expected but "(" found' if I reduce that to 'Orientation'.

The first error seems most peculiar when auto-complete offers the property.

Whilst I would be interested (academically) in the reasons behind the error messages, what I really want to know is how do I set the paper orientation?

A secondary question though is  how can I invoke the Printer Set Up Dialogue or the Page Set Up Dialogue?  both of which I have placed on the form but the [Events] associated with them don't have [OnClick]  -  I have to assume that a third party component (with [On Click]) is needed but can't yet fathom how I can link the two.

A positive answer to this secondary question may well mean that the first question becomes irrelevant!
Title: Re: Printer Paper Orientation
Post by: paweld on August 14, 2022, 09:20:12 pm
Code: Pascal  [Select][+][-]
  1. uses
  2.   Printers;
  3.  
  4. procedure TForm1.Button1Click(Sender: TObject);
  5. begin
  6.   //run printer dialog
  7.   ShowMessage('Current printer: ' + Printer.PrinterName);
  8.   if PrintDialog1.Execute then
  9.     ShowMessage('Printer changed to: ' + Printer.PrinterName + #13#10 +
  10.       ' and number of copies set to: ' + IntToStr(Printer.Copies));
  11. end;
  12.  
  13. procedure TForm1.Button2Click(Sender: TObject);
  14. const
  15.   poarr: array [TPrinterOrientation] of String = ('portait', 'landscape', 'reverse portait', 'reverse landscape');
  16. begin
  17.   //run page setup dialog
  18.   ShowMessage('Current orientation: ' + poarr[Printer.Orientation]);
  19.   if PageSetupDialog1.Execute then
  20.     ShowMessage('Orientation changed to: ' + poarr[Printer.Orientation] + #13#10 +
  21.       ' and paper size: ' + Printer.PaperSize.PaperName);
  22. end;
  23.  
  24. procedure TForm1.Button3Click(Sender: TObject);
  25. begin
  26.   //change paper orientation
  27.   if Printer.Orientation = poPortrait then
  28.     Printer.Orientation := poLandscape
  29.   else
  30.     Printer.Orientation := poPortrait;
  31. end;          
Title: Re: Printer Paper Orientation
Post by: J-G on August 14, 2022, 11:06:33 pm
!! @ paweld !!

On opening your reply I was at first somewhat taken aback

- just code without explanation ??

... but it didn't take me long to appreciate that it is a most succinct but fullsome reply providing all the answers I could want !

I'll have to do some testing and 'adjustment' but that's all the better since (hopefully) I'll learn so much more.

Many thanks.
Title: Re: Printer Paper Orientation
Post by: paweld on August 14, 2022, 11:17:37 pm
Hi @J-G,My written English is not very good, and often sample code with short comments will help you understand more than the description.
Title: Re: Printer Paper Orientation
Post by: J-G on August 15, 2022, 03:04:17 am
Hi @J-G,My written English is not very good, and often sample code with short comments will help you understand more than the description.

It's vastly superior to my Polish!!   :D

I haven't done much work on it yet, I've spent most of this evening working out how to show a 'Print Preview'  -  just showing the size of the final image within and A4 outline --  which I think I cracked about half-an-hour ago.  It can determine whether to use Portrait or View Orientation so will be used when I come to code the actual Print routine.

Title: Re: Printer Paper Orientation
Post by: paweld on August 15, 2022, 09:12:33 am
Instead of writing print and preview support from scratch, you can use ready-made components, such as fpReport. Sample in attachement.
Title: Re: Printer Paper Orientation
Post by: J-G on August 15, 2022, 08:28:17 pm
Instead of writing print and preview support from scratch, you can use ready-made components, such as fpReport. Sample in attachement.
Hmmm...  I don't think so.

When I selected a 180k .png file it took over a minute (I'm guessing :) ) to show a blank 'preview' --- the 'image' appeared a little while later but 'draging' the preview about the screen was equally lethargic and even stopped all other mouse activity.

My 'preview' only needs to show the area that the final image will take up and it has to be 'dynamic' - ie. changing with each minor modification to the data.

The attached ScreenGrab shows two results - one Portrait the other View -  I've added the yellow box after taking the grab to indicate the part of the display that will actually be sent to the printer. The preview is just a TMemo on a TPanel but I may change that and draw a box on the panel since I don't see a way to add a border to the TMemo. In real life the memo outline can be seen but it's rather weak.

I suspect that trying to understand fpReport would take me vastly longer than writing the Print Code from scratch -- and of course I'll understand my own code  ::)
Title: Re: Printer Paper Orientation
Post by: J-G on August 16, 2022, 06:17:06 pm
I'm somewhat further forward, having three operational buttons to [Print], [Page Setup] & [Select Printer] but there is still an action which is eluding me.

I'm using the code :
Code: Pascal  [Select][+][-]
  1. procedure TForm1.PrintImgClick(Sender: TObject);
  2.   procedure PrintDescription;
  3.   begin
  4.     PrintCentrePage(10,Desc,1,16,1);
  5.   end;
  6.  
  7.   procedure PrintTooth;
  8.   begin
  9.  
  10.   end;
  11.  
  12. begin
  13.   with Printer do
  14.    try
  15.      BeginDoc;
  16.      if P_Orient = 'P' then
  17.        Orientation := poPortrait
  18.      else
  19.        Orientation := poLandscape;
  20.  
  21.      PrintDescription;
  22. //     PrintTooth;
  23.    finally
  24.      EndDoc;
  25.    end;
  26. end;
to create the print   -  I haven't yet coded 'Print Tooth' as you can see, I'm just testing that the 'Description' prints at top centre which it does IF the Page Setup is in the correct orientation. That is lines 15 to 19 have no effect.

Using that same code in the [Page Setup] proc  - - - -
Code: Pascal  [Select][+][-]
  1. procedure TForm1.SetupClick(Sender: TObject);
  2. begin
  3.   if P_Orient = 'P' then
  4.     Printer.Orientation := poPortrait
  5.   else
  6.     Printer.Orientation := poLandscape;
  7.  
  8.   PageSetup.Execute;
  9. end;

... correctly sets the orientation but only if I use that button each time. I would have expected that to be sufficient to make the approriate change in Code.  It seems wrong to need to insert 'PageSetup.Execute;' at Line 20 which would open the Dialogue every time.

It's useful to have the option to change the page size etc. using the [Page Setup] but it surely shouldn't be necessary to enter that dialogue explicitly when there is the facility to set 'Orientation' via code.

I've tested [Select Printer]  - ie. I can change the printer in use -- and that works   -  as long as the orientation has been set with similar code in the [Select Printer] Proc.

I must be missing a 'magiic bullet' of some kind but can't see what or where yet  :(





Title: Re: Printer Paper Orientation
Post by: paweld on August 16, 2022, 10:19:10 pm
Perhaps the attached example will help you.
Title: Re: Printer Paper Orientation
Post by: J-G on August 17, 2022, 02:54:28 am
Perhaps the attached example will help you.
Thanks for your efforts @paweld. That's certainly an interesting program but I don't think it addresses my problem.

I work out whether the orientation needs to be Portrait or Landscape according to the height & width of the gear tooth  -  the object to be plotted  -  without overtly selecting the orientaion by use of a [button].

It seems reasonable (to me) that using the Printer.Orientaion := poXXXXXX  should do just that and I can't see what I need to do to make that so.

Working on a bitmap and selecting any part thereof is one thing but you still set the orientation by use of the RadioButtons.  If you determined the orientation according to the shape selected  that is; if the selection is taller than it is wide then the orientation should be set to poPortrait but if the selection is wider than it is tall then the orientation should be poLandscape -  if you could then set it without recourse to the RadioButtons you would be much closer to my problem.

Title: Re: Printer Paper Orientation
Post by: paweld on August 17, 2022, 07:03:30 am
Before generating a preview / printout, you need to check the ratio of the width of the image (selected area) to its height - if the width is greater than the height then you set the horizontal orientation, otherwise vertical.
Modified version attached.
Title: Re: Printer Paper Orientation
Post by: J-G on August 17, 2022, 08:49:33 am
Before generating a preview / printout, you need to check the ratio of the width of the image (selected area) to its height - if the width is greater than the height then you set the horizontal orientation, otherwise vertical.
Modified version attached.
Sorry @paweld, we still have a misunderstanding.  What I need is a reason why the orientation isn't changed without ME setting the orientation.

You say "then you set the horizontal orientation"  (my emphasis),  I nead a means by which the orientation is set without recourse to a secondary component ([TButton],[Radio Button]...). I can already manually set the orientation by invoking the [Page Setup] button and it is correctly set using the If...Then...Else construct but that doesn't do the job without calling the dialogue.

 
Title: Re: Printer Paper Orientation
Post by: paweld on August 17, 2022, 09:51:00 am
@J-G: If "Auto" is selected in RagioGroup then the program, based on the size of the image, checks what the page setting should be, and this function does it:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.SetAutoPageOrientation;
  2. var
  3.   whscale: Double;
  4. begin
  5.   if (Image1.Picture.Width = 0) or (Image1.Picture.Height = 0) then
  6.   begin
  7.     Printer.Orientation := poPortrait;
  8.     exit;
  9.   end;
  10.   if RadioGroup1.ItemIndex = 0 then   //if cheched auto page orientation
  11.   begin
  12.     if (FSelection.Width = 0) or (FSelection.Height = 0) then  //FSelection - is TRect with selection area
  13.       whscale := Image1.Picture.Width / Image1.Picture.Height
  14.     else
  15.       whscale := abs(FSelection.Width) / abs(FSelection.Height);
  16.     if whscale > 1 then
  17.       Printer.Orientation := poLandscape
  18.     else
  19.       Printer.Orientation := poPortrait;
  20.   end;
  21. end;              
Title: Re: Printer Paper Orientation
Post by: J-G on August 17, 2022, 11:05:53 am
Thanks for your continued patience @paweld but I don't have (and don't want) a [RadioGroup] so can't set that to 'Auto'.

I've done some more testing and find another 'issue' - though whether this has any bearing on the problem is debateable -  I have a .PDF printer set as the 'Default' and create the filename in a string called F_Name - works as expected and is set to Printer .Title thus :
Code: Pascal  [Select][+][-]
  1.  
  2. [...]
  3. with Printer do
  4.    try
  5.      BeginDoc;
  6.      Title := F_Name+'.PDF';
  7.      if P_Orient = 'P' then
  8.        Orientation := poPortrait
  9.      else
  10.        Orientation := poLandscape;
  11. [...]
  12.  
However the first time I click [Print] the filename is blank. If I [Cancel] the print and immediately click  [Print] again, the filename is shown ????

Further, if I change a parameter - which creates a new F_Name - the filename shown in the [Print] dialogue is the previous one !!! 

Stepping through the code, I can confirm that 'Printer.Title' is correctly set to F_Name at line 6 of the code snippet above and that 'Printer.Orientation' is also correctly selected in the If...Then...Else section.

Title: Re: Printer Paper Orientation
Post by: paweld on August 17, 2022, 12:15:03 pm
Attached to the previous post are the modified sources from which I removed the RadioGroup control.

In Printer.Title you specify the name of the report, not the name of the target PDF file.
Look in the attached example, in my case the report title is passed to the PDF printer every time.
Title: Re: Printer Paper Orientation
Post by: J-G on August 17, 2022, 03:32:21 pm
Attached to the previous post are the modified sources from which I removed the RadioGroup control.
Ah... apologies  -  I saw the reference to RadioGroup and made incorrect assumptions  :-[
Quote from: paweld
In Printer.Title you specify the name of the report, not the name of the target PDF file.
Look in the attached example, in my case the report title is passed to the PDF printer every time.
That is exactly what I'm doing  -  ???

Your latest code works exactly as I wish and I can follow the logic which is exactly the same as mine - albeit more robust and handling bitmaps -  I've now written a small project (,ZIP Attached) which only deals with the creation of a box which can be modified and the orientation evaluated from the size created.  The size is adjusted dynamically using two TTrack Components. I haven't included tests to limit the dimensions other than they can both be between 1 & 297.

This still leaves the Printer.orientation and the filename untouched so shows exactly what I'm not getting.

It doesn't have 'SetAutoPageOrientation' and I can't see anything in your Code/Form which allows me to create such an [Event]  -  I can see that it is in the 'Public' section but I can't see it in the [Events] of any of your components. I have no idea how you created it so I can't (as yet) add it into my code for testing.
Title: Re: Printer Paper Orientation
Post by: paweld on August 17, 2022, 05:23:06 pm
'SetAutoPageOrientation' procedure is called each time the preview generate
Title: Re: Printer Paper Orientation
Post by: J-G on August 17, 2022, 05:48:46 pm
'SetAutoPageOrientation' procedure is called each time the preview generate
I can see that  -  what I can't see is how the procedure/event is created.

It's surely not simply 'typed' in?

Hmmm....  it is !!       since the Proc started 'TForm1.',   I had assumed that it was created by clicking on the [...] of an [Event] but I've just typed it into my test project and added the If...Then...Else structure - - - - which was already being called at each [Print]  - - - -  the project compiled without problem but it's had no effect on the problem so that isn't the solution.

Have you seen the result provided by my test project?  Do you get the same result?  ie. no filename at first run and orientation not being set.





Title: Re: Printer Paper Orientation
Post by: paweld on August 17, 2022, 07:53:28 pm
Move the print name and page orientation setting before calling BeginDoc;, and it will work, ie
Code: Pascal  [Select][+][-]
  1. procedure TForm1.PrintImgClick(Sender: TObject);
  2. Var
  3.   W : word;
  4. begin
  5.   with Printer do
  6.    try                      
  7.      Title := F_Name+'.PDF';
  8.      if P_Orient = 'P' then
  9.        Orientation := poPortrait
  10.      else
  11.        Orientation := poLandscape;
  12.      BeginDoc;
  13.      with Canvas.Font do  
  14.   ...
instead of
Code: Pascal  [Select][+][-]
  1. procedure TForm1.PrintImgClick(Sender: TObject);
  2. Var
  3.   W : word;
  4. begin
  5.   with Printer do
  6.    try
  7.      BeginDoc;
  8.      Title := F_Name+'.PDF';
  9.      if P_Orient = 'P' then
  10.        Orientation := poPortrait
  11.      else
  12.        Orientation := poLandscape;
  13.      with Canvas.Font do
  14.   ...
Title: Re: Printer Paper Orientation
Post by: J-G on August 17, 2022, 08:23:50 pm
Move the print name and page orientation setting before calling BeginDoc;, and it will work,

D'oh!   --   I said that I must be missing a 'Magic Bullet'  !!

That's a day of both our lives that we won't get back  :D

However I have certainly learned quite a bit, and it may be that someone doing a search on this forum in the future may stumble across this answer which might save them some head-scratching.

Thanks for your efforts and tremendous patience in the face of my inability to really see how your Code differed from mine. I have spent the past hour going through not only your code line by line but even the settings of some of the components in the vain hope that I might see some difference.

TinyPortal © 2005-2018