• Welcome to PlanetSquires Forums.
 

Print Preview Class (CPrintPreview)

Started by Paul Squires, March 06, 2023, 08:22:10 PM

Previous topic - Next topic

Paul Squires

Hi Everyone,

After a few emails between myself and Peter (Petrus Vorster), I am revisiting an older class, CPrintPreview, that I started coding a couple of years ago. I hope that this class will fill a gap in the WinFBE and FreeBasic ecosystem.

This print preview class is similar to controls like IDEAL Software's Virtual Print Engine (VPE), or Don Dickinson's ddoc for PowerBasic.

VPE is a great control but it is VERY expensive. The free Community Edition has way too many limitations and is not high-DPI aware.

This CPrintPreview class is designed so that it creates the print preview canvas (via a sequence of EnhancedMetaFiles). You take this canvas and either print it directly to the printer, or embed it into a dialog as a child control. This allows you to create your own Print Preview dialog rather than being forced into a pre-designed dialog that may not fit your needs.

I have an early prototype already working so I hope to add a lot of meat to it over the coming week.

I will post it to GitHub when it's ready so that everyone can test it and provide feedback. Currently, it only prints text but eventually I want it to allow embedding of images and barcodes.

Here is what the syntax looks like so far. You can create pages in any order and even jump between them to do modifications. You are not forced to create the pages in a sequential order. Pages are zero based so the first page is 0. Currently, it uses Inches but I will also add ability to specify Centimeters as an alternative.

I am making this post to motivate myself to continue coding and finish the project because I have now announced it  ;D   

If any of you would like to make suggestions at this point then please do so. A lot can change before the final code is completed.

   ' Create the new document
   dim pCanvas as CPrintPreview ptr = new CPrintPreview

   ' Add 4 different fonts to the Canvas that we can use. These fonts are
   ' automatically released when the Canvas is destroyed (to avoid GDI leaks).
   dim as HFONT hFont(3)
   hFont(0) = pCanvas->AddFont( "Arial", 10 )
   hFont(1) = pCanvas->AddFont( "Arial", 10, true )
   hFont(2) = pCanvas->AddFont( "Courier New", 12 )
   hFont(3) = pCanvas->AddFont( "Courier New", 12, true, true )
   
   dim as CWSTR wszText
   dim as single nTop
   
   ' Page #0
   pCanvas->ModifyPage(0)
   nTop = 1   ' start at 1 inch from the top of the page
   for i as long = 1 to 30
      ' Every second line will be bold
      if (i mod 2) = 0 then
         pCanvas->UseFont(hFont(1))
      else   
         pCanvas->UseFont(hFont(0))
      end if
      wszText = "This is my Arial font test string! " & i & " on Page ZERO"
      nTop = pCanvas->WriteText( 1, nTop, 3, nTop + 0.25, wszText )
   next

   ' Page #1
   pCanvas->ModifyPage(1)
   nTop = 1   ' start at 1 inch from the top of the page
   for i as long = 1 to 30
      ' Every second line will be bold & underline
      if (i mod 2) = 0 then
         pCanvas->UseFont(hFont(3))
      else   
         pCanvas->UseFont(hFont(2))
      end if
      wszText = "This is my Courier New test string! " & i & " on Page ONE"
      nTop = pCanvas->WriteText( 1, nTop, 3, nTop + 0.25, wszText )
   next
   
   function = pCanvas

Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

philbar

Hi Paul,

This looks terrific! It will save me a lot of going back and forth to my (disorganized) notes.

I'll be looking for ways to add line art to the page, either directly or using CGpGraphics to create an image and then embedding that.

Phil

Petrus Vorster

Wow, you already made quite a move after those emails!

Phil also identified line drawings since many printing needs exists around billing and report printing.
Line art like rounded corners rectangles etc.

I am grateful that you are always up for a challenge!

Regards,

Peter
-Regards
Peter

Paul Squires

Oh yes, there will be lines, boxes, colors, etc. All the basic primitives that you'd expect.
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Paul Squires

Got the visual aspect of print preview working perfectly. It uses double buffering and shows no flicker when resizing or moving between pages. Happy with the progress so far.

Here is a screenshot showing what the demo code from my original post looks like when it is displayed. Excuse the primitive container that the print canvas is embedded within. It is just a few controls that I put together for demo purposes to be able to navigate between pages and test zoom factors. Your print preview dialog can be as elaborate as you dream.... or, use no print dialog at all if you wish.



Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Bumblebee

#5
If only there were code that could rejuvenate dried out ink cartridges. ;)
Failed pollinator.

Paul Squires

