Quick/Dirty Print

Printer Selection

Printing Text

Print Preview

Printing Graphics

WPF Tutorial Contents

APL  Home Page

Quick/Dirty Print

No selection; just throwing a text vector (with embedded newlines) to the default printer...

 ∇ KwikPrint w;⎕IO;⎕ML;pd;doc;dps;⎕USING;items
    ⍝ Quick/dirty print of character matrix to default printer
      ⎕IO ⎕ML←0 3
      w←∊w,⎕UCS 13
      pd←⎕NEW PrintDialog
      doc←⎕NEW FlowDocument(⎕NEW Paragraph(⎕NEW Run(⊂w)))
      dps←IDocumentPaginatorSource ⎕CLASS doc
      pd.PrintDocument(dps.DocumentPaginator'Printing Something')

Printer Selection

As usual, Microsoft impresses by adding confusion.  There are two classes called <PrintDialog> in .NET, the one we want for WPF-based applications is in System.Windows.Controls.  For the nonce, lets show a printer selection dialogue and return the selected printer name...

∇ z←PrinterSelect w;⎕IO;⎕ML;⎕USING;pdg
  ⍝ Printer selection
    ⎕IO ⎕ML ⎕USING←0 3 #.WPF.Using
    pdg←⎕NEW PrintDialog

Notice here that there's always a Name property, even if the user decides to cancel.

It is, of course, not a good idea to actually use this stand-alone function - put the code inline (as shown below).

Printing Text

Becoming a little more ambitious, we now want to allow our application to specify the font and our user to be able to select the printer...

  a DogPrint w;⎕IO;⎕ML;pd;doc;dps;⎕USING;font;jobname;select
⍝ Tester for text/figure printing
⍝ Example ←→ 'percy' 1 DogPrint PrintSample
 ⎕IO ⎕ML←0 3
 ⎕USING←#.UTIL.PRINT.PrintUsing ⍬
 jobname select←a
 pd←⎕NEW PrintDialog
 :If select
     :If ~rc
 doc←pd DogPrintFlowDoc w
 dps←IDocumentPaginatorSource ⎕CLASS doc
 pd.PrintDocument(dps.DocumentPaginator jobname)

In use...

  'percy' 1 DogPrint   ('Text' ('Constantia' 10) (10⍴'a')) ('Text' ('Felix Titling' 20) (10⍴'b')) ('Text' ('Impact' 8)(10⍴'c'))


∇ flowDoc←pd PrintFlowDoc docs;⎕IO;⎕ML;ff;pd;font;doc;run;para;ic;source;image;bi
    ⍝ Create FlowDocument for printing
      ⎕IO ⎕ML←0 3
      flowDoc←⎕NEW FlowDocument ⍬
      flowDoc.PagePadding←⎕NEW Thickness 50
      :For doc :In docs
          :Select ↑doc
          :Case 'Text'
              run←⎕NEW Run(2⌷doc)
              para←⎕NEW Paragraph run
              ff←⎕NEW FontFamily(⊂1 0⊃doc)
              para.FontSize←1 1⊃doc
          :Case 'Image'
              para←⎕NEW Paragraph ⍬
              para.fig←para.⎕NEW Figure ⍬
              para.fig.blockcontainer←para.fig.⎕NEW BlockUIContainer ⍬
              para.fig.blockcontainer.image←para.fig.blockcontainer.⎕NEW Image ⍬
              ic←⎕NEW ImageSourceConverter''
          flowDoc.Blocks.Add para

Watch this space for further enlightenment/enhancement...

Print Preview

Here's an adaptation of a function from Pierre Gilbert which illustrates a slightly different (more complex) approach to building the printed document.  It may be that this is what's really necessary.

What we're aiming for here is a series of paragraphs with font specified for each.

    ∇ PrintPreview docs;flowDoc;docViewer;flowDocPaginator;package;packageUri;packageUriString;printDLG;sink;wDV;xpsDoc;xpsSm;xpsStream;⎕USING;⎕IO;⎕ML;ff;pd
⍝ Adaptation of Pierre Gilbert's <PrintPreview> to handle multiple documents and maybe graphic images
      ⎕IO ⎕ML←0 3
      ⎕USING←PrintUsing ⍬
      pd←⎕NEW PrintDialog
      flowDoc←pd PrintFlowDoc docs
      flowDocPaginator←(IDocumentPaginatorSource ⎕CLASS flowDoc).DocumentPaginator    
      xpsStream←⎕NEW MemoryStream
      packageUri←⎕NEW Uri(⊂packageUriString)
      xpsDoc←⎕NEW XpsDocument(package,(CompressionOption.SuperFast),⊂packageUriString) 
      xpsSm←⎕NEW XpsSerializationManager((⎕NEW XpsPackagingPolicy(xpsDoc)),0)
      xpsSm.SaveAsXaml flowDocPaginator
      docViewer←⎕NEW DocumentViewer  
      wDV←⎕NEW Window 
      wDV.Title←'Print Preview'

And, in use...

  #.UTIL.PRINT.PrintPreview ('Text' ('Tahoma' 12) 'aaaa') ('Text' ('Verdana' 16) 'bbb')

Printing Graphics

PrintVisual is the first (easy, but limited) thing you need to know about; there's a usefully simple page here showing some nerd-language examples.

What makes PrintVisual both easy and limited is that it prints precisely what you send it; there's no pagination, no scrolling - just what you see is what you print.  More ambitious requirements - you'll need to start exploring PrintDocument options.

For a simple example of using this from APL here are some snippets from an APLet which superimposes some lines onto a map image, and has some further text annotation.

I keep separate (updated in parallel) windows for the screen (which the user interacts with) and printing (which stays invisible, just getting populated with what's for printing.

The XAML for the print window is...

<?xml version="1.0" encoding="utf-8"?>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="wdwDogPrint">
  <ScrollViewer Name="svMap" VerticalScrollBarVisibility="Hidden" Height="800" Width="700">
        <Image Name="imgMap" />
        <Canvas Name="cvsTrack" />
      <TextBox Name="txtFileName" />
      <TextBox Name="txtCatalogue" />
      <TextBox Name="txtDate" />
      <TextBox Name="txtMap" />

Notice how both the Image and the Canvas are contained in the Grid with no row or column definitions - done like this anything drawn onto the Canvas is visually overlaid onto the Image.  Notice the jiggery-pokery in the ScrollViewer definition (making sure, in my pig-ignorant way, that sizes are appropriate for an A4 page and there's no chance of an unwanted ScrollBar showing up).

Populate in the usual way, here's a snippet...

:If #.UTIL.FILE.FileExists mapfile
     ic←⎕NEW ImageSourceConverter''
 wdw.txtFileName.Text←'File: ',file

What's important here is to force the size of the Image source.

Add this line where it suits you...

pd.PrintVisual(#.wdwDogPrint.svMap printname)

And, once you've done that - bingowingo, out pops the printing.