Print framework in action

What follows is a code example to show you how the print framework works in practice. The example consists of a simple framework for printing text files, and an application that allows you to type a simple text file. Figure 17.2 displays the application.

Listing 17.1 displays both the print framework we've already discussed, as well as the dialog data mechanisms we'll get to shortly.

|rHE BROTHERS GRIMM FAIRY TALES

THE GOLDEN BIRD

A certain king had a beautiful garden, and in the garden stood a tree which bore golden apples. These apples were always counted, and about the time when they began to grow ripe it was found that every night one of them was gone. The king became very angry at this, and ordered the gardener to keep watch all night under the tree. The gardener set his eldest son to watch; but about twelve o'clock he fell asleep, and in the morning another of the apples was missing. Then the second son was ordered to watch; and at midnight he too fell asleep, and in the morning another apple was gone. Then the third son offered to keep watch; but the gardener at first would not let him, for fear some harm should come to him: however, at last he consented, and the young man laid himself under the tree to watch. As the clock struck twelve he heard a rustling noise in the air, and a bird came flying that was of pure gold; and as it was snapping at one of the apples with its beak, the gardener's son jumped up and shot an arrow at it. But the arrow did the bird no harm; only it dropped a golden feather from its tail,

Figure 17.2 The simple printing framework in action

Listing 17.1 A long example of a print framework in action import wx import os

FONTSIZE = 10

class TextDocPrintout(wx.Printout): <— Declaring the printout class def _init_(self, text, title, margins):

wx.Printout._init_(self, title)

self.lines = text.split('\n') self.margins = margins def HasPage(self, page): <-1 How many pages? return page <= self.numPages def GetPageInfo(self):

return (1, self.numPages, 1, self.numPages)

def CalculateScale(self, dc): <— Scaling the DC to screen size ppiPrinterX, ppiPrinterY = self.GetPPIPrinter() ppiScreenX, ppiScreenY = self.GetPPIScreen() logScale = float(ppiPrinterX)/float(ppiScreenX)

pw, ph = self.GetPageSizePixels() <i— Adjusting scale dw, dh = dc.GetSize()

scale = logScale * float(dw)/float(pw) dc.SetUserScale(scale, scale)

self.logUnitsMM = float(ppiPrinterX)/(logScale*25.4)

def CalculateLayout(self, dc):

topLeft, bottomRight = self.margins <— Determining margins dw, dh = dc.GetSize()

self.x1 = topLeft.x * self.logUnitsMM self.y1 = topLeft.y * self.logUnitsMM self.x2 = (dc.DeviceToLogicalXRel(dw) -bottomRight.x * self.logUnitsMM) self.y2 = (dc.DeviceToLogicalYRel(dh) - Putting a buffer bottomRight.y * self.logUnitsMM) around page self.pageHeight = self.y2 - self.y1 - 2*self.logUnitsMM <— font = wx.Font(FONTSIZE, wx.TELETYPE, wx.NORMAL, wx.NORMAL) dc.SetFont(font)

self.lineHeight = dc.GetCharHeight()

self.linesPerPage = int(self.pageHeight/self.lineHeight)

def OnPreparePrinting(self): <— Calculating page count dc = self.GetDC() self.CalculateScale(dc) self.CalculateLayout(dc)

self.numPages = len(self.lines) / self.linesPerPage if len(self.lines) % self.linesPerPage != 0: self.numPages += 1

def OnPrintPage(self, page): <— Printing a page dc = self.GetDC() self.CalculateScale(dc) self.CalculateLayout(dc)

dc.SetPen(wx.Pen("black", 0)) <-l Drawing an outline dc.SetBrush(wx.TRANSPARENT_BRUSH) r = wx.RectPP((self.x1, self.yl), (self.x2, self.y2)) dc.DrawRectangleRect(r) dc.SetClippingRect(r)

line = (page-1) * self.linesPerPage <1— Drawing text x = self.xl + self.logUnitsMM y = self.yl + self.logUnitsMM while line < (page * self.linesPerPage): dc.DrawText(self.lines[line], x, y) y += self.lineHeight line += 1

if line >= len(self.lines): break return True class PrintFrameworkSample(wx.Frame):

wx.Frame._init_(self, None, size=(640, 480), title="Print Framework Sample") self.CreateStatusBar()

self.tc = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_DONTWRAP) self.tc.SetFont(wx.Font(FONTSIZE, wx.TELETYPE, wx.NORMAL, wx.NORMAL))