Boxes/Rectangles are done. You can draw filled or empty rectangles, with or without rounded corners.

I will add "lines" today and then the class should be ready for some basic beta testing.

I may even get time to adding images prior to the first beta. We'll see.
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Petrus Vorster

I am very excited.
Knowing your work, I know it will be great.

-Peter
-Regards
Peter

Paul Squires

#8
In order to test the functionality of the CPrintPreview class, I found a sample invoice template on the web and duplicated it with the class code.

Here is what the invoice looks like when previewed:



Here is the code used to create that invoice. I may tweak the different functions used or add additional convenience functions so that the user does not have to write out lengthy function calls. Granted, once you've created your print preview template, it becomes easy to populate it.

I used Centimeters to create the page because it was easier (for me) to work with rather than inches.

function CreatePrintPreviewCanvas() as CPrintPreview ptr
   
   ' Create the new Invoice document
   dim pCanvas as CPrintPreview ptr = new CPrintPreview

   ' Add different fonts to the Canvas that we can use. These fonts are
   ' automatically released when the Canvas is destroyed (to avoid GDI leaks).
   dim as HFONT hFont(5)
   hFont(0) = pCanvas->AddFont( "Arial", 9, true )       ' Invoice/Date headings
   hFont(1) = pCanvas->AddFont( "Arial", 10 )            ' Regular line items
   hFont(2) = pCanvas->AddFont( "Arial", 11, , true )    ' Thank you for your business!
   hFont(3) = pCanvas->AddFont( "Arial", 12, true )      ' Total amount
   hFont(4) = pCanvas->AddFont( "Arial", 16 )            ' [COMPANY NAME]
   hFont(5) = pCanvas->AddFont( "Arial", 28, true )      ' INVOICE (gray color)
   
   ' Create a solid pen of width 2. Black color is used if no color is specified.
   dim as HPEN hPen = pCanvas->AddSolidPen( 2 ) 
   ' Create an invisible pen used for writing text to boxes with no border.
   dim as HPEN hPenInvisible = pCanvas->AddInvisiblePen() 
   
   ' Define gray color for solid boxes
   dim as COLORREF clrLtGray = BGR(219,219,219)
   dim as COLORREF clrDkGray = BGR(148,148,148)
   
   ' Need to set the measurement units before creating objects if
   ' you decide to use centimeters because inches is the default.
   pCanvas->MeasurementUnits = 1   ' 0:Inches, 1:Centimeters
   
   pCanvas->Orientation = DMORIENT_PORTRAIT
   pCanvas->PaperWidth = 21.59     ' cm  (8.5 inches)
   pCanvas->PaperHeight = 27.94    ' cm  (11 inches)

   ' Page #0
   pCanvas->ModifyPage(0)
   
   pCanvas->UseFont( hFont(4) )
   ' black text color and white background is used if not specified
   pCanvas->WriteText( 1.5, 1.5, "[Company Name]" )   
   
   pCanvas->UseFont( hFont(1) )
   pCanvas->WriteText( 1.5, 2.5, "[Street Address]" )
   pCanvas->WriteText( 1.5, 3.0, "[City, ST ZIP]" )
   pCanvas->WriteText( 1.5, 3.5, "Phone: (000) 000-0000" )

   pCanvas->UseFont( hFont(5) )
   pCanvas->WriteTextBox( 16.0, 1.5, 20.4, 2.5, "INVOICE", hPenInvisible, , DT_TOP or DT_RIGHT, clrDkGray )

   pCanvas->UseFont( hFont(0) )
   pCanvas->WriteTextBox( 12.5, 3.5, 16.6, 4.2, "INVOICE #", hPen, clrLtGray )
   pCanvas->WriteTextBox( 16.6, 3.5, 20.4, 4.2, "DATE", hPen, clrLtGray )
   pCanvas->UseFont( hFont(1) )
   pCanvas->WriteTextBox( 12.5, 4.2, 16.6, 4.9, "[123456]", hPen )
   pCanvas->WriteTextBox( 16.6, 4.2, 20.4, 4.9, "2023-03-14", hPen )

   pCanvas->UseFont( hFont(0) )
   pCanvas->DrawSolidRect( 1.5, 6.0, 9.5, 6.7, hPen, clrLtGray )
   pCanvas->WriteText( 1.8, 6.2, "BILL TO", , clrLtGray )
   pCanvas->UseFont( hFont(1) )
   pCanvas->WriteText( 1.5, 7.0, "[Name]" )
   pCanvas->WriteText( 1.5, 7.5, "[Company Name]")
   pCanvas->WriteText( 1.5, 8.0, "[Street Address]" )
   pCanvas->WriteText( 1.5, 8.5, "[City, ST ZIP]" )
   pCanvas->WriteText( 1.5, 9.0, "[Phone]" )
   pCanvas->WriteText( 1.5, 9.5, "[Email Address]" )

   pCanvas->UseFont( hFont(0) )
   pCanvas->DrawSolidRect( 1.5, 11.0, 16.6, 11.7, hPen, clrLtGray )
   pCanvas->WriteText( 1.8, 11.2, "DESCRIPTION", , clrLtGray )
   pCanvas->WriteTextBox( 16.6, 11.0, 20.4, 11.7, "AMOUNT", hPen, clrLtGray )
   pCanvas->DrawRect( 1.5, 11.7, 16.6, 21.0, hPen )
   pCanvas->DrawRect( 16.6, 11.7, 20.4, 21.0, hPen )

   pCanvas->UseFont( hFont(1) )
   pCanvas->WriteTextBox( 1.8, 12.0, 16.0, 12.5, "Service Fee", hPenInvisible, , DT_LEFT or DT_VCENTER )
   pCanvas->WriteTextBox( 1.8, 12.5, 16.0, 13.0, "Labor: 5 hours at $75/hr", hPenInvisible, , DT_LEFT or DT_VCENTER )
   pCanvas->WriteTextBox( 1.8, 13.0, 16.0, 13.5, "New client discount", hPenInvisible, , DT_LEFT or DT_VCENTER )
   pCanvas->WriteTextBox( 1.8, 13.5, 16.0, 14.0, "Tax (4.25% after discount)", hPenInvisible, , DT_LEFT or DT_VCENTER )

   pCanvas->WriteTextBox( 18.2, 12.0, 20.2, 12.5, "200.00", hPenInvisible, , DT_RIGHT or DT_VCENTER )
   pCanvas->WriteTextBox( 18.2, 12.5, 20.2, 13.0, "375.00", hPenInvisible, , DT_RIGHT or DT_VCENTER )
   pCanvas->WriteTextBox( 18.2, 13.0, 20.2, 13.5, "(50.00)", hPenInvisible, , DT_RIGHT or DT_VCENTER )
   pCanvas->WriteTextBox( 18.2, 13.5, 20.2, 14.0, "26.56", hPenInvisible, , DT_RIGHT or DT_VCENTER )

   pCanvas->UseFont( hFont(2) )
   pCanvas->WriteTextBox( 1.5, 21.0, 12.5, 22.0, "Thank you for your business!", hPen )

   pCanvas->UseFont( hFont(3) )
   pCanvas->DrawRect( 12.5, 21.0, 20.4, 22.0, hPen )
   pCanvas->WriteTextBox( 13.0, 21.2, 16.6, 21.8, "TOTAL", hPenInvisible, , DT_LEFT or DT_VCENTER )
   pCanvas->WriteTextBox( 16.8, 21.2, 18, 21.8, "$", hPenInvisible, , DT_LEFT or DT_VCENTER  )
   pCanvas->WriteTextBox( 18.2, 21.2, 20.2, 21.8, "551.56", hPenInvisible, , DT_RIGHT or DT_VCENTER )

   dim as CWSTR wszText
   pCanvas->UseFont( hFont(1) )
   wszText = "If you have any questions about this invoice, please contact"
   pCanvas->WriteTextBox( 1.5, 25.0, 20.4, 25.5, wszText, hPenInvisible )
   wszText = "[Name, Phone, email@address.com]"
   pCanvas->WriteTextBox( 1.5, 25.5, 20.4, 26.0, wszText, hPenInvisible )

   function = pCanvas
end function


Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

James Klutho


philbar

Oh, that invisible pen. Had to think about it for a minute.

Idle question: can font sizes be expressed in inches (cm)?

Paul Squires

Thanks gentlemen for the encouragement! Today is "documentation day", so hopefully I will have a tutorial/reference document produced today so that I can upload the class for you to try.

Quote from: philbar on March 15, 2023, 05:22:25 PMIdle question: can font sizes be expressed in inches (cm)?

Fonts are measured in a point sizes but you can easily convert to and from inch or cm. There is about 72 (72.272) points in one inch. So, a 12pt font would be (12 / 72.272) = 0.166 inches, which is (0.166 * 2.54) = 0.422 cm
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Paul Squires

I have forgotten how tedious and boring creating documentation is  ;D

No wonder there is so very little documentation for WinFBE itself. Hopefully I will finish documenting the CPrintPreview class functions by the end of today unless I fall asleep at my keyboard from boredom.
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer