I have been playing with this for a couple of days and I cannot get
printing and print previewing to work consistently. I adapted my
print setup from the wxPython In Action book and from the
StyledTextCtrl information. I can preview and print just fine, but I
cannot get the preview to match the print out exactly. For example,
when I preview the document I compute that the number of lines per
page are 45 but when I physically print it out I calculate 53 lines
per page. Also when I change certain zoom percentages, the line
numbers per page are sometimes not consistent with other zoom
percentages either. So the main problem is I cannot achieve
consistency between different zoom percentages of the print preview
what the actual print out will look like.
My page height calculations, margins etc all come out consistent. My
problems seem to be in calculating my scale and for some reason when I
try to retrieve the character height it differs significantly from the
preview to the actual printout.
I have attached my sample code below, I appreciate any assistance or
advice.
"""
Assembles a document which can be sent to a printer. This will
also create a document for previewing as
well.
"""
# Import outside dependancies
import wx
import wx.stc as stc
···
#
----------------------------------------------------------------------------------------------------------
class GeneratePrintableDoc(wx.Printout):
def __init__(self, doc, margins=((wx.Point(15,15)),wx.Point
(15,15))):
"""
Print the document
"""
wx.Printout.__init__(self)
# Set a reference to the STC document
self.doc = doc
# Set the margin
self.margins = margins
def HasPage(self, page):
"""
Return whether this page exists
"""
return page <= 1
def GetPageInfo(self):
return (1, 1, 1, 1)
def CalculateScale(self, dc):
"""
Calcualte the scale for the device context
"""
# Get the device context parameters
dcX_du, dcY_du = dc.GetSize()
# Get the pixels per logical inch of the printer and screen
device context
pPrintX_ppi, pPrintY_ppi = self.GetPPIPrinter()
pScrnX_ppi, pScrnY_ppi = self.GetPPIScreen()
# Get the physical dimensions of the page in millimeters and
pixels
pPageX_px, pPageY_px = self.GetPageSizePixels()
# Calculate the scale for the PPI between the device context
for the printer and screen
self.ppiScale = float(pPrintX_ppi)/float(pScrnX_ppi)
# Calculate the scale for the screen device context
self.screenScaleX = self.ppiScale * (float(dcX_du)/float
(pPageX_px))
self.screenScaleY = self.ppiScale * (float(dcY_du)/float
(pPageY_px))
# Set the device context scale
dc.SetUserScale(self.screenScaleX, self.screenScaleY)
# Calcuate the number of pixels per millimeter
self.PPMM = float(pPrintX_ppi)/(self.ppiScale * 25.4)
def CalcualteLayout(self, dc):
"""
Calcualate the layout of the document
"""
# Get the size of the screen device context in millimeters
dcX_px, dcY_px = dc.GetSize()
# Get the top and bottom coordinates
topLeft, bottomRight = self.margins
# Calculate the top rectangle point in pixels
self.x1 = topLeft.x * self.PPMM
self.y1 = topLeft.y * self.PPMM
self.x2 = (dc.DeviceToLogicalXRel(dcX_px) - bottomRight.x *
self.PPMM)
self.y2 = (dc.DeviceToLogicalYRel(dcY_px) - bottomRight.y *
self.PPMM)
# Calculate the printable page width and height
self.pageHeight = self.y2 - self.y1
self.pageWidth = self.x2 - self.x1
# Set the font for the device
font = wx.Font(12, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
dc.SetFont(font)
self.charHeight = dc.GetCharHeight()
self.charWidth = dc.GetCharWidth()
# Calculate the allowable lines and columns per page
self.linesPerPage = int(self.pageHeight/self.charHeight)
self.linesPerColumn = int(self.pageWidth/self.charWidth)
def OnPreparePrinting(self):
"""
Calculate the scale and layout. Compute the number of pages
for this document
"""
dc = self.GetDC()
self.CalculateScale(dc)
self.CalcualteLayout(dc)
# Here I would calculate the number of pages in the document
def OnPrintPage(self, page):
"""
Create the device context and then use the STC FormatRange to
generate the final document
"""
dc = self.GetDC()
self.CalculateScale(dc)
self.CalcualteLayout(dc)
rect = wx.RectPP((self.x1, self.y1), (self.x2, self.y2))
dc.SetPen(wx.Pen("black",1))
dc.DrawRectangleRect(rect)
# Format the text
ep = self.doc.FormatRange(True, 0, self.doc.GetLength(), dc,
dc, rect, rect)
return True
class MyApp(wx.App):
def OnInit(self):
frame = SimpleDoc(None)
frame.Show(True)
self.SetTopWindow(frame)
return True
class SimpleDoc(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, wx.ID_ANY)
self.doc = stc.StyledTextCtrl(self, wx.ID_ANY)
for i in range(0,128):
self.doc.AddText("line: %d\n" % i)
# Create the menu bar
self.mb = wx.MenuBar()
self.mFile = wx.Menu()
PRINTPREVIEW = wx.NewId()
self.mFile.Append(PRINTPREVIEW, "Print Preview")
self.mb.Append(self.mFile, "File")
self.SetMenuBar(self.mb)
szr = wx.BoxSizer(wx.VERTICAL)
szr.Add(self.doc,1,wx.EXPAND)
self.Bind(wx.EVT_MENU, self.Print, id=PRINTPREVIEW)
def Print(self, evt):
printout = GeneratePrintableDoc(self.doc)
printout2 = GeneratePrintableDoc(self.doc)
preview = wx.PrintPreview(printout, printout2, wx.PrintData())
pre_frame = wx.PreviewFrame(preview, None, "Print Preview")
pre_frame.Initialize()
pre_frame.Show()
# Main
if __name__=='__main__':
app = MyApp(0)
app.MainLoop()