filename = os.path.join(os.path.dirname(_file_), "sample-text.txt")

self.tc.SetValue(open(filename).read()) self.tc.Bind(wx.EVT_SET_FOCUS, self.OnClearSelection) wx.CallAfter(self.tc.SetInsertionPoint, 0)

item = menu.Append(-1, "Page Setup...\tF5",

"Set up page margins and etc.") self.Bind(wx.EVT_MENU, self.OnPageSetup, item) item = menu.Append(-1, "Print Setup...\tF6",

"Set up the printer options, etc.") self.Bind(wx.EVT_MENU, self.OnPrintSetup, item) item = menu.Append(-1, "Print Preview...\tF7",

"View the printout on-screen") self.Bind(wx.EVT_MENU, self.OnPrintPreview, item) item = menu.Append(-1, "Print...\tF8", "Print the document")

self.Bind(wx.EVT_MENU, self.OnPrint, item) menu.AppendSeparator()

item = menu.Append(-1, "E&xit", "Close this application") self.Bind(wx.EVT_MENU, self.OnExit, item)

menubar = wx.MenuBar() menubar.Append(menu, "&File") self.SetMenuBar(menubar)

self.pdata = wx.PrintData() <-J Initializing print data self.pdata.SetPaperId(wx.PAPER_LETTER) self.pdata.SetOrientation(wx.PORTRAIT) self.margins = (wx.Point(15,15), wx.Point(15,15))

def OnExit(self, evt): self.Close()

def OnClearSelection(self, evt): evt.Skip()

wx.CallAfter(self.tc.SetInsertionPoint, self.tc.GetInsertionPoint())

def OnPageSetup(self, evt):

data = wx.PageSetupDialogData() data.SetPrintData(self.pdata) data.SetDefaultMinMargins(True) data.SetMarginTopLeft(self.margins[0]) data.SetMarginBottomRight(self.margins[1]) dlg = wx.PageSetupDialog(self, data) <— if dlg.ShowModal() == wx.ID_OK: data = dlg.GetPageSetupData() self.pdata = wx.PrintData(data.GetPrintData()) self.pdata.SetPaperId(data.GetPaperId()) self.margins = (data.GetMarginTopLeft(), data.GetMarginBottomRight())

dlg.Destroy()

Getting page setup data def OnPrintSetup(self, evt):

data = wx.PrintDialogData(self.pdata)

dlg = wx.PrintDialog(self, data)

dlg.GetPrintDialogData().SetSetupDialog(True)

dlg.ShowModal();

data = dlg.GetPrintDialogData()

self.pdata = wx.PrintData(data.GetPrintData())

dlg.Destroy()

def OnPrintPreview(self, evt): <-J Starting print preview data = wx.PrintDialogData(self.pdata) text = self.tc.GetValue()

printoutl = TextDocPrintout(text, "title", self.margins) printout2 = TextDocPrintout(text, "title", self.margins)

preview = wx.PrintPreview(printout1, printout2, data) if not preview.Ok():

wx.MessageBox("Unable to create PrintPreview!", "Error")

else:

frame = wx.PreviewFrame(preview, self, "Print Preview", pos=self.GetPosition(), size=self.GetSize())

frame.Initialize() frame.Show()

def OnPrint(self, evt): <1—1 Starting Print data = wx.PrintDialogData(self.pdata) printer = wx.Printer(data) text = self.tc.GetValue()

printout = TextDocPrintout(text, "title", self.margins) useSetupDialog = True if not printer.Print(self, printout, useSetupDialog) \ and printer.GetLastError() == wx.PRINTER_ERROR: wx.MessageBox(

"There was a problem printing.\n"

"Perhaps your current printer is not set correctly?", "Printing Error", wx.OK)

else:

data = printer.GetPrintDialogData()

self.pdata = wx.PrintData(data.GetPrintData()) # force a copy printout.Destroy()

app = wx.PySimpleApp()

frm = PrintFrameworkSample()

frm.Show()

app.MainLoop()

The printout class presented in listing 17.2 is able to print simple text documents, but doesn't handle page numbers or titles, and it assumes that no lines are longer than will fit within the page width. Those features are left as an exercise for the reader.

The most important code snippets are in the OnPreparePrinting() and OnPrintPage() methods of the framework and the OnPrint() method of the sample window. Notice how the draw commands in the OnPrintPage() are the same as if you were drawing to the screen.

Was this article helpful?

0 -1

Post a comment