# 第十七章 wxPython的打印構架
本章內容
* 用`wxPython`打印
* 創建和顯示打印對話框
* 創建和顯示頁面設置對話框
* 在你的程序中執行打印
* 執行一個打印預覽
在第16章中,我們已經關注了`wxPython`的一打印方法:使用`wx.HtmlEasyPrinting`。如果你用該方法打印`HTML`(或某些容易轉換為`HTML`的文件)的話,這個方法將會工作的很好,但是要作為一個完善打印辦法還是不夠的。在`wxPython`中還有一個更為通用的打印構架,你可以用它來打印你想打印的任何東西。基本上,該構架使你能夠使用設備上下文和繪制操作來執行打印。你也可以創建打印預覽。
本章將討論該構架中最重要的類:`wx.Printout`,它管理實際的圖片部分。打印輸出實例可以由一個代表打印機的`wx.Printer`對象或用于打印預覽的`wx.PrintPreview`對象來管理。多們也將討論幾個管理與打印相關的數據的類,以及用來顯示信息給用戶的對話框。
## 如何用wxPython打印?
我們將以類`wx.Printout`作為開始。首先你要創建你自定義的`wx.Printout`的子類。接著你要覆蓋`wx.Printout`的方法以定義你自定義的打印行為。`wx.Printout`有7個你可以覆蓋以自定義打印行為的方法。這些方法在一個打印會話過程期間被`wxPython`自動調用。圖17.1其中的六個方法,它們被特定的事件觸發。在大多數情況下,你不需要全部覆蓋它們。
**圖17.1**

### 理解打印輸出的生命周期
你通過創建一個你的打印輸出對象的實例和一個類`wx.Printer`的實例啟動一個打印會話:
```
wx.Printer(data=None)
```
可選的`data`參數是`wx.PrintDialogData`的一個實例。要開始實際的打印,需要調用`wx.Printer`的`Print(parent,?printout,?prompt=True)`方法。參數`parent`是父窗口(它被用作對話框的窗口中)。參數`printout`是你的`wx.Printout`實例。如果參數`prompt`為`True`,那么在打印之前,`wxPython`將顯示打印對話框,否則不顯示。
在`Print()`方法開始后,它調用`wx.Printout`的第一個可被覆蓋的方法`OnPreparePrint()`。`OnPreparePrint()`方法在`wx.Printout`實例做任何其它的事之前被確保調用,因此該方法是放置收集你的數據或做那些必須在打印開始之前所要做的計算的一個好的地方。實際的打印使用`OnBeginPrinting()`方法開始,你可以對該方法進行覆蓋,以自定主你想要的行為——默認情況下,該方法什么也不做。`OnBeginPrinting()`在整個打印會話中只會被調用一次。
你希望打印的文檔的每個單獨的拷貝觸發對`OnBeginDocument(startPage,?endPage)`的一個調用,其中參數`startPage,?endPage`告訴`wxPython`打印的起始頁和最后一頁。這兩個參數都應該指定。如果你想覆蓋這個方法,那么你必須調用它的基類的方法,因為基類的方法要做一些重要的工作(如調用`wx.DC.StartDoc()`)。在`wxPython`中,你可以使用`base_OnBeginDocument(startPage,?endPage)`來調用其父類的方法。如果`OnBeginDocument`返回`False`,那么將取消打印工作。
你最有可能去覆蓋的方法是`OnPrintPage(pageNum)`,該方法是你放置關于每一頁的繪制命令的地方。參數`pageNum`是要打印的頁的頁碼。在這個方法中,你調用`GetDC()`,`GetDC()`根據你當前的系統平臺返回一個適當的設備上下文。對于實際的打印,如果你是在一個微軟的`Windows`系統上的話,那么`GetDC()`返回的是類`wx.PrinterDC`的實例。對于其它的系統,返回的是類`wx.PostScriptDC`的實例。如果你是處在一個打印預覽操作中,那么對于任何的操作系統,`GetDC()`返回的都是一個`wx.MemoryDC`。一旦你有了設備上下文,你就可以做你想做的設備上下文繪制操作,并且它們將被打印或預覽。
在一個文檔的副本打印結束后,一個`OnEndDocument()`調用被觸發。另外,如果你要覆蓋`OnEndDocument()`方法,那么你必須調用其基類的方法`base_OnEndDocument()`。`base_OnEndDocument()`將調用`wx.DC.EndDoc()`方法。當你的所有的副本被打印完后,`OnEndPrinting()`方法被調用,這樣就結束了打印會話。
`wx.Printout`還有另一個可被覆蓋的方法:`HasPage(pageNum)`。該方法通常需要被覆蓋,它被打印架構用于循環控制。如果參數`pageNum`存在于文檔中,那么該方法返回`True`,否則返回`False`。
### 實戰打印構架
下面我們將通過一個例子來展示打印構架實際上是如何工作的。這個例子由一個簡單的用于打印文本文件的構架組成,并且應用程序讓你能夠鍵入簡單的文本。圖17.2顯示了這個應用程序的結果。
**圖17.1**

