Printing using Win32lib.ew Functions

Since I haven't yet gotten around to changing the addressbook example to use the printing functions which are now a part of Win32lib, here's a little example that prints using these.

If you study the text and code in Extra02, you'll notice there aren't really that many differences.

Although the function names have changed slightly,
... you use:

getPrinter(), and
startDoc(), ... to get your ( printer ) document file started, then carry on ...

... with groups of:
startPage(),
endPage(), ... for each page, and then, finally:

endDoc(), and
releasePrinter(), ... to print a document.

A major difference is that getPrinter() calls a printer dialog box from which you can select a printer, and some of it's settings. Very nice !
My old version only used the Windows 'default' printer.

Instead of using 'my' pTextOut(), Win32lib uses setPenPos(), and wPuts(), to send text out to a printer page.

This example is a variation of pr123.exw, which shows how to 'wrap' a long text line to keep it on a page, and prints some simple graphics as well.

(... remember, that a printer page is basically a bitmap. If you send a long line to it, the excess will simply 'disappear' off the page's right margin unless you break up the line into smaller chunks first ! )

-- pr234.exw

    include win32lib.ew

      integer junk, linecount, charsPerLine, linesPerPage,
      halfx, halfy
      sequence  fontSize, printerSize, text, lineOfText

    constant
    PrWin = create(Window,"Another Win32lib 'print'",0,10,10,300,210,0),
    MenuP = create(Menu,"&Print",PrWin,0,0,0,0,0),
    PNow  = create(MenuItem,"&A demo page !",MenuP,0,0,0,0,0)

    -- a long text line
    text = "I have been working on this tutorial since October of 1998, " &
     "starting with Win32lib version 0.15c, " &
     "and even though David added some 'wrappers' to Win32lib.ew for " &
     "printing " &
     "quite some time ago, " &
     "( in version 0.43e, Oct./99 ), it has taken me this long to finally " &
     "get around to using *his* functions " &
     "in a tutorial example !"

    procedure get_info()
    -- open the printer dialog
    -- then, IF the user has selected a printer...
    if length(getPrinter()) > 0 then
      -- pick a big fixed width font
      setFont( Printer, "Courier New", 24, Normal )
      -- get the font metrics
      fontSize = getFontSize( Printer )
      -- get the size of a printer page
      printerSize = getCtlSize( Printer )
      -- how many characters can fit on a line?
      charsPerLine = floor(printerSize[1]/fontSize[1])
      -- how many lines can fit on a page?
      linesPerPage = floor(printerSize[2]/fontSize[2])

    -- report all the printer's 'metrics'
    setPenPos(PrWin,10,10)
    wPuts(PrWin,"...using the \"Courier New\", size 24 font.")
    setPenPos(PrWin,10,30)
    wPuts(PrWin,"character width = " & sprintf("%d",fontSize[1]))
    setPenPos(PrWin,10,50)
    wPuts(PrWin,"character height = " & sprintf("%d",fontSize[2]))
    setPenPos(PrWin,10,70)
    wPuts(PrWin,"characters per line = " & sprintf("%d",charsPerLine))
    setPenPos(PrWin,10,90)
    wPuts(PrWin,"lines per page = " & sprintf("%d",linesPerPage))
    setPenPos(PrWin,10,120)
    wPuts(PrWin,"page 'pixel' width = " & sprintf("%d",printerSize[1]))
    setPenPos(PrWin,10,140)
    wPuts(PrWin,"page 'pixel' height = " & sprintf("%d",printerSize[2]))

    end if

    end procedure

    procedure print_now()
    get_info()
    -- start up the document
    if startDoc( "My Print Job" ) then
      junk = startPage()
      -- set to top of page
      linecount = 0
      -- print until long text line is empty
      while length( text ) do
      -- get a line of text
        if length( text ) < charsPerLine then
            -- get remaining text
            lineOfText = text
            text = ""
        else
            -- get one 'printer line' of text
            lineOfText = text[1..charsPerLine]
            -- remove from remaining text
            text = text[charsPerLine+1..length(text)]

            -- is first character of line a space ?
            if equal(lineOfText[1], ' ') then
              lineOfText = lineOfText[2..length(lineOfText)]
              if length(text) > 0 then
                lineOfText = lineOfText & text[1]
              end if
              if length(text) > 1 then
                text = text[2..length(text)]
              end if
            end if

        end if
        -- position text on page
        setPenPos( Printer, 0, linecount*fontSize[2] )
        -- write the text
        wPuts( Printer,lineOfText )
        -- move down one line
        linecount += 1
        -- at bottom of page?
        if linecount > linesPerPage then
          -- print page
          if not endPage() then
            exit
          end if
          -- start a new page
          if not startPage() then
            exit
          end if
         -- reset counter
          linecount = 0
        end if
      end while

    -- shucks, we know we haven't printed a full page yet...
    -- so let's throw in some graphics, OK ?

    -- draw a fat line half-way down the page.
    halfy = floor(printerSize[2] / 2)
    setPenWidth(Printer,5)
    drawLine(Printer,0,halfy,printerSize[1],halfy)

    -- draw a fat line at the bottom of the page.
    setPenWidth(Printer,5)
    drawLine(Printer,0,printerSize[2]-5,printerSize[1],printerSize[2]-10)

    -- then draw a circle of size 50, at 20 by 20 below the top line.
    setPenWidth( Printer,1 )
    drawEllipse( Printer, True,  -- fill the circle
                 20, halfy + 25,  -- start x,y
                 20 + 50, halfy + 25 + 50 )  -- end x,y

    -- then add a line of smaller text after the circle.
    setFont( Printer, "Courier New", 16, Bold )
    setPenPos( Printer, 100, halfy + 25 )
    wPuts( Printer, "This makes a BIG point !" )

    -- then add a big empty circle with a '400' diameter.
    halfx = floor(printerSize[1] / 2)
    setPenWidth( Printer, 4 )
    drawEllipse( Printer, False,  -- don't fill the circle.
                 halfx - 200, halfy + 100,  -- start x,y
                 halfx + 200, halfy + 100 + 400 )  -- end x,y

    -- with a check-mark near the center.
    setPenWidth( Printer, 8 )
    drawLine( Printer, halfx-50, halfy+300,
                       halfx, halfy+405 )
    setPenWidth( Printer, 12 )
    drawArc( Printer, False,
             halfx, halfy+405-600,
             halfx+600, halfy+405+600,
             halfx+200, halfy-100,
             halfx, halfy+400)

    -- then, finally, send the page to the printer
    junk=endPage()
    -- ending our 'shucks' graphics demonstration.

    end if

    -- end the document, and,
    if endDoc() then
      -- release the printer.
      releasePrinter()
    end if
    end procedure

    --------

    onClick[PNow] = routine_id("print_now")

    WinMain(PrWin, Normal)

    -- end code --

If you study the code, you'll notice that you can send data to the page in any order using setPenPos(). The page is not 'complete' until you send an endPage() command.

The simple 'line-wrap' code formats a line according to the printer's width. This code was originally by David Cuny, as an answer to a mailing list question. It really only works correctly if you are printing fixed-width fonts.

I've just added the bit which tries to remove any space characters from line beginnings, and 'steals' a character from the long line, to maximize the printed line's length.

... anyone who's feeling particularly brave, can try to modify the addressbook examples to use 'just' Win32lib printing functions.

... with knowledge comes success, and with success, comes knowledge...

( or, in programming, ya gotta try things to learn'em ;) )

..end of lesson.

CONTENTS