例17.1顯示了我們已經討論過的打印構架和我們將要接觸的打印對話框機制。
**例17.1** **打印構架的一個較長的例子**
```
import wx
import os
FONTSIZE = 10
class TextDocPrintout(wx.Printout):
"""
A printout class that is able to print simple text documents.
Does not handle page numbers o titles, and it assumes that no
lines are longer than what will fit within the page width. Those
features are left as an exercise for the reader. ;-)
"""
def __init__(self, text, title, margins):
wx.Printout.__init__(self, title)
self.lines = text.split('\n')
self.margins = margins
def HasPage(self, page):
return page = self.numPages
def GetPageInfo(self):
return (1, self.numPages, 1, self.numPages)
def CalculateScale(self, dc):
# Scale the DC such that the printout is roughly the same as
# the screen scaling.
ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
ppiScreenX, ppiScreenY = self.GetPPIScreen()
logScale = float(ppiPrinterX)/float(ppiScreenX)
# Now adjust if the real page size is reduced (such as when
# drawing on a scaled wx.MemoryDC in the Print Preview.) If
# page width == DC width then nothing changes, otherwise we
# scale down for the DC.
pw, ph = self.GetPageSizePixels()
dw, dh = dc.GetSize()
scale = logScale * float(dw)/float(pw)
# Set the DC's scale.
dc.SetUserScale(scale, scale)
# Find the logical units per millimeter (for calculating the
# margins)
self.logUnitsMM = float(ppiPrinterX)/(logScale*25.4)
def CalculateLayout(self, dc):
# Determine the position of the margins and the
# page/line height
topLeft, bottomRight = self.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) - bottomRight.y * self.logUnitsMM
# use a 1mm buffer around the inside of the box, and a few
# pixels between each line
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):
# calculate the number of pages
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):
dc = self.GetDC()
self.CalculateScale(dc)
self.CalculateLayout(dc)
# draw a page outline at the margin points
dc.SetPen(wx.Pen("black", 0))
dc.SetBrush(wx.TRANSPARENT_BRUSH)
r = wx.RectPP((self.x1, self.y1),
(self.x2, self.y2))
dc.DrawRectangleRect(r)
dc.SetClippingRect(r)
# Draw the text lines for this page
line = (page-1) * self.linesPerPage
x = self.x1 + self.logUnitsMM
y = self.y1 + 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):
def __init__(self):
wx.Frame.__init__(self, None, size=(640, 480),
title="Print Framework Sample")
self.CreateStatusBar()
# A text widget to display the doc and let it be edited
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)
# Create the menu and menubar
menu = wx.Menu()
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 ", "Close this application")
self.Bind(wx.EVT_MENU, self.OnExit, item)
menubar = wx.MenuBar()
menubar.Append(menu, " ")
self.SetMenuBar(menubar)
# initialize the print data and set some default values
self.pdata = wx.PrintData()
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()) # force a copy
self.pdata.SetPaperId(data.GetPaperId())
self.margins = (data.GetMarginTopLeft(),
data.GetMarginBottomRight())
dlg.Destroy()
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()) # force a copy
dlg.Destroy()
def OnPrintPreview(self, evt):
data = wx.PrintDialogData(self.pdata)
text = self.tc.GetValue()
printout1 = TextDocPrintout(text, "title", self.margins)
printout2 = None #TextDocPrintout(text, "title", self.margins)
preview = wx.PrintPreview(printout1, printout2, data)
if not preview.Ok():
wx.MessageBox("Unable to create PrintPreview!", "Error")
else:
# create the preview frame such that it overlays the app frame
frame = wx.PreviewFrame(preview, self, "Print Preview",
pos=self.GetPosition(),
size=self.GetSize())
frame.Initialize()
frame.Show()
def OnPrint(self, evt):
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()
```
例17.2中的打印輸出類能夠打印簡單的文本文檔,但是不能處理頁碼或標題,并且它創假設了行的寬度沒有超過頁面的寬度。對于例子的完善就留給讀者作為一個練習。
上面最重要的代碼片斷是在構架的`OnPreparePrinting()`和`OnPrintPage()`以及示例窗口的`OnPrint()`方法中。
### 使用wx.Printout的方法工作
在`wx.Printout`中有幾個`get`*方法,它們使你能夠獲取當前打印環境的有關信息。表17.1列出了這些方法。
**表17.1** **`wx.Printout`的信息獲取方法**
| | |
| --- | --- |
| `GetDC()` | 該方法返回關于打印機或打印預覽的用于繪制文檔的設備上下文。 |
| `GetPageInfo()` | 返回一個含有四個元素的元組(`minPage,?maxPage,?pageFrom,?pageTo)`。`minPage,?maxPage`分別是所允許的最小和最大頁碼,默認是1和32000。`pageFrom,?pageTo`是必須被打印的范圍,默認為1。你可以在你的子類中覆蓋這個方法。 |
| `GetPageSizeMM()` | 返回包含一個頁面的寬度和高度的一個(`w,?h)`元組,以毫米為單位。 |
| `GetPageSizePixels()` | 返回一個頁面的寬度和高度的一個(`w,?h)`元組,以像素為單位。如果打印輸出被用于打印預覽,那么像素數將反應當前的縮放比列,意思就是說像素將會隨縮放比列而變。 |
| `GetPPIPrinter()` | 返回當前打印機在垂直和水平方向上每英寸的像素的一個(`w,?h)`元組。在預覽中,這個值也是始終一致的,即使打印預覽的縮放比列變化了。 |
| `GetPPIScreen()` | 返回當前屏幕在垂直和水平方向上每英寸的像素的一個(`w,?h)`元組。在預覽中,這個值也是始終一致的,即使打印預覽的縮放比列變化了。 |
| `GetTitle()` | 返回打印輸出的標題。 |
在后面的幾節中,我們將討論如何呈現打印對話框給用戶。
## 如何顯示打印對話框?
諸如要打印那些面面,要打印多少副本這些關于打印工作的數據是由標準的打印對話框來管理的。打印對話框是與字體和顏色對話框類似的,`wxPython`中的打印對話框實例僅僅是對本地控件和一個儲存了對話框數據的分離的數據對象的簡單封裝。
### 創建一個打印對話框
圖17.3顯示了打印設置對話框的樣例。
**圖17.3**

這里的對話框是類`wx.PrintDialog`的一個實例,你可以使用下面的構造函數來得到:
```
wx.PrintDialog(parent, data=None)
```
其中,參數`parent`是對話框的父框架,參數`data`是一個預先存在的`wx.PrintDialogData`實例,它用于對話框的初始數據。
**使用方法**
一旦你有了打印對話框,你就可以使用標準的`ShowModal()`方法來顯示它,`ShowModal()`方法將根據用戶關閉對話框的方式而返回`wx.ID_OK`或`wx.ID_CANCEL`。 在你關閉了對話框之后,你可以使用`GetPrintDialogData()`方法來得到用戶輸入的數據。你也可以使用`GetPrintDC()`方法得到與數據相關聯的打印機的設備上下文,如果還沒有內容被創建,那么`GetPrintDC()`方法返回`None`。例17.1中的`OnPrintSetup()`方法顯示了實際上對話框是如何被獲取的。
**使用屬性**
這個數據對象本身有幾個屬性,其中的一個是對`wx.PrintData`類型的一個對象的引用,`wx.PrintData`有更多的屬性。你可以使用構造函數`wx.PrintDialogData()`來創建你的`wx.PrintDialogData`對象。這使得你能夠在打開對話框之前預設屬性。
`wx.PrintDialogData`對象有四個屬性用于控制打印對話框的各個部分的有效性。方法`EnableHelp(enable)`用于開關幫助性能。至于對話框的其它部分,`EnablePageNumbers(enable)`與頁面數量輸入框相關,`EnablePrintToFile(enable)`管理實際的打印按鈕,`EnableSelection(enable)`在打印所有和僅打印被選項之間作切換。
表17.2顯示了對話框數據對象的其它屬性,它們使你能夠管理有關打印請求的信息。
**表17.2** **`wx.PrintDialogData`的屬性**
| | |
| --- | --- |
| `GetAllPages()` | 如果用戶選擇了打印整個文檔這一選項,則返回`True`。 |
| `SetCollate(flag)` | |
| `GetCollate()` | 如果用戶選擇了核對打印的頁,則返回`True`。 |
| `SetFromPage(page)` | |
| `GetFromPage()` | 如果用戶選擇從某一頁打印,那么方法返回打印的第一頁的整數頁碼。 |
| `SetMaxPage(page)` | |
| `GetMaxPage()` | 返回文檔中最大的頁碼。 |
| `SetMinPage(page)` | |
| `GetMinPage()` | 返回文檔中最小的頁碼。 |
| `SetNoCopies()` | |
| `GetNoCopies()` | 返回用戶選擇要打印的副本的數量。 |
| `SetPrintData(printData)` | |
| `GetPrintData()` | 返回與對話框相關聯的`wx.PrintData`對象。 |
| `SetPrintToFile(flag)` | |
| `GetPrintToFile()` | 如果用戶已經選擇了打印到一個文件這一項,那么返回`True`。“打印到文件”這一機制由`wxPython`管理。 |
| `SetSelection(flag)` | |
| `GetSelection()` | 如果用戶已經選擇了只打印當前的選擇這一項,那么返回`True`。 |
| `SetToPage(page)` | |
| `GetToPage()` | 如果用戶指定了一個范圍,那么返回打印的最后一頁的頁碼。 |
被`GetPrintData()`方法返回的`wx.PrintData`實例提供了有關打印的更進一步的信息。通常這些信息是在你的打印對話框的打印設置子對話框中的。表17.3列出了`wx.PrintData`對象的屬性。
**表17.3** **`wx.PrintData`的屬性**
| | |
| --- | --- |
| `SetColour(flag)` |
| `GetColour()` | 如果當前的打印是用于顏色打印的,那么返回`True`。 |
| `SetDuplex(mode)` |
| `GetDuplex()` | 返回當前關于雙面打印的設置。值可以是`wx.DUPLEX_SIMPLE`(非雙面打印),`wx.DUPLEX_HORIZONTAL`(橫向雙面打印),`wx.DUPLEX_VERTICAL`(縱向雙面打印)。 |
| `SetOrientation(orientation)` |
| `GetOrientation()` | 返回紙張的打印定位(肖像或風景)。值可以是`wx.LANDSCAPE`和`wx.PORTRAIT`。 |
| `SetPaperId(paperId)` |
| `GetPaperId()` | 返回匹配紙張類型的標識符。通常的值有`wx.PAPER_LETTER,?wx.PAPER_LEGAL,?`和`wx.PAPER_A4`。完整的頁面(紙張)`ID`的列表見`wxWidgets`文檔。 |
| `SetPrinterName(printerName)` |
| `GetPrinterName()` | 返回被系統引用的當前打印機的名字。如果該值為空字符串,那么默認打印機被使用。 |
| `SetQuality(quality)` |
| `GetQuality()` | 返回打印機的當前品質值。`set`*方法僅接受如下取值 | `wx.PRINT_QUALITY_DRAFT,?wx.PRINT_QUALITY_HIGH,?wx.PRINT_QUALITY_MEDIUM,?`或`wx.PRINT_QUALITY_LOW`。`get`*方法將返回上面的這些值之一,或一個代表每英寸點數設置的正整數。 |
## 如何顯示頁面設置對話框?
圖17.4顯示了頁面設置對話框是如何讓用戶來設置與頁面尺寸相關的數據的。
**圖17.4**

### 創建頁面設置對話框
你可以通過實例化一個`wx.PageSetupDialog`類來創建一個頁面設置對話框。
`wx.PageSetupDialog(parent,?data=None)`
參數`parent`是新的對話框的父窗口。參數`data`是`wx.PageSetupDialogData`的一個實例默認為`None`。一旦頁面設置對話框被創建了,那么這個對話框的行為就和其它任何模式對話框一樣,并且你可以使用`ShowModal()`來顯示它。通常,返回值表明了用戶是否是使用`wx.ID_OK`或`wx.ID_CANCEL`按鈕關閉的對話框窗口。在對話框關閉后,你可以通過調用`GetPageSetupDialogData()`來取得對數據對象的訪問, `GetPageSetupDialogData()`返回類`wx.PageSetupDialogData`的一個實例。
### 使用頁面設置屬性工作
`wx.PageSetupDialogData`類有幾個必須與頁面設置一起使用的屬性。表17.4展示了控制對話框自身顯示的屬性。除非有其它的指定,否則所有這些屬性都默認為`True`。
**表17.4** **`wx.PageSetupDialogData`的對話框控制屬性**
| | |
| --- | --- |
| `GetDefaultMinMargins()` |
| `SetDefaultMinMargins(flag)` | 如果這個屬性為`True`,并且你是在微軟的`Windows`系統上,那么頁面設置將使用默認打印機的當前屬性作為默認認的最小化頁邊距。否則,它將使用系統默認值。 |
| `GetDefaultInfo()` |
| `SetDefaultInfo(flag)` | 如果這個屬性為`True`,并且你是在微軟的`Windows`系統上,那么這個頁面設置對話框不會被顯示。替而代之,當前打印機的所有默認值都將被放入數據對象。 |
| `EnableHelp(flag)` |
| `GetEnableHelp()` | 如果為`True`,那么對話框的幫助部分是有效的。 |
| `EnableMargins(flag)` |
| `GetEnableMargins()` | 如果為`True`,那么對話框的用于調整頁邊距的部分是有效的。 |
| `EnableOrientation(flag)` |
| `GetEnableOrientation()` | 如果為`True`,那么對話框的用于改變頁面定位的部分是有效的。 |
| `EnablePaper(flag)` |
| `GetEnablePaper()` | 如果為`True`,那么對話框的用于允許用戶改變頁面(紙張)類型的部分是效的。 |
| `EnablePrinter(flag)` |
| `GetEnablePrinter()` | 如果為`True`,那么允許用戶設置打印機的按鈕是有效的。 |
表17.5顯示了`wx.PageSetupDialogData`類的附加的屬性,這些屬性用于控制頁面的邊距和尺寸。
**表17.5** **`wx.PageSetupDialogData`的頁邊距和尺寸屬性**
| | |
| --- | --- |
| `GetMarginTopLeft()` |
| `SetMarginTopLeft(pt)` | `get`*方法返回一個`wx.Point`,其中的值x是當前的左邊距,y是當前的上邊距。`set`*方法允許你使用一個`wx.Point`或一個`Python`元組來改變這些值。 |
| `GetMarginBottomRight()` |
| `SetMarginBottomRight(pt)` | `get`*方法返回一個`wx.Point`,其中的值x是當前的右邊距,y是當前的下邊距。`set`*方法允許你使用一個`wx.Point`或一個`Python`元組來改變這些值。 |
| `GetMinMarginTopLeft()` |
| `SetMinMarginTopLeft(pt)` | 同`GetMarginTopLeft()`中的一樣,只是值是所允許的最小左邊距和上邊距。 |
| `GetMinMarginBottomRight()` |
| `SetMinMarginBottomRight(pt)` | 同`GetMarginBottomRight()`中的一樣,只是值是所允許的最小右邊距和下邊距。 |
| `GetPaperId()` |
| `SetPaperId(id)` | 返回關于當前頁面類型的`wxPython`標識符。同`wx.PrinterData`的屬性。 |
| `GetPaperSize()` |
| `SetPaperSize(size)` | `get`*方法返回包含頁面的水平和堅直方向尺寸的一個`wx.Size`實例。單位是毫米。 |
| `GetPrintData()` |
| `SetPrintData(printData)` | `get`*方法返回與當前打印會話相關的`wx.PrintData`實例。 |
到目前為止,我們已經討論了所有關于數據對話框的整改,下面我們將重點放在打印上面。
## 如何打印?
到目前為止,我們已經見過了打印構架的所有部分,現是我們打印一些東西的時候了。實際的打印部分是由`wx.Printer`類的一個實例來控制的。與已經說明的其它部分相比,打印并不更簡單。接下來,我們將對在例17.1中的`OnPrint()`中的步驟作介紹。
第一步 按順序得到你的所有數據
這至少應該包括帶有打印機命令的`wx.Printout`對象,通常也要包括一個`wx.PrintDialogData`實例。
第二步 創建一個`wx.Printer`實例
創建該實例,要使用構造器`wx.Printer(data=None)`。可選參數`data`是一個`wx.PrintDialogData`實例。該數據控制打印,通常,你會想使用它。
第三步 使用`wx.Printer`的`Print?()`方法打印
`Print()`方法如下:
```
Print(parent, printout, prompt=True)
```
其中參數`parent`是當打印時所觸發的對話框的父窗口。`printout`是用于打印的`wx.Printout`對象。如果參數`prompt`為`True`,那么在打印之前顯示打印對話框,否則將立即;啟動打印。
如果打印成功,則`Print()`方法返回`True`。你能夠調用`GetLastError()`方法來得到下列常量之一:`wx.PRINTER_CANCELLED`(如果失敗是由于用戶取消了打印所引起的),`wx.PRINTER_ERROR`(如果失敗在打印期間由打印自身所引起的),或`wx.PRINTER_NO_ERROR`(如果`Print()`返回`True`且沒有錯誤發生)。
這兒還有另外兩個你可以使用一個`wx.Printer`實例做的事:
* 你可以使用`CreateAbortWindow(parent,printout)`來顯示中止對話框,其中參數`parent`和`printout`同`Print()`方法中的。如果用戶已經中止打印任務,你能夠通過調用`Abort()`來發現,該方法在這種情況下返回`True`。
* 你可以使用`PrintDialog(parent)`來顯式地顯示打印對話框,并且你可以使用`GetPrintDialogData()`來得到活動的打印數據對象。
## 如何實現一個打印預覽?
使用設備上下文的一個好處就是很容易管理打印預覽,你可以使用一個屏幕設備上下文來代替打印機設備上下文。接下來的三個部分將討論打印預覽的過程。
第一步 創建預覽實例
在一個打印預覽中的第一步是創建類`wx.PrintPreview`的一個實例,`wx.PrintPreview`類似`wx.Printer`。構造器如下:
```
wx.PrintPreview(printout, printoutForPrinting, data=None)
```
其中參數`printout`是一個`wx.Printout`對象,用于管理預覽。參數`printoutForPrinting`是另一個`wx.Printout`對象。如果它不是`None`,那么當顯示的時候,該打印預覽窗口包含一`Print`按鈕,該按鈕啟動打印。`printoutForPrinting`用于實際的打印。如果參數`printoutForPrinting`為`None`,那么`Print`按鈕不顯示。當然,你可以傳遞同一個實例或你的自定義打印輸出類的相同版本的兩個實例給參數`printout`和`printoutForPrinting`。參數`data`可以是一個`wx.PrintData`對象或一個`wx.PrintDialogData`對象。如果參數`data`指定了的話,那么它被用于控制該打印預覽。在例17.1中,我們顯示了一個在`OnPrintPreview()`方法中使用打印預覽的例子。
第二步 創建預覽框架
一旦你有了你的`wx.PrintPreview`,你就需要一框架以在其中觀看你的`wx.PrintPreview`。該框架由類`wx.PreviewFrame`提供,`wx.PreviewFrame`是`wx.Frame`的一個子類,`wx.Frame`為預覽提供基本的用戶交互控件。`wx.PreviewFrame`的構造器如下:
```
wx.PreviewFrame(preview, parent, title, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
name="frame")
```
其中真正有意義的參數是`preview`,它是要被預覽的`wx.PrintPreview`實例。其它的參數都是標準的`wx.Frame`中的。`wx.PreviewFrame`不定義任何自定義的樣式或事件。
第三步 初始化框架
在你顯示你的`wx.PreviewFrame`之前,你需要調用`Initialize()`方法,該方法創建窗口的內部的部件并做其它的內部的計算。一旦你`Show()`了該框架,那么如果你想再改變預覽窗口的感觀,你可以使用考慮`CreateControlBar()`和`CreateCanvas()`方法,它們分別創建類`wx.PreviewControlBar`和`wx.PreviewCanvas`的對象。覆蓋這些方法以創建你自己的畫布(`canvas)`和/或控制欄對象,使得你能夠定制你的打印預覽窗口的感觀。
## 本章小結
1、這是`wxPython`中的一個通用的打印構架,它不僅可以打印`HTML`,還可以打印任何能夠被繪制到設備上下文的東西。這個架構中的主要的類是`wx.Printout`,但是`wx.Printer`和`wx.PrintPreview`也是重要的。
2、`wx.Printout`類管理圖形打印的細節,并且它包含幾個可以被覆蓋來定制打印會話期間的行為和使用的數據的方法。打印發生在`OnPrintPage()`方法期間。
3、用于打印機設置和頁面設置的標準的對話框是可以從`wxPython`來訪問的。打印機設置對話框是`wx.PrintDialog`的一個實例,頁面設置對話框是`wx.PageSetupDialog`的一個實例。這兩個對話框都有相關的數據類,數據類使你的程序可以處理所有顯示在對話框中的值。
4、一旦有了數據,那么實際將數據傳送給打印機則是`wx.Printer`類的相對簡單的應用。你可以使用`wx.PrintPreview`類來管理一個打印預覽會話,該類包括一個打印預覽框架,和根據該框架指定通常打印行為的選項。
- 活學活用wxPython
- 前言
- 致謝
- 關于本書
- 第一部分
- 第一章 歡迎使用wxPython
- 第二章 給wxPython程序一個堅實的基礎
- 第三章 在事件驅動環境中開發
- 第四章 用PyCrust使得wxPython更易處理
- 第五章 繪制藍圖
- 第六章 使用wxPython基本構件
- 第二部分 基礎wxPython
- 第七章 使用基礎控件
- 第八章 將構件放入窗體中
- 第九章 通過對話框讓用戶選擇
- 第十章 創建和使用wxPython菜單
- 第十一章 使用sizer放置構件
- 第十二章 操作基本圖像
- 第三部分 高級wxPython
- 第十三章 建造列表控件并管理列表項
- 第十四章 網格控件
- 第十五章 樹形控件
- 第十六章 在應用程序中加入HTML
- 第十七章 wxPython的打印構架
- 第十八章 使用wxPython的其他功能