Printing framework (Phoenix)

Keywords : Printing, Printout, Preview, Printer, PrintData, PrintDialogData, PageSetupDialogData, PageSetupDialog, PrintPreview, PreviewFrame, Canvas, Grid, HtmlEasyPrinting, PDFViewer, PDFWindow, ReportLab.


Introduction

The Printer framework for wx.Windows / wx.Python is quite complicated. Because of this, wx.HtmlEasyPrinting is provided to help simplify basic printing functionality. This Recipe covers a simplified approach to using both wx.HtmlEasyPrinting and the more complicated wx.Printout.


What Objects are Involved

The following classes will be used in these recipes:


Demonstrating :

Tested py3.x, wx4.x and Win10.

Printing is an essential element for your programs, here we show you how to print.

Are you ready to use some samples ? ;)

Test, modify, correct, complete, improve and share your discoveries ! (!)


Direct printing

img_sample_one.png

   1 # sample_one.py
   2 
   3 import sys
   4 import os
   5 import platform
   6 import wx
   7 
   8 # class My_Frame
   9 # class My_App
  10 
  11 #-------------------------------------------------------------------------------
  12 
  13 if os.name == "posix":
  14     print("\nPlatform : UNIX - Linux")
  15 elif os.name in ['nt', 'dos', 'ce']:
  16     print("\nPlatform : Windows")
  17 else:
  18     print("\nPlatform : ", platform.system())
  19 
  20 #-------------------------------------------------------------------------------
  21 
  22 class My_Frame(wx.Frame):
  23     """
  24     Create a main frame for my application.
  25     """
  26     def __init__(self, parent, id, title=""):
  27         wx.Frame.__init__(self,
  28                           parent,
  29                           id,
  30                           title,
  31                           size=(600, 350),
  32                           style=wx.DEFAULT_FRAME_STYLE)
  33 
  34         #------------
  35 
  36         # Simplified init method.
  37         self.SetProperties()
  38         self.CreateMenu()
  39         self.CreateCtrls()
  40         self.BindEvents()
  41         self.DoLayout()
  42 
  43         #------------
  44 
  45         self.CenterOnScreen()
  46 
  47     #---------------------------------------------------------------------------
  48 
  49     def SetProperties(self):
  50         """
  51         Set the main frame properties (title, icon...).
  52         """
  53 
  54         self.SetTitle("Printing test...")
  55 
  56 
  57     def CreateMenu(self):
  58         """
  59         Make the frame menus.
  60         """
  61 
  62         menub = wx.MenuBar()
  63 
  64         fmenu = wx.Menu()
  65         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
  66         fmenu.AppendSeparator()
  67         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
  68         menub.Append(fmenu, "&File")
  69 
  70         self.SetMenuBar(menub)
  71 
  72 
  73     def CreateCtrls(self):
  74         """
  75         Make widgets for my application.
  76         """
  77 
  78         boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
  79         boldFont.SetWeight(wx.BOLD)
  80         boldFont.SetPointSize(10)
  81 
  82         #------------
  83 
  84         # First create the controls.
  85         self.panel = wx.Panel(self,
  86                               id=-1,
  87                               style=wx.BORDER_THEME|
  88                               wx.TAB_TRAVERSAL)
  89 
  90         self.text = wx.StaticText(self.panel,
  91                                   id=-1,
  92                                   label="Demonstrating :")
  93         self.text.SetFont(boldFont)
  94 
  95         self.info = wx.StaticText(self.panel,
  96                                   id=-1,
  97                                   label="> Direct printing.")
  98         self.info.SetForegroundColour("red")
  99 
 100         self.tc = wx.TextCtrl(self.panel,
 101                               id=-1,
 102                               size=(200, -1),
 103                               value="Hello, World ! A sample text.")
 104 
 105         self.btnPrint = wx.Button(self.panel,
 106                                   id=wx.ID_PRINT,
 107                                   label="")
 108         self.btnPrint.SetFocus()
 109 
 110         self.btnClose = wx.Button(self.panel,
 111                                   id=wx.ID_CLOSE,
 112                                   label="E&xit")
 113 
 114 
 115     def BindEvents(self):
 116         """
 117         Bind all the events related to my application.
 118         """
 119 
 120         # Bind some menu events to an events handler.
 121         self.Bind(wx.EVT_MENU, self.OnBtnPrint, id=wx.ID_PRINT)
 122         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 123 
 124         # Bind the close event to an event handler.
 125         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 126 
 127         # Bind some buttons events to an events handler.
 128         self.Bind(wx.EVT_BUTTON, self.OnBtnPrint, self.btnPrint)
 129         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 130 
 131 
 132     def DoLayout(self):
 133         """
 134         Manage widgets Layout.
 135         """
 136 
 137         # MainSizer is the top-level one that manages everything.
 138         mainSizer = wx.BoxSizer(wx.VERTICAL)
 139 
 140         #------------
 141 
 142         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 143         hBox1.Add(self.info, 0, wx.ALL, 15)
 144 
 145         #------------
 146 
 147         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 148         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
 149         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 150 
 151         #------------
 152 
 153         mainSizer.Add(self.text, 0, wx.ALL, 10)
 154         mainSizer.Add(wx.StaticLine(self.panel),
 155                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 156         mainSizer.Add(self.tc, 0, wx.ALL, 15)
 157         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 158         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 159 
 160         #------------
 161 
 162         # Finally, tell the panel to use the mainSizer for layout.
 163         self.panel.SetSizer(mainSizer)
 164 
 165 
 166     def OnBtnPrint(self, event):
 167         """
 168         Print the document.
 169         """
 170 
 171         text = self.tc.GetValue()
 172 
 173         #------------
 174 
 175         pd = wx.PrintData()
 176 
 177         pd.SetPrinterName("")
 178         pd.SetOrientation(wx.PORTRAIT)
 179         pd.SetPaperId(wx.PAPER_A4)
 180         pd.SetQuality(wx.PRINT_QUALITY_DRAFT)
 181         # Black and white printing if False.
 182         pd.SetColour(True)
 183         pd.SetNoCopies(1)
 184         pd.SetCollate(True)
 185 
 186         #------------
 187 
 188         pdd = wx.PrintDialogData()
 189 
 190         pdd.SetPrintData(pd)
 191         pdd.SetMinPage(1)
 192         pdd.SetMaxPage(1)
 193         pdd.SetFromPage(1)
 194         pdd.SetToPage(1)
 195         pdd.SetPrintToFile(False)
 196         # pdd.SetSetupDialog(False)
 197         # pdd.EnableSelection(True)
 198         # pdd.EnablePrintToFile(True)
 199         # pdd.EnablePageNumbers(True)
 200         # pdd.SetAllPages(True)
 201 
 202         #------------
 203 
 204         dlg = wx.PrintDialog(self, pdd)
 205 
 206         if dlg.ShowModal() == wx.ID_OK:
 207             dc = dlg.GetPrintDC()
 208 
 209             dc.StartDoc("My document title")
 210             dc.StartPage()
 211 
 212             # (wx.MM_METRIC) ---> Each logical unit is 1 mm.
 213             # (wx.MM_POINTS) ---> Each logical unit is a "printer point" i.e.
 214             dc.SetMapMode(wx.MM_POINTS)
 215 
 216             dc.SetTextForeground("red")
 217             dc.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD))
 218             dc.DrawText(text, 50, 100)
 219 
 220             dc.EndPage()
 221             dc.EndDoc()
 222             del dc
 223 
 224         else :
 225             dlg.Destroy()
 226 
 227 
 228     def OnBtnClose(self, event):
 229         """
 230         ...
 231         """
 232 
 233         self.Close(True)
 234 
 235 
 236     def OnCloseWindow(self, event):
 237         """
 238         ...
 239         """
 240 
 241         self.Destroy()
 242 
 243 #-------------------------------------------------------------------------------
 244 
 245 class My_App(wx.App):
 246     """
 247     ...
 248     """
 249     def OnInit(self):
 250 
 251         #------------
 252 
 253         frame = My_Frame(None, id=-1)
 254         self.SetTopWindow(frame)
 255         frame.Show(True)
 256 
 257         return True
 258 
 259 #-------------------------------------------------------------------------------
 260 
 261 def main():
 262     app = My_App(False)
 263     app.MainLoop()
 264 
 265 #-------------------------------------------------------------------------------
 266 
 267 if __name__ == "__main__" :
 268     main()


Printout class

img_sample_two.png

   1 # sample_two.py
   2 
   3 import sys
   4 import os
   5 import platform
   6 import wx
   7 
   8 # class My_Printout
   9 # class My_Frame
  10 # class My_App
  11 
  12 #-------------------------------------------------------------------------------
  13 
  14 if os.name == "posix":
  15     print("\nPlatform : UNIX - Linux")
  16 elif os.name in ['nt', 'dos', 'ce']:
  17     print("\nPlatform : Windows")
  18 else:
  19     print("\nPlatform : ", platform.system())
  20 
  21 #-------------------------------------------------------------------------------
  22 
  23 class My_Printout(wx.Printout):
  24     """
  25     Create a printout.
  26     """
  27     def __init__(self, text, title):
  28         wx.Printout.__init__(self, title)
  29 
  30         #------------
  31 
  32         self.lines = text
  33 
  34     #---------------------------------------------------------------------------
  35 
  36     def OnBeginDocument(self, start, end):
  37         """
  38         ...
  39         """
  40 
  41         return super(My_Printout, self).OnBeginDocument(start, end)
  42 
  43 
  44     def OnEndDocument(self):
  45         """
  46         ...
  47         """
  48 
  49         super(My_Printout, self).OnEndDocument()
  50 
  51 
  52     def OnBeginPrinting(self):
  53         """
  54         ...
  55         """
  56 
  57         super(My_Printout, self).OnBeginPrinting()
  58 
  59 
  60     def OnEndPrinting(self):
  61         """
  62         ...
  63         """
  64 
  65         super(My_Printout, self).OnEndPrinting()
  66 
  67 
  68     def OnPreparePrinting(self):
  69         """
  70         ...
  71         """
  72 
  73         super(My_Printout, self).OnPreparePrinting()
  74 
  75 
  76     def HasPage(self, page):
  77         """
  78         ...
  79         """
  80 
  81         if page <= 2:
  82             return True
  83         else:
  84             return False
  85 
  86 
  87     def GetPageInfo(self):
  88         """
  89         ...
  90         """
  91 
  92         return (1, 2, 1, 2)
  93 
  94 
  95     def OnPrintPage(self, page):
  96         """
  97         ...
  98         """
  99 
 100         dc = self.GetDC()
 101 
 102         # (wx.MM_METRIC) ---> Each logical unit is 1 mm.
 103         # (wx.MM_POINTS) ---> Each logical unit is a "printer point" i.e.
 104         dc.SetMapMode(wx.MM_POINTS)
 105 
 106         dc.SetTextForeground("red")
 107         dc.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD))
 108         dc.DrawText(self.lines, 50, 100)
 109 
 110         # R, V, B.
 111         dc.SetPen(wx.Pen(wx.Colour(255, 20, 5)))
 112         dc.SetBrush(wx.Brush(wx.Colour(30, 255, 20)))
 113         # x, y, radius.
 114         dc.DrawCircle(100, 275, 25)
 115         # x, y, width, height.
 116         dc.DrawEllipse(100, 275, 75, 50)
 117 
 118         return True
 119 
 120 #-------------------------------------------------------------------------------
 121 
 122 class My_Frame(wx.Frame):
 123     """
 124     Create a main frame for my application.
 125     """
 126     def __init__(self, parent, id, title=""):
 127         wx.Frame.__init__(self,
 128                           parent,
 129                           id,
 130                           title,
 131                           size=(600, 350),
 132                           style=wx.DEFAULT_FRAME_STYLE)
 133 
 134         #------------
 135 
 136         # Simplified init method.
 137         self.SetProperties()
 138         self.CreateMenu()
 139         self.CreateCtrls()
 140         self.CreatePrintData()
 141         self.BindEvents()
 142         self.DoLayout()
 143 
 144         #------------
 145 
 146         self.CenterOnScreen()
 147 
 148     #---------------------------------------------------------------------------
 149 
 150     def SetProperties(self):
 151         """
 152         Set the main frame properties (title, icon...).
 153         """
 154 
 155         self.SetTitle("Printing test...")
 156 
 157 
 158     def CreateMenu(self):
 159         """
 160         Make the frame menus.
 161         """
 162 
 163         menub = wx.MenuBar()
 164 
 165         fmenu = wx.Menu()
 166         fmenu.Append(wx.ID_PAGE_SETUP, "Page set&up\tCtrl+U")
 167         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
 168         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
 169         fmenu.AppendSeparator()
 170         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
 171         menub.Append(fmenu, "&File")
 172 
 173         self.SetMenuBar(menub)
 174 
 175 
 176     def CreateCtrls(self):
 177         """
 178         Make widgets for my app.
 179         """
 180 
 181         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 182         font.SetWeight(wx.BOLD)
 183         font.SetPointSize(10)
 184 
 185         #------------
 186 
 187         # First create the controls.
 188         self.panel = wx.Panel(self,
 189                               id=-1,
 190                               style=wx.BORDER_THEME|
 191                               wx.TAB_TRAVERSAL)
 192 
 193         self.text = wx.StaticText(self.panel,
 194                                   id=-1,
 195                                   label="Demonstrating :")
 196         self.text.SetFont(font)
 197 
 198         self.info = wx.StaticText(self.panel,
 199                                   id=-1,
 200                                   label="1) Direct printing,\n"
 201                                         "2) Printout class,\n"
 202                                         "3) Preview,\n"
 203                                         "4) Menu,\n"
 204                                         "5) Page setup.")
 205         self.info.SetForegroundColour("red")
 206         font.SetWeight(wx.NORMAL)
 207         self.info.SetFont(font)
 208 
 209         self.tc = wx.TextCtrl(self.panel,
 210                               id=-1,
 211                               size=(200, -1),
 212                               value="Hello, World ! A sample text.")
 213 
 214         self.btnSetup = wx.Button(self.panel,
 215                                   id=wx.ID_PAGE_SETUP,
 216                                   label="Page set&up")
 217 
 218         self.btnPreview = wx.Button(self.panel,
 219                                     id=wx.ID_PREVIEW,
 220                                     label="Print pre&view")
 221         self.btnPreview.SetFocus()
 222 
 223         self.btnPrint = wx.Button(self.panel,
 224                                   id=wx.ID_PRINT,
 225                                   label="&Print")
 226 
 227         self.btnClose = wx.Button(self.panel,
 228                                   id=wx.ID_CLOSE,
 229                                   label="E&xit")
 230 
 231 
 232     def CreatePrintData(self):
 233         """
 234         Create printing data.
 235         """
 236 
 237         self.printdata = wx.PrintData()
 238 
 239         self.printdata.SetPrinterName('')
 240         self.printdata.SetOrientation(wx.PORTRAIT)
 241         self.printdata.SetPaperId(wx.PAPER_A4)
 242         self.printdata.SetQuality(wx.PRINT_QUALITY_DRAFT)
 243         # Black and white printing if False.
 244         self.printdata.SetColour(True)
 245         self.printdata.SetNoCopies(1)
 246         self.printdata.SetCollate(True)
 247         # self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)
 248 
 249 
 250     def BindEvents(self):
 251         """
 252         Bind all the events related to my application.
 253         """
 254 
 255         # Bind some menu events to an events handler.
 256         self.Bind(wx.EVT_MENU, self.OnBtnPageSetup, id=wx.ID_PAGE_SETUP)
 257         self.Bind(wx.EVT_MENU, self.OnBtnPreview, id=wx.ID_PREVIEW)
 258         self.Bind(wx.EVT_MENU, self.OnBtnPrint, id=wx.ID_PRINT)
 259         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 260 
 261         # Bind the close event to an event handler.
 262         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 263 
 264         # Bind some buttons events to an events handler.
 265         self.Bind(wx.EVT_BUTTON, self.OnBtnPageSetup, self.btnSetup)
 266         self.Bind(wx.EVT_BUTTON, self.OnBtnPreview, self.btnPreview)
 267         self.Bind(wx.EVT_BUTTON, self.OnBtnPrint, self.btnPrint)
 268         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 269 
 270 
 271     def DoLayout(self):
 272         """
 273         Manage widgets Layout.
 274         """
 275 
 276         # MainSizer is the top-level one that manages everything.
 277         mainSizer = wx.BoxSizer(wx.VERTICAL)
 278 
 279         #------------
 280 
 281         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 282         hBox1.Add(self.info, 0, wx.ALL, 15)
 283 
 284         #------------
 285 
 286         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 287         hBox2.Add(self.btnSetup, 0, wx.ALL, 10)
 288         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
 289         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
 290         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 291 
 292         #------------
 293 
 294         mainSizer.Add(self.text, 0, wx.ALL, 10)
 295         mainSizer.Add(wx.StaticLine(self.panel),
 296                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 297         mainSizer.Add(self.tc, 0, wx.ALL, 15)
 298         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 299         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 300 
 301         #------------
 302 
 303         # Finally, tell the panel to use the mainSizer for layout.
 304         self.panel.SetSizer(mainSizer)
 305 
 306 
 307     def OnBtnPageSetup(self, event):
 308         """
 309         Show the PrinterSetup dialog.
 310         """
 311 
 312         psdd = wx.PageSetupDialogData(self.printdata)
 313 
 314         psdd.EnablePrinter(True)
 315         # psdd.CalculatePaperSizeFromId()
 316 
 317         #------------
 318 
 319         dlg = wx.PageSetupDialog(self, psdd)
 320         dlg.ShowModal()
 321 
 322         #------------
 323 
 324         # This makes a copy of the wx.PrintData instead of just saving
 325         # a reference to the one inside the PrintDialogData that will
 326         # be destroyed when the dialog is destroyed
 327         self.printdata = wx.PrintData(dlg.GetPageSetupData().GetPrintData())
 328 
 329         dlg.Destroy()
 330 
 331 
 332     def OnBtnPreview(self, event):
 333         """
 334         Show the print preview.
 335         """
 336 
 337         text = self.tc.GetValue()
 338 
 339         #------------
 340 
 341         data = wx.PrintDialogData(self.printdata)
 342 
 343         printout1 = My_Printout(text, "- My printing object")
 344         printout2 = My_Printout(text, "- My printing object")
 345 
 346         printPreview = wx.PrintPreview(printout1, printout2, data)
 347 
 348         # Initial zoom value.
 349         if "__WXMAC__" in wx.PlatformInfo:
 350             printPreview.SetZoom(50)
 351         else:
 352             printPreview.SetZoom(35)
 353 
 354         if not printPreview.IsOk():
 355             wx.MessageBox(("There was a problem printing.\nPerhaps "\
 356                            "your current printer is \nnot "\
 357                            "set correctly ?"),
 358                           ("Printing"),
 359                           wx.OK)
 360             return
 361 
 362         else:
 363             previewFrame = wx.PreviewFrame(printPreview, None, "Print preview")
 364             previewFrame.Initialize()
 365             previewFrame.SetPosition(self.GetPosition())
 366             previewFrame.SetSize(self.GetSize())
 367             # Or full screen :
 368             # previewFrame.Maximize()
 369             previewFrame.Show(True)
 370             previewFrame.Layout()
 371 
 372 
 373     def OnBtnPrint(self, event):
 374         """
 375         Prints the document.
 376         """
 377 
 378         text = self.tc.GetValue()
 379 
 380         #------------
 381 
 382         pdd = wx.PrintDialogData(self.printdata)
 383         pdd.SetPrintData(self.printdata)
 384         pdd.SetMinPage(1)
 385         pdd.SetMaxPage(1)
 386         pdd.SetFromPage(1)
 387         pdd.SetToPage(1)
 388         pdd.SetPrintToFile(False)
 389         # pdd.SetSetupDialog(False)
 390         # pdd.EnableSelection(True)
 391         # pdd.EnablePrintToFile(True)
 392         # pdd.EnablePageNumbers(True)
 393         # pdd.SetAllPages(True)
 394 
 395         #------------
 396 
 397         printer = wx.Printer(pdd)
 398 
 399         myPrintout = My_Printout(text, "- My printing object")
 400 
 401         if not printer.Print(self, myPrintout, True):
 402             wx.MessageBox(("There was a problem printing.\nPerhaps "\
 403                            "your current printer is \nnot "\
 404                            "set correctly ?"),
 405                           ("Printing"),
 406                           wx.OK)
 407             return
 408 
 409         else:
 410             self.printData = wx.PrintData(printer.GetPrintDialogData().GetPrintData())
 411         myPrintout.Destroy()
 412 
 413 
 414     def OnBtnClose(self, event):
 415         """
 416         ...
 417         """
 418 
 419         self.Close(True)
 420 
 421 
 422     def OnCloseWindow(self, event):
 423         """
 424         ...
 425         """
 426 
 427         self.Destroy()
 428 
 429 #-------------------------------------------------------------------------------
 430 
 431 class My_App(wx.App):
 432     """
 433     ...
 434     """
 435     def OnInit(self):
 436 
 437         #------------
 438 
 439         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 440 
 441         #------------
 442 
 443         frame = My_Frame(None, id=-1)
 444         self.SetTopWindow(frame)
 445         frame.Show(True)
 446 
 447         return True
 448 
 449 
 450 #-------------------------------------------------------------------------------
 451 
 452 def main():
 453     app = My_App(False)
 454     app.MainLoop()
 455 
 456 #-------------------------------------------------------------------------------
 457 
 458 if __name__ == "__main__" :
 459     main()


Canvas and printout class

img_sample_three.png

   1 # sample_three.py
   2 
   3 import sys
   4 import os
   5 import platform
   6 import time
   7 import wx
   8 
   9 # class My_Canvas
  10 # class My_Printout
  11 # class My_Frame
  12 # class My_App
  13 
  14 # There are two different approaches to drawing, buffered or direct.
  15 # This sample shows both approaches so you can easily compare and
  16 # contrast the two by changing this value :
  17 BUFFERED = 1
  18 
  19 #-------------------------------------------------------------------------------
  20 
  21 if os.name == "posix":
  22     print("\nPlatform : UNIX - Linux")
  23 elif os.name in ['nt', 'dos', 'ce']:
  24     print("\nPlatform : Windows")
  25 else:
  26     print("\nPlatform : ", platform.system())
  27 
  28 #-------------------------------------------------------------------------------
  29 
  30 class My_Canvas(wx.ScrolledWindow):
  31     """
  32     ...
  33     """
  34     def __init__(self, parent, id=-1, size=wx.DefaultSize):
  35         wx.ScrolledWindow.__init__(self,
  36                                    parent,
  37                                    id,
  38                                    pos=(0, 0),
  39                                    size=size,
  40                                    style=wx.SUNKEN_BORDER)
  41 
  42         #------------
  43 
  44         self.maxWidth  = 1000
  45         self.maxHeight = 1000
  46         self.x = self.y = 0
  47         self.drawing = False
  48 
  49         #------------
  50 
  51         self.SetVirtualSize((self.maxWidth, self.maxHeight))
  52         self.SetScrollRate(30, 30)
  53 
  54         #------------
  55 
  56         if BUFFERED:
  57             # Initialize the buffer bitmap.  No real DC is needed at this point
  58             self.buffer = wx.Bitmap(self.maxWidth, self.maxHeight)
  59             dc = wx.BufferedDC(None, self.buffer)
  60             dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
  61             dc.Clear()
  62             self.DoDrawing(dc)
  63 
  64         #------------
  65 
  66         # Bind a paint event to an events handler
  67         self.Bind(wx.EVT_PAINT, self.OnPaint)
  68 
  69     #---------------------------------------------------------------------------
  70 
  71     def GetWidth(self):
  72         """
  73         ...
  74         """
  75 
  76         return self.maxWidth
  77 
  78 
  79     def GetHeight(self):
  80         """
  81         ...
  82         """
  83 
  84         return self.maxHeight
  85 
  86 
  87     def OnPaint(self, event):
  88         """
  89         ...
  90         """
  91 
  92         if BUFFERED:
  93             # Create a buffered paint DC.  It will create the real
  94             # wx.PaintDC and then blit the bitmap to it when dc is
  95             # deleted.  Since we don't need to draw anything else
  96             # here that's all there is to it.
  97             dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)
  98         else:
  99             dc = wx.PaintDC(self)
 100             self.PrepareDC(dc)
 101             # Since we're not buffering in this case, we have to
 102             # (re)paint the all the contents of the window, which can
 103             # be potentially time consuming and flickery depending on
 104             # what is being drawn and how much of it there is.
 105             self.DoDrawing(dc)
 106 
 107 
 108     def DoDrawing(self, dc, printing=False):
 109         """
 110         ...
 111         """
 112 
 113         # Draw.
 114         pen = wx.Pen("BLACK", 4, wx.SOLID)
 115 
 116         dc.SetPen(wx.TRANSPARENT_PEN)
 117         dc.SetBrush(wx.Brush("#e0f0f0"))
 118 
 119         for i in range(56, 784, 56):
 120             dc.DrawRectangle(0,  i, 794, 28)
 121 
 122         pen.SetCap(wx.CAP_BUTT)
 123         dc.SetPen(pen)
 124         dc.DrawLine(397, 56, 397, 756)
 125 
 126         pen.SetCap(wx.CAP_BUTT)
 127         dc.SetPen(pen)
 128         dc.DrawLine(0, 756, 794, 756)
 129 
 130         pen.SetCap(wx.CAP_BUTT)
 131         dc.SetPen(pen)
 132         dc.DrawLine(0, 56, 794, 56)
 133 
 134         dc.SetTextForeground("BLACK")
 135         dc.SetFont(wx.Font(24, wx.DEFAULT, wx.NORMAL, wx.BOLD))
 136         dc.DrawText("Python", 15, 8)
 137 
 138         pen.SetJoin(wx.JOIN_MITER)
 139         dc.SetPen(pen)
 140         dc.SetBrush(wx.TRANSPARENT_BRUSH)
 141         dc.DrawRectangle(0, 0, 794, 794)
 142 
 143         dc.SetPen(wx.Pen("RED", 1))
 144         dc.DrawRectangle(0, 0, 1000, 1000)
 145 
 146 #-------------------------------------------------------------------------------
 147 
 148 class My_Printout(wx.Printout):
 149     """
 150     Create a printout.
 151     """
 152     def __init__(self, canvas, text, title):
 153         wx.Printout.__init__(self, title)
 154 
 155         #------------
 156 
 157         self.canvas = canvas
 158         self.lines = text
 159 
 160     #---------------------------------------------------------------------------
 161 
 162     def OnBeginDocument(self, start, end):
 163         """
 164         ...
 165         """
 166 
 167         return super(My_Printout, self).OnBeginDocument(start, end)
 168 
 169 
 170     def OnEndDocument(self):
 171         """
 172         ...
 173         """
 174 
 175         super(My_Printout, self).OnEndDocument()
 176 
 177 
 178     def OnBeginPrinting(self):
 179         """
 180         ...
 181         """
 182 
 183         super(My_Printout, self).OnBeginPrinting()
 184 
 185 
 186     def OnEndPrinting(self):
 187         """
 188         ...
 189         """
 190 
 191         super(My_Printout, self).OnEndPrinting()
 192 
 193 
 194     def OnPreparePrinting(self):
 195         """
 196         ...
 197         """
 198 
 199         super(My_Printout, self).OnPreparePrinting()
 200 
 201 
 202     def HasPage(self, page):
 203         """
 204         ...
 205         """
 206 
 207         if page <= 2:
 208             return True
 209         else:
 210             return False
 211 
 212 
 213     def GetPageInfo(self):
 214         """
 215         ...
 216         """
 217 
 218         return (1, 2, 1, 2)
 219 
 220 
 221     def OnPrintPage(self, page):
 222         """
 223         ...
 224         """
 225 
 226         dc = self.GetDC()
 227 
 228         # (wx.MM_METRIC) ---> Each logical unit is 1 mm.
 229         # (wx.MM_POINTS) ---> Each logical unit is a "printer point" i.e.
 230         # dc.SetMapMode(wx.MM_POINTS)
 231 
 232         #------------
 233 
 234         # One possible method of setting scaling factors...
 235         maxX = self.canvas.GetWidth()
 236         maxY = self.canvas.GetHeight()
 237 
 238         #------------
 239 
 240         # Let's have at least 50 device units margin.
 241         marginX = 180
 242         marginY = 180
 243 
 244         #------------
 245 
 246         # Add the margin to the graphic size.
 247         maxX = maxX + (2 * marginX)
 248         maxY = maxY + (2 * marginY)
 249 
 250         #------------
 251 
 252         # Get the size of the DC in pixels.
 253         # (w, h) = dc.GetSizeTuple()
 254         (w, h) = dc.GetSize()
 255 
 256         # Calculate a suitable scaling factor.
 257         scaleX = float(w) / maxX
 258         scaleY = float(h) / maxY
 259 
 260         # Use x or y scaling factor, whichever fits on the DC.
 261         actualScale = min(scaleX, scaleY)
 262 
 263         # Calculate the position on the DC for centering the graphic.
 264         posX = (w - (self.canvas.GetWidth() * actualScale)) / 2.0
 265         posY = (h - (self.canvas.GetHeight() * actualScale)) / 2.0
 266 
 267         # Set the scale and origin.
 268         dc.SetUserScale(actualScale, actualScale)
 269         dc.SetDeviceOrigin(int(posX), int(posY))
 270 
 271         #------------
 272 
 273         self.canvas.DoDrawing(dc, True)
 274 
 275         #------------
 276 
 277         # Draw.
 278         dc.SetTextForeground("RED")
 279         dc.SetFont(wx.Font(17, wx.DEFAULT, wx.NORMAL, wx.NORMAL))
 280         dc.DrawText(self.lines, 6, 57)
 281         dc.DrawText(self.lines, 6, 85)
 282         dc.DrawText(self.lines, 6, 113)
 283         dc.DrawText(self.lines, 6, 141)
 284         dc.DrawText(self.lines, 6, 169)
 285         dc.DrawText(self.lines, 6, 197)
 286 
 287         dc.SetTextForeground("GRAY")
 288         dc.SetFont(wx.Font(32, wx.DEFAULT, wx.NORMAL, wx.BOLD))
 289         dc.DrawText(("wxPython sample :"), 0, -150)
 290 
 291         dc.SetTextForeground("BLACK")
 292         dc.SetFont(wx.Font(18, wx.DEFAULT, wx.NORMAL, wx.BOLD))
 293         dc.DrawText(("Page : %d") % page, int(marginX/2), int(maxY-marginY))
 294 
 295         tm = time.strftime(("Printing %a, %d %b %Y - %Hh%M"))
 296 
 297         dc.SetTextForeground("GRAY")
 298         dc.SetFont(wx.Font(16, wx.DEFAULT, wx.NORMAL, wx.NORMAL))
 299         dc.DrawText(tm, 10, 764)
 300 
 301         return True
 302 
 303 #-------------------------------------------------------------------------------
 304 
 305 class My_Frame(wx.Frame):
 306     """
 307     Create a main frame for my application.
 308     """
 309     def __init__(self, parent, id, title=""):
 310         wx.Frame.__init__(self,
 311                           parent,
 312                           id,
 313                           title,
 314                           size=(600, 367),
 315                           style=wx.DEFAULT_FRAME_STYLE)
 316 
 317         #------------
 318 
 319         # Simplified init method.
 320         self.SetProperties()
 321         self.CreateMenu()
 322         self.CreateCtrls()
 323         self.CreatePrintData()
 324         self.BindEvents()
 325         self.DoLayout()
 326 
 327         #------------
 328 
 329         self.CenterOnScreen()
 330 
 331     #---------------------------------------------------------------------------
 332 
 333     def SetProperties(self):
 334         """
 335         Set the main frame properties (title, icon...).
 336         """
 337 
 338         self.SetTitle("Printing test...")
 339 
 340 
 341     def CreateMenu(self):
 342         """
 343         Make the frame menus.
 344         """
 345 
 346         menub = wx.MenuBar()
 347 
 348         fmenu = wx.Menu()
 349         fmenu.Append(wx.ID_PAGE_SETUP, "Page set&up\tCtrl+U")
 350         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
 351         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
 352         fmenu.AppendSeparator()
 353         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
 354         menub.Append(fmenu, "&File")
 355 
 356         self.SetMenuBar(menub)
 357 
 358 
 359     def CreateCtrls(self):
 360         """
 361         Make widgets for my app.
 362         """
 363 
 364         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 365         font.SetWeight(wx.BOLD)
 366         font.SetPointSize(10)
 367 
 368         #------------
 369 
 370         # First create the controls.
 371         self.panel = wx.Panel(self,
 372                               id=-1,
 373                               style=wx.BORDER_THEME|
 374                               wx.TAB_TRAVERSAL)
 375 
 376         self.text = wx.StaticText(self.panel,
 377                                   id=-1,
 378                                   label="Demonstrating :")
 379         self.text.SetFont(font)
 380 
 381         self.info = wx.StaticText(self.panel,
 382                                   id=-1,
 383                                   label="1) Direct printing,\n"
 384                                         "2) Printout class,\n"
 385                                         "3) Canvas class,\n"
 386                                         "4) Preview,\n"
 387                                         "5) Menu,\n"
 388                                         "6) Page setup.")
 389         self.info.SetForegroundColour("red")
 390         font.SetWeight(wx.NORMAL)
 391         self.info.SetFont(font)
 392 
 393         self.tc = wx.TextCtrl(self.panel,
 394                               id=-1,
 395                               size=(200, -1),
 396                               value="Hello, World ! A sample text.")
 397 
 398         self.canvas = My_Canvas(self.panel, size=(0, 0))
 399 
 400         self.btnSetup = wx.Button(self.panel,
 401                                   id=wx.ID_PAGE_SETUP,
 402                                   label="Page set&up")
 403 
 404         self.btnPreview = wx.Button(self.panel,
 405                                     id=wx.ID_PREVIEW,
 406                                     label="Print pre&view")
 407         self.btnPreview.SetFocus()
 408 
 409         self.btnPrint = wx.Button(self.panel,
 410                                   id=wx.ID_PRINT,
 411                                   label="&Print")
 412 
 413         self.btnClose = wx.Button(self.panel,
 414                                   id=wx.ID_CLOSE,
 415                                   label="E&xit")
 416 
 417 
 418     def CreatePrintData(self):
 419         """
 420         Create printing data.
 421         """
 422 
 423         self.printdata = wx.PrintData()
 424 
 425         self.printdata.SetPrinterName('')
 426         self.printdata.SetOrientation(wx.PORTRAIT)
 427         self.printdata.SetPaperId(wx.PAPER_A4)
 428         self.printdata.SetQuality(wx.PRINT_QUALITY_DRAFT)
 429         # Black and white printing if False.
 430         self.printdata.SetColour(True)
 431         self.printdata.SetNoCopies(1)
 432         self.printdata.SetCollate(True)
 433         # self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)
 434 
 435 
 436     def BindEvents(self):
 437         """
 438         Bind all the events related to my application.
 439         """
 440 
 441         # Bind some menu events to an events handler.
 442         self.Bind(wx.EVT_MENU, self.OnBtnPageSetup, id=wx.ID_PAGE_SETUP)
 443         self.Bind(wx.EVT_MENU, self.OnBtnPreview, id=wx.ID_PREVIEW)
 444         self.Bind(wx.EVT_MENU, self.OnBtnPrint, id=wx.ID_PRINT)
 445         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 446 
 447         # Bind the close event to an event handler.
 448         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 449 
 450         # Bind some buttons events to an events handler.
 451         self.Bind(wx.EVT_BUTTON, self.OnBtnPageSetup, self.btnSetup)
 452         self.Bind(wx.EVT_BUTTON, self.OnBtnPreview, self.btnPreview)
 453         self.Bind(wx.EVT_BUTTON, self.OnBtnPrint, self.btnPrint)
 454         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 455 
 456 
 457     def DoLayout(self):
 458         """
 459         Manage widgets Layout.
 460         """
 461 
 462         # MainSizer is the top-level one that manages everything.
 463         mainSizer = wx.BoxSizer(wx.VERTICAL)
 464 
 465         #------------
 466 
 467         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 468         hBox1.Add(self.info, 0, wx.ALL, 15)
 469 
 470         #------------
 471 
 472         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 473         hBox2.Add(self.btnSetup, 0, wx.ALL, 10)
 474         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
 475         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
 476         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 477 
 478         #------------
 479 
 480         mainSizer.Add(self.text, 0, wx.ALL, 10)
 481         mainSizer.Add(wx.StaticLine(self.panel),
 482                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 483         mainSizer.Add(self.tc, 0, wx.ALL, 15)
 484         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 485         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 486 
 487         #------------
 488 
 489         # Finally, tell the panel to use the mainSizer for layout.
 490         self.panel.SetSizer(mainSizer)
 491 
 492 
 493     def OnBtnPageSetup(self, event):
 494         """
 495         Show the PrinterSetup dialog.
 496         """
 497 
 498         psdd = wx.PageSetupDialogData(self.printdata)
 499 
 500         psdd.EnablePrinter(True)
 501         # psdd.CalculatePaperSizeFromId()
 502 
 503         #------------
 504 
 505         dlg = wx.PageSetupDialog(self, psdd)
 506         dlg.ShowModal()
 507 
 508         #------------
 509 
 510         # This makes a copy of the wx.PrintData instead of just saving
 511         # a reference to the one inside the PrintDialogData that will
 512         # be destroyed when the dialog is destroyed
 513         self.printdata = wx.PrintData(dlg.GetPageSetupData().GetPrintData())
 514 
 515         dlg.Destroy()
 516 
 517 
 518     def OnBtnPreview(self, event):
 519         """
 520         Show the print preview.
 521         """
 522 
 523         text = self.tc.GetValue()
 524 
 525         #------------
 526 
 527         data = wx.PrintDialogData(self.printdata)
 528 
 529         printout1 = My_Printout(self.canvas, text, "- My printing object")
 530         printout2 = My_Printout(self.canvas, text, "- My printing object")
 531 
 532         printPreview = wx.PrintPreview(printout1, printout2, data)
 533 
 534         # Initial zoom value.
 535         if "__WXMAC__" in wx.PlatformInfo:
 536             printPreview.SetZoom(50)
 537         else:
 538             printPreview.SetZoom(35)
 539 
 540         if not printPreview.IsOk():
 541             wx.MessageBox(("There was a problem printing.\nPerhaps "\
 542                            "your current printer is \nnot "\
 543                            "set correctly ?"),
 544                           ("Printing"),
 545                           wx.OK)
 546             return
 547 
 548         else:
 549             previewFrame = wx.PreviewFrame(printPreview, None, "Print preview")
 550             previewFrame.Initialize()
 551             previewFrame.SetPosition(self.GetPosition())
 552             previewFrame.SetSize(self.GetSize())
 553             # Or full screen :
 554             # previewFrame.Maximize()
 555             previewFrame.Show(True)
 556             previewFrame.Layout()
 557 
 558 
 559     def OnBtnPrint(self, event):
 560         """
 561         Prints the document.
 562         """
 563 
 564         text = self.tc.GetValue()
 565 
 566         #------------
 567 
 568         pdd = wx.PrintDialogData(self.printdata)
 569         pdd.SetPrintData(self.printdata)
 570         pdd.SetMinPage(1)
 571         pdd.SetMaxPage(1)
 572         pdd.SetFromPage(1)
 573         pdd.SetToPage(1)
 574         pdd.SetPrintToFile(False)
 575         # pdd.SetSetupDialog(False)
 576         # pdd.EnableSelection(True)
 577         # pdd.EnablePrintToFile(True)
 578         # pdd.EnablePageNumbers(True)
 579         # pdd.SetAllPages(True)
 580 
 581         #------------
 582 
 583         printer = wx.Printer(pdd)
 584 
 585         myPrintout = My_Printout(self.canvas, text, "- My printing object")
 586 
 587         if not printer.Print(self, myPrintout, True):
 588             wx.MessageBox(("There was a problem printing.\nPerhaps "\
 589                            "your current printer is \nnot "\
 590                            "set correctly ?"),
 591                           ("Printing"),
 592                           wx.OK)
 593             return
 594 
 595         else:
 596             self.printData = wx.PrintData(printer.GetPrintDialogData().GetPrintData())
 597         myPrintout.Destroy()
 598 
 599 
 600     def OnBtnClose(self, event):
 601         """
 602         ...
 603         """
 604 
 605         self.Close(True)
 606 
 607 
 608     def OnCloseWindow(self, event):
 609         """
 610         ...
 611         """
 612 
 613         self.Destroy()
 614 
 615 #-------------------------------------------------------------------------------
 616 
 617 class My_App(wx.App):
 618     """
 619     ...
 620     """
 621     def OnInit(self):
 622 
 623         #------------
 624 
 625         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 626 
 627         #------------
 628 
 629         frame = My_Frame(None, id=-1)
 630         self.SetTopWindow(frame)
 631         frame.Show(True)
 632 
 633         return True
 634 
 635 #-------------------------------------------------------------------------------
 636 
 637 def main():
 638     app = My_App(False)
 639     app.MainLoop()
 640 
 641 #-------------------------------------------------------------------------------
 642 
 643 if __name__ == "__main__" :
 644     main()


Multiline printing

img_sample_four.png

   1 # sample_four.py
   2 
   3 #-------------------------------------------------------------------------------
   4 # Name:         printout.py
   5 # Purpose:      preview and printing class -> table/grid printing
   6 #
   7 # Author:       Lorne White (email: lorne.white@telusplanet.net)
   8 #
   9 # Created:
  10 # Version:      0.75
  11 # Date:         May 15, 2002
  12 # Licence:      wxWindows license
  13 #-------------------------------------------------------------------------------
  14 # Link:
  15 # https://raw.githubusercontent.com/wxWidgets/wxPython/master/wx/lib/printout.py
  16 #-------------------------------------------------------------------------------
  17 # Release Notes :
  18 # fixed bug for string wider than print region
  19 # add index to data list after parsing total pages for paging
  20 #-------------------------------------------------------------------------------
  21 # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net)
  22 # o 2.5 compatability update.
  23 #-------------------------------------------------------------------------------
  24 # 11/23/2004 - Vernon Cole (wnvcole@peppermillcas.com)
  25 # o Generalize for non-2-dimensional sequences and non-text data
  26 #   (can use as a simple text printer by supplying a list of strings.)
  27 # o Add a small _main_ for self test
  28 #-------------------------------------------------------------------------------
  29 
  30 import os
  31 import copy
  32 import wx
  33 
  34 # class PrintBase
  35 # class PrintTableDraw
  36 # class PrintTable
  37 # class PrintGrid
  38 # class SetPrintout
  39 # class Frame
  40 # class App
  41 
  42 #-------------------------------------------------------------------------------
  43 
  44 if os.name == "posix":
  45     print("\nPlatform : UNIX - Linux")
  46 elif os.name in ['nt', 'dos', 'ce']:
  47     print("\nPlatform : Windows")
  48 else:
  49     print("\nPlatform : ", platform.system())
  50 
  51 #-------------------------------------------------------------------------------
  52 
  53 class PrintBase(object):
  54     """
  55     ...
  56     """
  57     def SetPrintFont(self, font):      # set the DC font parameters
  58         fattr = font["Attr"]
  59         if fattr[0] == 1:
  60             weight = wx.BOLD
  61         else:
  62             weight = wx.NORMAL
  63 
  64         if fattr[1] == 1:
  65             set_style = wx.ITALIC
  66         else:
  67             set_style = wx.NORMAL
  68 
  69         underline = fattr[2]
  70         fcolour = self.GetFontColour(font)
  71         self.DC.SetTextForeground(fcolour)
  72 
  73         setfont = wx.Font(font["Size"], wx.SWISS, set_style, weight, underline)
  74         setfont.SetFaceName(font["Name"])
  75         self.DC.SetFont(setfont)
  76 
  77     #---------------------------------------------------------------------------
  78 
  79     def GetFontColour(self, font):
  80         fcolour = font["Colour"]
  81         return wx.Colour(fcolour[0], fcolour[1], fcolour[2])
  82 
  83 
  84     def OutTextRegion(self, textout, txtdraw = True):
  85         textlines = textout.split('\n')
  86         y = copy.copy(self.y) + self.pt_space_before
  87         for text in textlines:
  88             remain = 'X'
  89             while remain != "":
  90                 vout, remain = self.SetFlow(text, self.region)
  91                 if self.draw == True and txtdraw == True:
  92                     test_out = self.TestFull(vout)
  93                     if self.align == wx.ALIGN_LEFT:
  94                         self.DC.DrawText(test_out, int(self.indent+self.pcell_left_margin), int(y))
  95 
  96                     elif self.align == wx.ALIGN_CENTRE:
  97                         diff = self.GetCellDiff(test_out, self.region)
  98                         self.DC.DrawText(test_out, int(self.indent+diff/2), y)
  99 
 100                     elif self.align == wx.ALIGN_RIGHT:
 101                         diff = self.GetCellDiff(test_out, self.region)
 102                         self.DC.DrawText(test_out, int(self.indent+diff), y)
 103 
 104                     else:
 105                         self.DC.DrawText(test_out, int(self.indent+self.pcell_left_margin), int(y))
 106                 text = remain
 107                 y = y + self.space
 108         return y - self.space + self.pt_space_after
 109 
 110 
 111     def GetCellDiff(self, text, width):      # get the remaining cell size for adjustment
 112         w, h = self.DC.GetTextExtent(text)
 113         diff = width - w
 114         if diff < 0:
 115             diff = 0
 116         return diff
 117 
 118 
 119     def TestFull(self, text_test):
 120         w, h = self.DC.GetTextExtent(text_test)
 121         if w > self.region:     # trouble fitting into cell
 122             return self.SetChar(text_test, self.region)     # fit the text to the cell size
 123         else:
 124             return text_test
 125 
 126 
 127     def SetFlow(self, ln_text, width):
 128         width = width - self.pcell_right_margin
 129         text = ""
 130         split = ln_text.split()
 131         if len(split) == 1:
 132             return ln_text, ""
 133 
 134         try:
 135             w, h = self.DC.GetTextExtent(" " + split[0])
 136             if w >= width:
 137                 return ln_text, ""
 138         except:
 139             pass
 140 
 141         cnt = 0
 142         for word in split:
 143             bword = " " + word  # blank + word
 144             length = len(bword)
 145 
 146             w, h = self.DC.GetTextExtent(text + bword)
 147             if w < width:
 148                 text = text + bword
 149                 cnt = cnt + 1
 150             else:
 151                 remain = ' '.join(split[cnt:])
 152                 text = text.strip()
 153                 return text, remain
 154 
 155         remain = ' '.join(split[cnt:])
 156         vout = text.strip()
 157         return vout, remain
 158 
 159 
 160     def SetChar(self, ln_text, width):  # truncate string to fit into width
 161         width = width - self.pcell_right_margin - self.pcell_left_margin
 162         text = ""
 163         for val in ln_text:
 164             w, h = self.DC.GetTextExtent(text + val)
 165             if w > width:
 166                 text = text + ".."
 167                 return text     # fitted text value
 168             text = text + val
 169         return text
 170 
 171 
 172     def OutTextPageWidth(self, textout, y_out, align, indent, txtdraw = True):
 173         textlines = textout.split('\n')
 174         y = copy.copy(y_out)
 175 
 176         pagew = self.parent.page_width * self.pwidth        # full page width
 177         w, h = self.DC.GetTextExtent(textout)
 178         y_line = h
 179 
 180         for text in textlines:
 181             remain = 'X'
 182             while remain != "":
 183                 vout, remain = self.SetFlow(text, pagew)
 184                 if self.draw == True and txtdraw == True:
 185                     test_out = vout
 186                     if align == wx.ALIGN_LEFT:
 187                         self.DC.DrawText(test_out, indent, y)
 188 
 189                     elif align == wx.ALIGN_CENTRE:
 190                         diff = self.GetCellDiff(test_out, pagew)
 191                         self.DC.DrawText(test_out, int(indent+diff/2), int(y))
 192 
 193                     elif align == wx.ALIGN_RIGHT:
 194                         diff = self.GetCellDiff(test_out, pagew)
 195                         self.DC.DrawText(test_out, int(indent+diff), int(y))
 196 
 197                     else:
 198                         self.DC.DrawText(test_out, indent, y_out)
 199                 text = remain
 200                 y = y + y_line
 201         return y - y_line
 202 
 203 
 204     def GetDate(self):
 205         date, time = self.GetNow()
 206         return date
 207 
 208 
 209     def GetDateTime(self):
 210         date, time = self.GetNow()
 211         return date + ' ' + time
 212 
 213 
 214     def GetNow(self):
 215         now = wx.DateTime.Now()
 216         date = now.FormatDate()
 217         time = now.FormatTime()
 218         return date, time
 219 
 220 
 221     def SetPreview(self, preview):
 222         self.preview = preview
 223 
 224 
 225     def SetPSize(self, width, height):
 226         self.pwidth = width/self.scale
 227         self.pheight = height/self.scale
 228 
 229 
 230     def SetScale(self, scale):
 231         self.scale = scale
 232 
 233 
 234     def SetPTSize(self, width, height):
 235         self.ptwidth = width
 236         self.ptheight = height
 237 
 238 
 239     def getWidth(self):
 240         return self.sizew
 241 
 242 
 243     def getHeight(self):
 244         return self.sizeh
 245 
 246 #-------------------------------------------------------------------------------
 247 
 248 class PrintTableDraw(wx.ScrolledWindow, PrintBase):
 249     """
 250     ...
 251     """
 252     def __init__(self, parent, DC, size):
 253         self.parent = parent
 254         self.DC = DC
 255         self.scale = parent.scale
 256         self.width = size[0]
 257         self.height = size[1]
 258         self.SetDefaults()
 259 
 260     #---------------------------------------------------------------------------
 261 
 262     def SetDefaults(self):
 263         self.page = 1
 264         self.total_pages = None
 265 
 266         self.page_width = self.parent.page_width
 267         self.page_height = self.parent.page_height
 268 
 269         self.left_margin = self.parent.left_margin
 270         self.right_margin = self.parent.right_margin
 271 
 272         self.top_margin  = self.parent.top_margin
 273         self.bottom_margin = self.parent.bottom_margin
 274         self.cell_left_margin = self.parent.cell_left_margin
 275         self.cell_right_margin = self.parent.cell_right_margin
 276 
 277         self.label_colour = self.parent.label_colour
 278 
 279         self.row_line_colour = self.parent.row_line_colour
 280         self.row_line_size = self.parent.row_line_size
 281 
 282         self.row_def_line_colour = self.parent.row_def_line_colour
 283         self.row_def_line_size = self.parent.row_def_line_size
 284 
 285         self.column_line_colour = self.parent.column_line_colour
 286         self.column_line_size = self.parent.column_line_size
 287 
 288         self.column_def_line_size = self.parent.column_def_line_size
 289         self.column_def_line_colour = self.parent.column_def_line_colour
 290 
 291         self.text_font = self.parent.text_font
 292 
 293         self.label_font = self.parent.label_font
 294 
 295 
 296     def AdjustValues(self):
 297         self.vertical_offset = self.pheight * self.parent.vertical_offset
 298         self.horizontal_offset = self.pheight * self.parent.horizontal_offset
 299 
 300         self.pcell_left_margin = self.pwidth * self.cell_left_margin
 301         self.pcell_right_margin = self.pwidth * self.cell_right_margin
 302         self.ptop_margin = self.pheight * self.top_margin
 303         self.pbottom_margin = self.pheight * self.bottom_margin
 304 
 305         self.pheader_margin = self.pheight * self.parent.header_margin
 306         self.pfooter_margin = self.pheight * self.parent.footer_margin
 307 
 308         self.cell_colour = self.parent.set_cell_colour
 309         self.cell_text = self.parent.set_cell_text
 310 
 311         self.column = []
 312         self.column_align = []
 313         self.column_bgcolour = []
 314         self.column_txtcolour = []
 315 
 316         set_column_align = self.parent.set_column_align
 317         set_column_bgcolour = self.parent.set_column_bgcolour
 318         set_column_txtcolour = self.parent.set_column_txtcolour
 319 
 320         pos_x = self.left_margin * self.pwidth + self.horizontal_offset     # left margin
 321         self.column.append(pos_x)
 322 
 323         # Module logic expects two dimensional data -- fix input if needed
 324         if isinstance(self.data, str):
 325             self.data = [[copy.copy(self.data)]] # a string becomes a single cell
 326         try:
 327             rows = len(self.data)
 328         except TypeError:
 329             self.data = [[str(self.data)]] # a non-iterable becomes a single cell
 330             rows = 1
 331         first_value = self.data[0]
 332 
 333         if isinstance(first_value, str): # A sequence of strings
 334             if self.label == [] and self.set_column == []:
 335                 data = []
 336                 for x in self.data:     # Becomes one column
 337                     data.append([x])
 338             else:
 339                 data = [self.data]      # Becames one row
 340             self.data = data
 341             first_value = data[0]
 342         try:
 343             column_total = len(first_value)
 344         except TypeError:    # A sequence of non-iterables
 345             if self.label == [] and self.set_column == []:
 346                 data = []       # Becomes one column
 347                 for x in self.data:
 348                     data.append([str(x)])
 349                 column_total = 1
 350             else:
 351                 data = [self.data] # Becomes one row
 352                 column_total = len(self.data)
 353             self.data = data
 354             first_value = data[0]
 355 
 356         if self.set_column == []:
 357             table_width = self.page_width - self.left_margin - self.right_margin
 358             if self.label == []:
 359                 temp = first_value
 360             else:
 361                 temp = self.label
 362             width = table_width/(len(temp))
 363             for val in temp:
 364                 column_width = width * self.pwidth
 365                 pos_x = pos_x + column_width
 366                 self.column.append(pos_x)   # position of each column
 367         else:
 368             for val in self.set_column:
 369                 column_width = val * self.pwidth
 370                 pos_x = pos_x + column_width
 371                 self.column.append(pos_x)   # position of each column
 372 
 373         if pos_x > self.page_width * self.pwidth:    # check if it fits in page
 374             print("Warning, Too Wide for Page")
 375             return
 376 
 377         if self.label != []:
 378             if len(self.column) -1 != len(self.label):
 379                 print("Column Settings Incorrect", "\nColumn Value: " + str(self.column), "\nLabel Value: " + str(self.label))
 380                 return
 381 
 382         if column_total != len(self.column) -1:
 383             print("Cannot fit", first_value, 'in', len(self.column)-1, 'columns.')
 384             return
 385 
 386         for col in range(column_total):
 387             try:
 388                 align = set_column_align[col]       # check if custom column alignment
 389             except:
 390                 align = wx.ALIGN_LEFT
 391             self.column_align.append(align)
 392 
 393             try:
 394                 colour = set_column_bgcolour[col]     # check if custom column background colour
 395             except:
 396                 colour = self.parent.column_colour
 397             self.column_bgcolour.append(colour)
 398 
 399             try:
 400                 colour = set_column_txtcolour[col]     # check if custom column text colour
 401             except:
 402                 colour = self.GetFontColour(self.parent.text_font)
 403             self.column_txtcolour.append(colour)
 404 
 405 
 406     def SetPointAdjust(self):
 407         f = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)     # setup using 10 point
 408         self.DC.SetFont(f)
 409         f.SetFaceName(self.text_font["Name"])
 410         x, y = self.DC.GetTextExtent("W")
 411 
 412         self.label_pt_space_before = self.parent.label_pt_adj_before * y/10        # extra spacing for label per point value
 413         self.label_pt_space_after = self.parent.label_pt_adj_after * y/10
 414 
 415         self.text_pt_space_before = self.parent.text_pt_adj_before * y/10        # extra spacing for row text per point value
 416         self.text_pt_space_after = self.parent.text_pt_adj_after * y/10
 417 
 418 
 419     def SetPage(self, page):
 420         self.page = page
 421 
 422 
 423     def SetColumns(self, col):
 424         self.column = col
 425 
 426 
 427     def OutCanvas(self):
 428         self.AdjustValues()
 429         self.SetPointAdjust()
 430 
 431         self.y_start = self.ptop_margin + self.vertical_offset
 432         self.y_end = self.parent.page_height * self.pheight - self.pbottom_margin + self.vertical_offset
 433 
 434         self.SetPrintFont(self.label_font)
 435 
 436         x, y = self.DC.GetTextExtent("W")
 437         self.label_space = y
 438 
 439         self.SetPrintFont(self.text_font)
 440 
 441         x, y = self.DC.GetTextExtent("W")
 442         self.space = y
 443 
 444         if self.total_pages is None:
 445             self.GetTotalPages()    # total pages for display/printing
 446 
 447         self.data_cnt = self.page_index[self.page-1]
 448 
 449         self.draw = True
 450         self.PrintHeader()
 451         self.PrintFooter()
 452         self.OutPage()
 453 
 454 
 455     def GetTotalPages(self):
 456         self.data_cnt = 0
 457         self.draw = False
 458         self.page_index = [0]
 459 
 460         cnt = 0
 461         while 1:
 462             test = self.OutPage()
 463             self.page_index.append(self.data_cnt)
 464             if  test == False:
 465                 break
 466             cnt = cnt + 1
 467 
 468         self.total_pages = cnt + 1
 469 
 470 
 471     def OutPage(self):
 472         self.y = self.y_start
 473         self.end_x = self.column[-1]
 474 
 475         if self.data_cnt < len(self.data):  # if there data for display on the page
 476             if self.label != []:        # check if header defined
 477                 self.PrintLabel()
 478         else:
 479             return False
 480 
 481         for val in self.data:
 482             try:
 483                 row_val = self.data[self.data_cnt]
 484             except:
 485                 self.FinishDraw()
 486                 return False
 487 
 488             max_y = self.PrintRow(row_val, False)       # test to see if row will fit in remaining space
 489             test = max_y + self.space
 490 
 491             if test > self.y_end:
 492                 break
 493 
 494             self.ColourRowCells(max_y-self.y+self.space)       # colour the row/column
 495             max_y = self.PrintRow(row_val, True)      # row fits - print text
 496             self.DrawGridLine()     # top line of cell
 497             self.y = max_y + self.space
 498 
 499             if self.y > self.y_end:
 500                 break
 501 
 502             self.data_cnt = self.data_cnt + 1
 503 
 504         self.FinishDraw()
 505 
 506         if self.data_cnt == len(self.data):    # last value in list
 507             return False
 508 
 509         return True
 510 
 511 
 512     def PrintLabel(self):
 513         self.pt_space_before = self.label_pt_space_before   # set the point spacing
 514         self.pt_space_after = self.label_pt_space_after
 515 
 516         self.LabelColorRow(self.label_colour)
 517         self.SetPrintFont(self.label_font)
 518 
 519         self.col = 0
 520         max_y = 0
 521         for vtxt in self.label:
 522             self.region = self.column[self.col+1] - self.column[self.col]
 523             self.indent = self.column[self.col]
 524 
 525             self.align = wx.ALIGN_LEFT
 526 
 527             max_out = self.OutTextRegion(vtxt, True)
 528             if max_out > max_y:
 529                 max_y = max_out
 530             self.col = self.col + 1
 531 
 532         self.DrawGridLine()     # top line of label
 533         self.y = max_y + self.label_space
 534 
 535 
 536     def PrintHeader(self):      # print the header array
 537         if self.draw == False:
 538             return
 539 
 540         for val in self.parent.header:
 541             self.SetPrintFont(val["Font"])
 542 
 543             header_indent = val["Indent"] * self.pwidth
 544             text = val["Text"]
 545 
 546             htype = val["Type"]
 547             if htype == "Date":
 548                 addtext = self.GetDate()
 549             elif htype == "Date & Time":
 550                 addtext = self.GetDateTime()
 551             else:
 552                 addtext = ""
 553 
 554             self.OutTextPageWidth(text+addtext, self.pheader_margin, val["Align"], header_indent, True)
 555 
 556 
 557     def PrintFooter(self):      # print the header array
 558         if self.draw == False:
 559             return
 560 
 561         footer_pos = self.parent.page_height * self.pheight - self.pfooter_margin + self.vertical_offset
 562         for val in self.parent.footer:
 563             self.SetPrintFont(val["Font"])
 564 
 565             footer_indent = val["Indent"] * self.pwidth
 566             text = val["Text"]
 567 
 568             ftype = val["Type"]
 569             if ftype == "Pageof":
 570                 addtext = "Page " + str(self.page) + " of " + str(self.total_pages)
 571             elif ftype == "Page":
 572                 addtext = "Page " + str(self.page)
 573             elif ftype == "Num":
 574                 addtext = str(self.page)
 575             elif ftype == "Date":
 576                 addtext = self.GetDate()
 577             elif ftype == "Date & Time":
 578                 addtext = self.GetDateTime()
 579             else:
 580                 addtext = ""
 581 
 582             self.OutTextPageWidth(text+addtext, footer_pos, val["Align"], footer_indent, True)
 583 
 584 
 585     def LabelColorRow(self, colour):
 586         brush = wx.Brush(colour, wx.SOLID)
 587         self.DC.SetBrush(brush)
 588         height = self.label_space + self.label_pt_space_before + self.label_pt_space_after
 589         self.DC.DrawRectangle(self.column[0], self.y,
 590                               self.end_x-self.column[0]+1, height)
 591 
 592 
 593     def ColourRowCells(self, height):
 594         if self.draw == False:
 595             return
 596 
 597         col = 0
 598         for colour in self.column_bgcolour:
 599             cellcolour = self.GetCellColour(self.data_cnt, col)
 600             if cellcolour is not None:
 601                 colour = cellcolour
 602 
 603             brush = wx.Brush(colour, wx.SOLID)
 604             self.DC.SetBrush(brush)
 605             self.DC.SetPen(wx.Pen(wx.Colour('WHITE'), 0))
 606 
 607             start_x = self.column[col]
 608             width = self.column[col+1] - start_x + 2
 609             self.DC.DrawRectangle(int(start_x), int(self.y), int(width), int(height))
 610             col = col + 1
 611 
 612 
 613     def PrintRow(self, row_val, draw = True, align = wx.ALIGN_LEFT):
 614         self.SetPrintFont(self.text_font)
 615 
 616         self.pt_space_before = self.text_pt_space_before   # set the point spacing
 617         self.pt_space_after = self.text_pt_space_after
 618 
 619         self.col = 0
 620         max_y = 0
 621         for vtxt in row_val:
 622             if not isinstance(vtxt, str):
 623                 vtxt = str(vtxt)
 624             self.region = self.column[self.col+1] - self.column[self.col]
 625             self.indent = self.column[self.col]
 626             self.align = self.column_align[self.col]
 627 
 628             fcolour = self.column_txtcolour[self.col]       # set font colour
 629             celltext = self.GetCellTextColour(self.data_cnt, self.col)
 630             if celltext is not None:
 631                 fcolour = celltext      # override the column colour
 632 
 633             self.DC.SetTextForeground(fcolour)
 634 
 635             max_out = self.OutTextRegion(vtxt, draw)
 636             if max_out > max_y:
 637                 max_y = max_out
 638             self.col = self.col + 1
 639         return max_y
 640 
 641 
 642     def GetCellColour(self, row, col):      # check if custom colour defined for the cell background
 643         try:
 644             set = self.cell_colour[row]
 645         except:
 646             return None
 647         try:
 648             colour = set[col]
 649             return colour
 650         except:
 651             return None
 652 
 653 
 654     def GetCellTextColour(self, row, col):      # check if custom colour defined for the cell text
 655         try:
 656             set = self.cell_text[row]
 657         except:
 658             return None
 659         try:
 660             colour = set[col]
 661             return colour
 662         except:
 663             return None
 664 
 665 
 666     def FinishDraw(self):
 667         self.DrawGridLine()     # draw last row line
 668         self.DrawColumns()      # draw all vertical lines
 669 
 670 
 671     def DrawGridLine(self):
 672         if self.draw == True \
 673         and len(self.column) > 2:    #supress grid lines if only one column
 674             try:
 675                 size = self.row_line_size[self.data_cnt]
 676             except:
 677                 size = self.row_def_line_size
 678 
 679             if size < 1: return
 680 
 681             try:
 682                 colour = self.row_line_colour[self.data_cnt]
 683             except:
 684                 colour = self.row_def_line_colour
 685 
 686             self.DC.SetPen(wx.Pen(colour, size))
 687 
 688             y_out = self.y
 689             #y_out = self.y + self.pt_space_before + self.pt_space_after     # adjust for extra spacing
 690             self.DC.DrawLine(self.column[0], y_out, self.end_x, y_out)
 691 
 692 
 693     def DrawColumns(self):
 694         if self.draw == True \
 695         and len(self.column) > 2:   #surpress grid line if only one column
 696             col = 0
 697             for val in self.column:
 698                 try:
 699                     size = self.column_line_size[col]
 700                 except:
 701                     size = self.column_def_line_size
 702 
 703                 if size < 1: continue
 704 
 705                 try:
 706                     colour = self.column_line_colour[col]
 707                 except:
 708                     colour = self.column_def_line_colour
 709 
 710                 indent = val
 711 
 712                 self.DC.SetPen(wx.Pen(colour, size))
 713                 self.DC.DrawLine(indent, self.y_start, indent, self.y)
 714                 col = col + 1
 715 
 716 
 717     def DrawText(self):
 718         self.DoRefresh()
 719 
 720 
 721     def DoDrawing(self, DC):
 722         size = DC.GetSize()
 723         self.DC = DC
 724 
 725         self.DrawText()
 726 
 727         self.sizew = DC.MaxY()
 728         self.sizeh = DC.MaxX()
 729 
 730 #-------------------------------------------------------------------------------
 731 
 732 class PrintTable(object):
 733     """
 734     ...
 735     """
 736     def __init__(self, parentFrame=None):
 737         self.data = []
 738         self.set_column = []
 739         self.label = []
 740         self.header = []
 741         self.footer = []
 742 
 743         self.set_column_align = {}
 744         self.set_column_bgcolour = {}
 745         self.set_column_txtcolour = {}
 746         self.set_cell_colour = {}
 747         self.set_cell_text = {}
 748         self.column_line_size = {}
 749         self.column_line_colour = {}
 750         self.row_line_size = {}
 751         self.row_line_colour = {}
 752 
 753         self.parentFrame = parentFrame
 754         self.SetPreviewSize()
 755 
 756         self.printData = wx.PrintData()
 757         self.scale = 1.0
 758 
 759         self.SetParms()
 760         self.SetColors()
 761         self.SetFonts()
 762         self.TextSpacing()
 763 
 764         self.SetPrinterOffset()
 765         self.SetHeaderValue()
 766         self.SetFooterValue()
 767         self.SetMargins()
 768         self.SetPortrait()
 769 
 770     #---------------------------------------------------------------------------
 771 
 772     def SetPreviewSize(self, position = wx.Point(0, 0), size="Full"):
 773         if size == "Full":
 774             r = wx.GetClientDisplayRect()
 775             self.preview_frame_size = r.GetSize()
 776             self.preview_frame_pos = r.GetPosition()
 777         else:
 778             self.preview_frame_size = size
 779             self.preview_frame_pos = position
 780 
 781 
 782     def SetPaperId(self, paper):
 783         self.printData.SetPaperId(paper)
 784 
 785 
 786     def SetOrientation(self, orient):
 787         self.printData.SetOrientation(orient)
 788 
 789 
 790     def SetColors(self):
 791         self.row_def_line_colour = wx.Colour('BLACK')
 792         self.row_def_line_size = 1
 793 
 794         self.column_def_line_colour = wx.Colour('BLACK')
 795         self.column_def_line_size = 1
 796         self.column_colour = wx.Colour('WHITE')
 797 
 798         self.label_colour = wx.Colour('LIGHT GREY')
 799 
 800 
 801     def SetFonts(self):
 802         self.label_font = { "Name": self.default_font_name, "Size": 12, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 803         self.text_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 804 
 805 
 806     def TextSpacing(self):
 807         self.label_pt_adj_before = 0     # point adjustment before and after the label text
 808         self.label_pt_adj_after = 0
 809 
 810         self.text_pt_adj_before = 0     # point adjustment before and after the row text
 811         self.text_pt_adj_after = 0
 812 
 813 
 814     def SetLabelSpacing(self, before, after):        # method to set the label space adjustment
 815         self.label_pt_adj_before = before
 816         self.label_pt_adj_after = after
 817 
 818 
 819     def SetRowSpacing(self, before, after):         # method to set the row space adjustment
 820         self.text_pt_adj_before = before
 821         self.text_pt_adj_after = after
 822 
 823 
 824     def SetPrinterOffset(self):        # offset to adjust for printer
 825         self.vertical_offset = -0.1
 826         self.horizontal_offset = -0.1
 827 
 828 
 829     def SetHeaderValue(self):
 830         self.header_margin = 0.25
 831         self.header_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 832         self.header_align = wx.ALIGN_CENTRE
 833         self.header_indent = 0
 834         self.header_type = "Text"
 835 
 836 
 837     def SetFooterValue(self):
 838         self.footer_margin = 0.7
 839         self.footer_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 840         self.footer_align = wx.ALIGN_CENTRE
 841         self.footer_indent = 0
 842         self.footer_type = "Pageof"
 843 
 844 
 845     def SetMargins(self):
 846         self.left_margin = 0.5
 847         self.right_margin = 0.5    # only used if no column sizes
 848 
 849         self.top_margin  = 0.8
 850         self.bottom_margin = 1.0
 851         self.cell_left_margin = 0.1
 852         self.cell_right_margin = 0.1
 853 
 854 
 855     def SetPortrait(self):
 856         self.printData.SetPaperId(wx.PAPER_LETTER)
 857         self.printData.SetOrientation(wx.PORTRAIT)
 858         self.page_width = 8.5
 859         self.page_height = 11.0
 860 
 861 
 862     def SetLandscape(self):
 863         self.printData.SetOrientation(wx.LANDSCAPE)
 864         self.page_width = 11.0
 865         self.page_height = 8.5
 866 
 867 
 868     def SetParms(self):
 869         self.ymax = 1
 870         self.xmax = 1
 871         self.page = 1
 872         self.total_pg = 100
 873 
 874         self.preview = None
 875         self.page = 0
 876 
 877         self.default_font_name = "Arial"
 878         self.default_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 879 
 880 
 881     def SetColAlignment(self, col, align=wx.ALIGN_LEFT):
 882         self.set_column_align[col] = align
 883 
 884 
 885     def SetColBackgroundColour(self, col, colour):
 886         self.set_column_bgcolour[col] = colour
 887 
 888 
 889     def SetColTextColour(self, col, colour):
 890         self.set_column_txtcolour[col] = colour
 891 
 892 
 893     def SetCellColour(self, row, col, colour):      # cell background colour
 894         try:
 895             set = self.set_cell_colour[row]     # test if row already exists
 896             try:
 897                 set[col] = colour       # test if column already exists
 898             except:
 899                 set = { col: colour }       # create the column value
 900         except:
 901             set = { col: colour }           # create the column value
 902 
 903         self.set_cell_colour[row] = set    # create dictionary item for colour settings
 904 
 905 
 906     def SetCellText(self, row, col, colour):        # font colour for custom cells
 907         try:
 908             set = self.set_cell_text[row]     # test if row already exists
 909             try:
 910                 set[col] = colour       # test if column already exists
 911             except:
 912                 set = { col: colour }       # create the column value
 913         except:
 914             set = { col: colour }           # create the column value
 915 
 916         self.set_cell_text[row] = set    # create dictionary item for colour settings
 917 
 918 
 919     def SetColumnLineSize(self, col, size):      # column line size
 920         self.column_line_size[col] = size    # create dictionary item for column line settings
 921 
 922 
 923     def SetColumnLineColour(self, col, colour):
 924         self.column_line_colour[col] = colour
 925 
 926 
 927     def SetRowLineSize(self, row, size):
 928         self.row_line_size[row] = size
 929 
 930 
 931     def SetRowLineColour(self, row, colour):
 932         self.row_line_colour[row] = colour
 933 
 934 
 935     def GetColour(self, colour):        # returns colours based from wxColour value
 936         red = colour.Red()
 937         blue = colour.Blue()
 938         green = colour.Green()
 939         return [red, green, blue ]
 940 
 941 
 942     def SetHeader(self, text = "", type = "Text", font=None, align = None, indent = None, colour = None, size = None):
 943         set = { "Text": text }
 944 
 945         if font is None:
 946             set["Font"] = copy.copy(self.default_font)
 947         else:
 948             set["Font"] = font
 949 
 950         if colour is not None:
 951             setfont = set["Font"]
 952             setfont["Colour"] = self.GetColour(colour)
 953 
 954         if size is not None:
 955             setfont = set["Font"]
 956             setfont["Size"] = size
 957 
 958         if align is None:
 959             set["Align"] = self.header_align
 960         else:
 961             set["Align"] = align
 962 
 963         if indent is None:
 964             set["Indent"] = self.header_indent
 965         else:
 966             set["Indent"] = indent
 967 
 968         if type is None:
 969             set["Type"] = self.header_type
 970         else:
 971             set["Type"] = type
 972 
 973         self.header.append(set)
 974 
 975 
 976     def SetFooter(self, text = "", type = None, font=None, align = None, indent = None, colour = None, size = None):
 977         set = { "Text": text }
 978 
 979         if font is None:
 980             set["Font"] = copy.copy(self.default_font)
 981         else:
 982             set["Font"] = font
 983 
 984         if colour is not None:
 985             setfont = set["Font"]
 986             setfont["Colour"] = self.GetColour(colour)
 987 
 988         if size is not None:
 989             setfont = set["Font"]
 990             setfont["Size"] = size
 991 
 992         if align is None:
 993             set["Align"] = self.footer_align
 994         else:
 995             set["Align"] = align
 996 
 997         if indent is None:
 998             set["Indent"] = self.footer_indent
 999         else:
1000             set["Indent"] = indent
1001 
1002         if type is None:
1003             set["Type"] = self.footer_type
1004         else:
1005             set["Type"] = type
1006 
1007         self.footer.append(set)
1008 
1009 
1010     def Preview(self):
1011         data = wx.PrintDialogData(self.printData)
1012 
1013         text = self.parentFrame.tc.GetValue()
1014 
1015         printout = SetPrintout(self, text)
1016         printout2 = SetPrintout(self, text)
1017         self.preview = wx.PrintPreview(printout, printout2, data)
1018         if not self.preview.IsOk():
1019             wx.MessageBox("There was a problem printing!", "Printing", wx.OK)
1020             return
1021 
1022         self.preview.SetZoom(60)        # initial zoom value
1023         frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview")
1024 
1025         frame.Initialize()
1026         if self.parentFrame:
1027             frame.SetPosition(self.preview_frame_pos)
1028             frame.SetSize(self.preview_frame_size)
1029         frame.Show(True)
1030 
1031 
1032     def Print(self):
1033         pdd = wx.PrintDialogData(self.printData)
1034         printer = wx.Printer(pdd)
1035 
1036         text = self.parentFrame.tc.GetValue()
1037 
1038         printout = SetPrintout(self, text)
1039         if not printer.Print(self.parentFrame, printout):
1040             if wx.Printer.GetLastError() == wx.PRINTER_ERROR:
1041                 wx.MessageBox("There was a problem printing.\n"
1042                               "Perhaps your current printer is not set correctly?",
1043                               "Printing", wx.OK)
1044         else:
1045             self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
1046         printout.Destroy()
1047 
1048 
1049     def DoDrawing(self, DC):
1050         size = DC.GetSize()
1051 
1052         table = PrintTableDraw(self, DC, size)
1053         table.data = self.data
1054         table.set_column = self.set_column
1055         table.label = self.label
1056         table.SetPage(self.page)
1057 
1058         if self.preview is None:
1059             table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1060             table.SetPTSize(size[0], size[1])
1061             table.SetPreview(False)
1062         else:
1063             if self.preview == 1:
1064                 table.scale = self.scale
1065                 table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1066             else:
1067                 table.SetPSize(self.pwidth, self.pheight)
1068 
1069             table.SetPTSize(self.ptwidth, self.ptheight)
1070             table.SetPreview(self.preview)
1071 
1072         table.OutCanvas()
1073         self.page_total = table.total_pages     # total display pages
1074 
1075         self.ymax = DC.MaxY()
1076         self.xmax = DC.MaxX()
1077 
1078         self.sizeh = size[0]
1079         self.sizew = size[1]
1080 
1081 
1082     def GetTotalPages(self):
1083         self.page_total = 100
1084         return self.page_total
1085 
1086 
1087     def HasPage(self, page):
1088         if page <= self.page_total:
1089             return True
1090         else:
1091             return False
1092 
1093 
1094     def SetPage(self, page):
1095         self.page = page
1096 
1097 
1098     def SetPageSize(self, width, height):
1099         self.pwidth, self.pheight = width, height
1100 
1101 
1102     def SetTotalSize(self, width, height):
1103         self.ptwidth, self.ptheight = width, height
1104 
1105 
1106     def SetPreview(self, preview, scale):
1107         self.preview = preview
1108         self.scale = scale
1109 
1110 
1111     def SetTotalSize(self, width, height):
1112         self.ptwidth = width
1113         self.ptheight = height
1114 
1115 #-------------------------------------------------------------------------------
1116 
1117 class PrintGrid(object):
1118     """
1119     ...
1120     """
1121     def __init__(self, parent, grid, format = [], total_col = None, total_row = None):
1122         if total_row is None:
1123             total_row = grid.GetNumberRows()
1124         if total_col is None:
1125             total_col = grid.GetNumberCols()
1126 
1127         self.total_row = total_row
1128         self.total_col = total_col
1129         self.grid = grid
1130 
1131         data = []
1132         for row in range(total_row):
1133             row_val = []
1134             value = grid.GetRowLabelValue(row)
1135             row_val.append(value)
1136 
1137             for col in range(total_col):
1138                 value = grid.GetCellValue(row, col)
1139                 row_val.append(value)
1140             data.append(row_val)
1141 
1142         label = [""]
1143         for col in range(total_col):
1144             value = grid.GetColLabelValue(col)
1145             label.append(value)
1146 
1147         self.table = PrintTable(parent)
1148         self.table.cell_left_margin = 0.0
1149         self.table.cell_right_margin = 0.0
1150 
1151         self.table.label = label
1152         self.table.set_column = format
1153         self.table.data = data
1154 
1155     #---------------------------------------------------------------------------
1156 
1157     def GetTable(self):
1158         return self.table
1159 
1160 
1161     def SetAttributes(self):
1162         for row in range(self.total_row):
1163             for col in range(self.total_col):
1164                 colour = self.grid.GetCellTextColour(row, col-1)
1165                 self.table.SetCellText(row, col, colour)
1166 
1167                 colour = self.grid.GetCellBackgroundColour(row, col-1)
1168                 self.table.SetCellColour(row, col, colour)
1169 
1170 
1171     def Preview(self):
1172         self.table.Preview()
1173 
1174 
1175     def Print(self):
1176         self.table.Print()
1177 
1178 #-------------------------------------------------------------------------------
1179 
1180 class SetPrintout(wx.Printout):
1181     """
1182     ...
1183     """
1184     def __init__(self, canvas, text):
1185         wx.Printout.__init__(self)
1186 
1187         self.canvas = canvas
1188         self.end_pg = 1000
1189         self.lines = text
1190 
1191     #---------------------------------------------------------------------------
1192 
1193     def OnBeginDocument(self, start, end):
1194         return super(SetPrintout, self).OnBeginDocument(start, end)
1195 
1196 
1197     def OnEndDocument(self):
1198         super(SetPrintout, self).OnEndDocument()
1199 
1200 
1201     def HasPage(self, page):
1202         try:
1203             end = self.canvas.HasPage(page)
1204             return end
1205         except:
1206             return True
1207 
1208 
1209     def GetPageInfo(self):
1210         try:
1211             self.end_pg = self.canvas.GetTotalPages()
1212         except:
1213             pass
1214 
1215         end_pg = self.end_pg
1216         str_pg = 1
1217         return (str_pg, end_pg, str_pg, end_pg)
1218 
1219 
1220     def OnPreparePrinting(self):
1221         super(SetPrintout, self).OnPreparePrinting()
1222 
1223 
1224     def OnBeginPrinting(self):
1225         dc = self.GetDC()
1226 
1227         self.preview = self.IsPreview()
1228         if (self.preview):
1229             self.pixelsPerInch = self.GetPPIScreen()
1230         else:
1231             self.pixelsPerInch = self.GetPPIPrinter()
1232 
1233         (w, h) = dc.GetSize()
1234         scaleX = float(w) / 1000
1235         scaleY = float(h) / 1000
1236         self.printUserScale = min(scaleX, scaleY)
1237 
1238         super(SetPrintout, self).OnBeginPrinting()
1239 
1240 
1241     def GetSize(self):
1242         self.psizew, self.psizeh = self.GetPPIPrinter()
1243         return self.psizew, self.psizeh
1244 
1245 
1246     def GetTotalSize(self):
1247         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1248         return self.ptsizew, self.ptsizeh
1249 
1250 
1251     def OnPrintPage(self, page):
1252         dc = self.GetDC()
1253         (w, h) = dc.GetSize()
1254         scaleX = float(w) / 1000
1255         scaleY = float(h) / 1000
1256         self.printUserScale = min(scaleX, scaleY)
1257         dc.SetUserScale(self.printUserScale, self.printUserScale)
1258 
1259         self.preview = self.IsPreview()
1260 
1261         self.canvas.SetPreview(self.preview, self.printUserScale)
1262         self.canvas.SetPage(page)
1263 
1264         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1265         self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh)
1266 
1267         self.psizew, self.psizeh = self.GetPPIPrinter()
1268         self.canvas.SetPageSize(self.psizew, self.psizeh)
1269 
1270         self.canvas.DoDrawing(dc)
1271         return True
1272 
1273 #-------------------------------------------------------------------------------
1274 
1275 class Frame(wx.Frame):
1276     """
1277     ...
1278     """
1279     def __init__(self, parent, id, title=""):
1280         wx.Frame.__init__(self,
1281                           parent,
1282                           id,
1283                           title,
1284                           size=(600, 450),
1285                           style=wx.DEFAULT_FRAME_STYLE)
1286 
1287         #------------
1288 
1289         # Simplified init method.
1290         self.SetProperties()
1291         self.CreateMenu()
1292         self.CreateCtrls()
1293         self.CreatePrintData()
1294         self.BindEvents()
1295         self.DoLayout()
1296 
1297         #------------
1298 
1299         self.CenterOnScreen()
1300 
1301     #---------------------------------------------------------------------------
1302 
1303     def SetProperties(self):
1304         """
1305         Set the main frame properties (title, icon...).
1306         """
1307 
1308         self.SetTitle("Dummy wx frame for testing printout.py")
1309 
1310 
1311     def CreateMenu(self):
1312         """
1313         ...
1314         """
1315 
1316         menub = wx.MenuBar()
1317 
1318         fmenu = wx.Menu()
1319         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
1320         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
1321         fmenu.AppendSeparator()
1322         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
1323         menub.Append(fmenu, "&File")
1324 
1325         self.SetMenuBar(menub)
1326 
1327 
1328     def CreateCtrls(self):
1329         """
1330         ...
1331         """
1332 
1333         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1334         font.SetWeight(wx.BOLD)
1335         font.SetPointSize(10)
1336 
1337         #------------
1338 
1339         # First create the controls.
1340         self.panel = wx.Panel(self, -1,
1341                               style=wx.BORDER_THEME|
1342                               wx.TAB_TRAVERSAL)
1343 
1344         self.demo = wx.StaticText(self.panel,
1345                                   id=-1,
1346                                   label="Demonstrating :")
1347         self.demo.SetFont(font)
1348 
1349         self.info = wx.StaticText(self.panel,
1350                                   id=-1,
1351                                   label="1) Direct printing,\n"
1352                                         "2) Printout class,\n"
1353                                         "3) PrintTable class,\n"
1354                                         "4) Preview,\n"
1355                                         "5) Menu")
1356         self.info.SetForegroundColour("red")
1357         font.SetWeight(wx.NORMAL)
1358         self.info.SetFont(font)
1359 
1360         text = ('This the first line of text.\n'\
1361                 'This is the second line\nand the third. The fourth will be the number 4.0.\n'\
1362                 '4.0\n'\
1363                 'This is the fifth line, but by design it is too long to fit in the width of a standard'\
1364                 'page, so it will be forced to wrap around in order to fit without having'\
1365                 'some of its verbose verbage truncated.\n'\
1366                 'Here we have the final line.')
1367 
1368         self.tc = wx.TextCtrl(self.panel,
1369                               id=-1,
1370                               size=(200, -1),
1371                               value=text,
1372                               style=wx.TE_MULTILINE|wx.TE_DONTWRAP)
1373 
1374         self.btnPreview = wx.Button(self.panel,
1375                                     id=wx.ID_PREVIEW,
1376                                     label="Print pre&view")
1377         self.btnPreview.SetFocus()
1378 
1379         self.btnPrint = wx.Button(self.panel,
1380                                   id=wx.ID_PRINT,
1381                                   label="&Print")
1382 
1383         self.btnClose = wx.Button(self.panel,
1384                                   id=wx.ID_CLOSE,
1385                                   label="E&xit")
1386 
1387 
1388     def CreatePrintData(self):
1389         """
1390         Create printing data.
1391         """
1392 
1393         self.ptbl = PrintTable(self)
1394         self.ptbl.SetHeader('This is the test HEADER')
1395         self.ptbl.SetFooter()
1396 
1397         #------------
1398 
1399         # a single sequence will print out as a single column with no borders ...
1400         self.ptbl.data = (self.tc.GetValue())
1401 
1402 
1403     def BindEvents(self):
1404         """
1405         Bind all the events related to my application.
1406         """
1407 
1408         # Bind some menu events to an events handler.
1409         self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
1410         self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
1411         self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
1412 
1413         # Bind the close event to an event handler.
1414         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1415 
1416         # Bind some buttons events to an events handler.
1417         self.Bind(wx.EVT_BUTTON, self.OnPrintPreview, self.btnPreview)
1418         self.Bind(wx.EVT_BUTTON, self.OnPrint, self.btnPrint)
1419         self.Bind(wx.EVT_BUTTON, self.OnClose, self.btnClose)
1420 
1421 
1422     def DoLayout(self):
1423         """
1424         Manage widgets Layout.
1425         """
1426 
1427         # MainSizer is the top-level one that manages everything.
1428         mainSizer = wx.BoxSizer(wx.VERTICAL)
1429 
1430         #------------
1431 
1432         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
1433         hBox1.Add(self.info, 0, wx.ALL, 15)
1434 
1435         #------------
1436 
1437         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
1438         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
1439         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
1440         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
1441 
1442         #------------
1443 
1444         mainSizer.Add(self.demo, 0, wx.ALL, 10)
1445         mainSizer.Add(wx.StaticLine(self.panel),
1446                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
1447         mainSizer.Add(self.tc, 1, wx.EXPAND | wx.ALL, 15)
1448         mainSizer.Add(hBox1, 0, wx.ALL, 5)
1449         mainSizer.Add(hBox2, 0, wx.ALL, 5)
1450 
1451         #------------
1452 
1453         # Finally, tell the panel to use the mainSizer for layout.
1454         self.panel.SetSizer(mainSizer)
1455 
1456 
1457     def OnPrintPreview(self, event):
1458         self.ptbl.data = (self.tc.GetValue())
1459         self.ptbl.Preview()
1460 
1461 
1462     def OnPrint(self, event):
1463         self.ptbl.data = (self.tc.GetValue())
1464         self.ptbl.Print()
1465 
1466 
1467     def OnClose(self, evt):
1468         self.Close()
1469 
1470 
1471     def OnCloseWindow(self, event):
1472         """
1473         ...
1474         """
1475 
1476         self.Destroy()
1477 
1478 #-------------------------------------------------------------------------------
1479 
1480 class App(wx.App):
1481     """
1482     ...
1483     """
1484     def OnInit(self):
1485 
1486         #------------
1487 
1488         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
1489 
1490         #------------
1491 
1492         frame = Frame(None, id=-1)
1493         self.SetTopWindow(frame)
1494         frame.Show(True)
1495 
1496         return True
1497 
1498 #-------------------------------------------------------------------------------
1499 
1500 def main():
1501     app = App(False)
1502     app.MainLoop()
1503 
1504 #-------------------------------------------------------------------------------
1505 
1506 if __name__ == "__main__" :
1507     main()


Grid Printing :

First example

img_sample_five_a.png

   1 # sample_five_a.py
   2 
   3 #-------------------------------------------------------------------------------
   4 # Name:         printout.py
   5 # Purpose:      preview and printing class -> table/grid printing
   6 #
   7 # Author:       Lorne White (email: lorne.white@telusplanet.net)
   8 #
   9 # Created:
  10 # Version:      0.75
  11 # Date:         May 15, 2002
  12 # Licence:      wxWindows license
  13 #-------------------------------------------------------------------------------
  14 # Link:
  15 # https://raw.githubusercontent.com/wxWidgets/wxPython/master/wx/lib/printout.py
  16 #-------------------------------------------------------------------------------
  17 # Release Notes :
  18 # fixed bug for string wider than print region
  19 # add index to data list after parsing total pages for paging
  20 #-------------------------------------------------------------------------------
  21 # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net)
  22 # o 2.5 compatability update.
  23 #-------------------------------------------------------------------------------
  24 # 11/23/2004 - Vernon Cole (wnvcole@peppermillcas.com)
  25 # o Generalize for non-2-dimensional sequences and non-text data
  26 #   (can use as a simple text printer by supplying a list of strings.)
  27 # o Add a small _main_ for self test
  28 #-------------------------------------------------------------------------------
  29 
  30 import os
  31 import copy
  32 import wx
  33 from   wx import grid
  34 
  35 # class PrintBase
  36 # class PrintTableDraw
  37 # class PrintTable
  38 # class PrintGrid
  39 # class SetPrintout
  40 # class Frame
  41 # class App
  42 
  43 #-------------------------------------------------------------------------------
  44 
  45 if os.name == "posix":
  46     print("\nPlatform : UNIX - Linux")
  47 elif os.name in ['nt', 'dos', 'ce']:
  48     print("\nPlatform : Windows")
  49 else:
  50     print("\nPlatform : ", platform.system())
  51 
  52 #-------------------------------------------------------------------------------
  53 
  54 class PrintBase(object):
  55     """
  56     ...
  57     """
  58     def SetPrintFont(self, font):      # set the DC font parameters
  59         fattr = font["Attr"]
  60         if fattr[0] == 1:
  61             weight = wx.BOLD
  62         else:
  63             weight = wx.NORMAL
  64 
  65         if fattr[1] == 1:
  66             set_style = wx.ITALIC
  67         else:
  68             set_style = wx.NORMAL
  69 
  70         underline = fattr[2]
  71         fcolour = self.GetFontColour(font)
  72         self.DC.SetTextForeground(fcolour)
  73 
  74         setfont = wx.Font(font["Size"], wx.SWISS, set_style, weight, underline)
  75         setfont.SetFaceName(font["Name"])
  76         self.DC.SetFont(setfont)
  77 
  78     #---------------------------------------------------------------------------
  79 
  80     def GetFontColour(self, font):
  81         fcolour = font["Colour"]
  82         return wx.Colour(fcolour[0], fcolour[1], fcolour[2])
  83 
  84 
  85     def OutTextRegion(self, textout, txtdraw = True):
  86         textlines = textout.split('\n')
  87         y = copy.copy(self.y) + self.pt_space_before
  88         for text in textlines:
  89             remain = 'X'
  90             while remain != "":
  91                 vout, remain = self.SetFlow(text, self.region)
  92                 if self.draw == True and txtdraw == True:
  93                     test_out = self.TestFull(vout)
  94                     if self.align == wx.ALIGN_LEFT:
  95                         self.DC.DrawText(test_out, int(self.indent+self.pcell_left_margin), int(y))
  96 
  97                     elif self.align == wx.ALIGN_CENTRE:
  98                         diff = self.GetCellDiff(test_out, self.region)
  99                         self.DC.DrawText(test_out, self.indent+diff/2, y)
 100 
 101                     elif self.align == wx.ALIGN_RIGHT:
 102                         diff = self.GetCellDiff(test_out, self.region)
 103                         self.DC.DrawText(test_out, self.indent+diff, y)
 104 
 105                     else:
 106                         self.DC.DrawText(test_out, int(self.indent+self.pcell_left_margin), int(y))
 107                 text = remain
 108                 y = y + self.space
 109         return y - self.space + self.pt_space_after
 110 
 111 
 112     def GetCellDiff(self, text, width):      # get the remaining cell size for adjustment
 113         w, h = self.DC.GetTextExtent(text)
 114         diff = width - w
 115         if diff < 0:
 116             diff = 0
 117         return diff
 118 
 119 
 120     def TestFull(self, text_test):
 121         w, h = self.DC.GetTextExtent(text_test)
 122         if w > self.region:     # trouble fitting into cell
 123             return self.SetChar(text_test, self.region)     # fit the text to the cell size
 124         else:
 125             return text_test
 126 
 127 
 128     def SetFlow(self, ln_text, width):
 129         width = width - self.pcell_right_margin
 130         text = ""
 131         split = ln_text.split()
 132         if len(split) == 1:
 133             return ln_text, ""
 134 
 135         try:
 136             w, h = self.DC.GetTextExtent(" " + split[0])
 137             if w >= width:
 138                 return ln_text, ""
 139         except:
 140             pass
 141 
 142         cnt = 0
 143         for word in split:
 144             bword = " " + word  # blank + word
 145             length = len(bword)
 146 
 147             w, h = self.DC.GetTextExtent(text + bword)
 148             if w < width:
 149                 text = text + bword
 150                 cnt = cnt + 1
 151             else:
 152                 remain = ' '.join(split[cnt:])
 153                 text = text.strip()
 154                 return text, remain
 155 
 156         remain = ' '.join(split[cnt:])
 157         vout = text.strip()
 158         return vout, remain
 159 
 160 
 161     def SetChar(self, ln_text, width):  # truncate string to fit into width
 162         width = width - self.pcell_right_margin - self.pcell_left_margin
 163         text = ""
 164         for val in ln_text:
 165             w, h = self.DC.GetTextExtent(text + val)
 166             if w > width:
 167                 text = text + ".."
 168                 return text     # fitted text value
 169             text = text + val
 170         return text
 171 
 172 
 173     def OutTextPageWidth(self, textout, y_out, align, indent, txtdraw = True):
 174         textlines = textout.split('\n')
 175         y = copy.copy(y_out)
 176 
 177         pagew = self.parent.page_width * self.pwidth        # full page width
 178         w, h = self.DC.GetTextExtent(textout)
 179         y_line = h
 180 
 181         for text in textlines:
 182             remain = 'X'
 183             while remain != "":
 184                 vout, remain = self.SetFlow(text, pagew)
 185                 if self.draw == True and txtdraw == True:
 186                     test_out = vout
 187                     if align == wx.ALIGN_LEFT:
 188                         self.DC.DrawText(test_out, indent, y)
 189 
 190                     elif align == wx.ALIGN_CENTRE:
 191                         diff = self.GetCellDiff(test_out, pagew)
 192                         self.DC.DrawText(test_out, int(indent+diff/2), int(y))
 193 
 194                     elif align == wx.ALIGN_RIGHT:
 195                         diff = self.GetCellDiff(test_out, pagew)
 196                         self.DC.DrawText(test_out, int(indent+diff), int(y))
 197 
 198                     else:
 199                         self.DC.DrawText(test_out, indent, y_out)
 200                 text = remain
 201                 y = y + y_line
 202         return y - y_line
 203 
 204 
 205     def GetDate(self):
 206         date, time = self.GetNow()
 207         return date
 208 
 209 
 210     def GetDateTime(self):
 211         date, time = self.GetNow()
 212         return '%s %s' % (date, time)
 213 
 214 
 215     def GetNow(self):
 216         now = wx.DateTime.Now()
 217         date = now.FormatDate()
 218         time = now.FormatTime()
 219         return date, time
 220 
 221 
 222     def SetPreview(self, preview):
 223         self.preview = preview
 224 
 225 
 226     def SetPSize(self, width, height):
 227         self.pwidth = width/self.scale
 228         self.pheight = height/self.scale
 229 
 230 
 231     def SetScale(self, scale):
 232         self.scale = scale
 233 
 234 
 235     def SetPTSize(self, width, height):
 236         self.ptwidth = width
 237         self.ptheight = height
 238 
 239 
 240     def getWidth(self):
 241         return self.sizew
 242 
 243 
 244     def getHeight(self):
 245         return self.sizeh
 246 
 247 #-------------------------------------------------------------------------------
 248 
 249 class PrintTableDraw(wx.ScrolledWindow, PrintBase):
 250     """
 251     ...
 252     """
 253     def __init__(self, parent, DC, size, colLabels=True):
 254         self.parent = parent
 255         self.DC = DC
 256         self.scale = parent.scale
 257         self.width = size[0]
 258         self.height = size[1]
 259         self.colLabels = colLabels
 260         self.SetDefaults()
 261 
 262     #---------------------------------------------------------------------------
 263 
 264     def SetDefaults(self):
 265         self.page = 1
 266         self.total_pages = None
 267 
 268         self.page_width = self.parent.page_width
 269         self.page_height = self.parent.page_height
 270 
 271         self.left_margin = self.parent.left_margin
 272         self.right_margin = self.parent.right_margin
 273 
 274         self.top_margin  = self.parent.top_margin
 275         self.bottom_margin = self.parent.bottom_margin
 276         self.cell_left_margin = self.parent.cell_left_margin
 277         self.cell_right_margin = self.parent.cell_right_margin
 278 
 279         self.label_colour = self.parent.label_colour
 280 
 281         self.row_line_colour = self.parent.row_line_colour
 282         self.row_line_size = self.parent.row_line_size
 283 
 284         self.row_def_line_colour = self.parent.row_def_line_colour
 285         self.row_def_line_size = self.parent.row_def_line_size
 286 
 287         self.column_line_colour = self.parent.column_line_colour
 288         self.column_line_size = self.parent.column_line_size
 289 
 290         self.column_def_line_size = self.parent.column_def_line_size
 291         self.column_def_line_colour = self.parent.column_def_line_colour
 292 
 293         self.text_font = self.parent.text_font
 294 
 295         self.label_font = self.parent.label_font
 296 
 297 
 298     def AdjustValues(self):
 299         self.vertical_offset = self.pheight * self.parent.vertical_offset
 300         self.horizontal_offset = self.pheight * self.parent.horizontal_offset
 301 
 302         self.pcell_left_margin = self.pwidth * self.cell_left_margin
 303         self.pcell_right_margin = self.pwidth * self.cell_right_margin
 304         self.ptop_margin = self.pheight * self.top_margin
 305         self.pbottom_margin = self.pheight * self.bottom_margin
 306 
 307         self.pheader_margin = self.pheight * self.parent.header_margin
 308         self.pfooter_margin = self.pheight * self.parent.footer_margin
 309 
 310         self.cell_colour = self.parent.set_cell_colour
 311         self.cell_text = self.parent.set_cell_text
 312 
 313         self.column = []
 314         self.column_align = []
 315         self.column_bgcolour = []
 316         self.column_txtcolour = []
 317 
 318         set_column_align = self.parent.set_column_align
 319         set_column_bgcolour = self.parent.set_column_bgcolour
 320         set_column_txtcolour = self.parent.set_column_txtcolour
 321 
 322         pos_x = self.left_margin * self.pwidth + self.horizontal_offset     # left margin
 323         self.column.append(pos_x)
 324 
 325         # Module logic expects two dimensional data -- fix input if needed
 326         if isinstance(self.data, str):
 327             self.data = [[copy.copy(self.data)]] # a string becomes a single cell
 328         try:
 329             rows = len(self.data)
 330         except TypeError:
 331             self.data = [[str(self.data)]] # a non-iterable becomes a single cell
 332             rows = 1
 333         first_value = self.data[0]
 334 
 335         if isinstance(first_value, str): # A sequence of strings
 336             if self.label == [] and self.set_column == []:
 337                 data = []
 338                 for x in self.data:     # Becomes one column
 339                     data.append([x])
 340             else:
 341                 data = [self.data]      # Becames one row
 342             self.data = data
 343             first_value = data[0]
 344         try:
 345             column_total = len(first_value)
 346         except TypeError:    # a sequence of non-iterables
 347             if self.label == [] and self.set_column == []:
 348                 data = []       #becomes one column
 349                 for x in self.data:
 350                     data.append([str(x)])
 351                 column_total = 1
 352             else:
 353                 data = [self.data] #becomes one row
 354                 column_total = len(self.data)
 355             self.data = data
 356             first_value = data[0]
 357 
 358         if self.set_column == []:
 359             table_width = self.page_width - self.left_margin - self.right_margin
 360             if self.label == []:
 361                 temp = first_value
 362             else:
 363                 temp = self.label
 364             width = table_width/(len(temp))
 365             for val in temp:
 366                 column_width = width * self.pwidth
 367                 pos_x = pos_x + column_width
 368                 self.column.append(pos_x)   # position of each column
 369         else:
 370             for val in self.set_column:
 371                 column_width = val
 372                 pos_x = pos_x + column_width
 373                 self.column.append(pos_x)   # position of each column
 374 
 375         if pos_x > self.page_width * self.pwidth:    # check if it fits in page
 376             print("Warning, Too Wide for Page")
 377             print(pos_x, self.page_width * self.pwidth)
 378             return
 379 
 380         if self.label != []:
 381             if len(self.column) -1 != len(self.label):
 382                 print("Column Settings Incorrect", "\nColumn Value: " + str(self.column), "\nLabel Value: " + str(self.label))
 383                 return
 384 
 385         if column_total != len(self.column) -1:
 386             print("Cannot fit", first_value, 'in', len(self.column)-1, 'columns.')
 387             return
 388 
 389         for col in range(column_total):
 390             try:
 391                 align = set_column_align[col]       # check if custom column alignment
 392             except:
 393                 align = wx.ALIGN_LEFT
 394             self.column_align.append(align)
 395 
 396             try:
 397                 colour = set_column_bgcolour[col]     # check if custom column background colour
 398             except:
 399                 colour = self.parent.column_colour
 400             self.column_bgcolour.append(colour)
 401 
 402             try:
 403                 colour = set_column_txtcolour[col]     # check if custom column text colour
 404             except:
 405                 colour = self.GetFontColour(self.parent.text_font)
 406             self.column_txtcolour.append(colour)
 407 
 408 
 409     def SetPointAdjust(self):
 410         f = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)     # setup using 10 point
 411         self.DC.SetFont(f)
 412         f.SetFaceName(self.text_font["Name"])
 413         x, y = self.DC.GetTextExtent("W")
 414 
 415         self.label_pt_space_before = self.parent.label_pt_adj_before * y/10        # extra spacing for label per point value
 416         self.label_pt_space_after = self.parent.label_pt_adj_after * y/10
 417 
 418         self.text_pt_space_before = self.parent.text_pt_adj_before * y/10        # extra spacing for row text per point value
 419         self.text_pt_space_after = self.parent.text_pt_adj_after * y/10
 420 
 421 
 422     def SetPage(self, page):
 423         self.page = page
 424 
 425 
 426     def SetColumns(self, col):
 427         self.column = col
 428 
 429 
 430     def OutCanvas(self):
 431         self.AdjustValues()
 432         self.SetPointAdjust()
 433 
 434         self.y_start = self.ptop_margin + self.vertical_offset
 435         self.y_end = self.parent.page_height * self.pheight - self.pbottom_margin + self.vertical_offset
 436 
 437         self.SetPrintFont(self.label_font)
 438 
 439         x, y = self.DC.GetTextExtent("W")
 440         self.label_space = y
 441 
 442         self.SetPrintFont(self.text_font)
 443 
 444         x, y = self.DC.GetTextExtent("W")
 445         self.space = y
 446 
 447         if self.total_pages is None:
 448             self.GetTotalPages()    # total pages for display/printing
 449 
 450         self.data_cnt = self.page_index[self.page-1]
 451 
 452         self.draw = True
 453         self.PrintHeader()
 454         self.PrintFooter()
 455         self.OutPage()
 456 
 457 
 458     def GetTotalPages(self):
 459         self.data_cnt = 0
 460         self.draw = False
 461         self.page_index = [0]
 462 
 463         cnt = 0
 464         while 1:
 465             test = self.OutPage()
 466             self.page_index.append(self.data_cnt)
 467             if  test == False:
 468                 break
 469             cnt = cnt + 1
 470 
 471         self.total_pages = cnt + 1
 472 
 473 
 474     def OutPage(self):
 475         self.y = self.y_start
 476         self.end_x = self.column[-1]
 477 
 478         if self.data_cnt < len(self.data):  # if there data for display on the page
 479             if self.colLabels and self.label != []:        # check if header defined
 480                 self.PrintLabel()
 481         else:
 482             return False
 483 
 484         for val in self.data:
 485             try:
 486                 row_val = self.data[self.data_cnt]
 487             except:
 488                 self.FinishDraw()
 489                 return False
 490 
 491             max_y = self.PrintRow(row_val, False)       # test to see if row will fit in remaining space
 492             test = max_y + self.space
 493 
 494             if test > self.y_end:
 495                 break
 496 
 497             self.ColourRowCells(max_y-self.y+self.space)       # colour the row/column
 498             max_y = self.PrintRow(row_val, True)      # row fits - print text
 499             self.DrawGridLine()     # top line of cell
 500             self.y = max_y + self.space
 501 
 502             if self.y > self.y_end:
 503                 break
 504 
 505             self.data_cnt = self.data_cnt + 1
 506 
 507         self.FinishDraw()
 508 
 509         if self.data_cnt == len(self.data):    # last value in list
 510             return False
 511 
 512         return True
 513 
 514 
 515     def PrintLabel(self):
 516         self.pt_space_before = self.label_pt_space_before   # set the point spacing
 517         self.pt_space_after = self.label_pt_space_after
 518 
 519         self.LabelColorRow(self.label_colour)
 520         self.SetPrintFont(self.label_font)
 521 
 522         self.col = 0
 523         max_y = 0
 524         for vtxt in self.label:
 525             self.region = self.column[self.col+1] - self.column[self.col]
 526             self.indent = self.column[self.col]
 527 
 528             self.align = wx.ALIGN_LEFT
 529 
 530             max_out = self.OutTextRegion(vtxt, True)
 531             if max_out > max_y:
 532                 max_y = max_out
 533             self.col = self.col + 1
 534 
 535         self.DrawGridLine()     # top line of label
 536         self.y = max_y + self.label_space
 537 
 538 
 539     def PrintHeader(self):      # print the header array
 540         if self.draw == False:
 541             return
 542 
 543         for val in self.parent.header:
 544             self.SetPrintFont(val["Font"])
 545 
 546             header_indent = val["Indent"] * self.pwidth
 547             text = val["Text"]
 548 
 549             htype = val["Type"]
 550             if htype == "Date":
 551                 addtext = self.GetDate()
 552             elif htype == "Date & Time":
 553                 addtext = self.GetDateTime()
 554             else:
 555                 addtext = ""
 556 
 557             self.OutTextPageWidth(text+addtext, self.pheader_margin, val["Align"], header_indent, True)
 558 
 559 
 560     def PrintFooter(self):      # print the header array
 561         if self.draw == False:
 562             return
 563 
 564         footer_pos = self.parent.page_height * self.pheight - self.pfooter_margin + self.vertical_offset
 565         for val in self.parent.footer:
 566             self.SetPrintFont(val["Font"])
 567 
 568             footer_indent = val["Indent"] * self.pwidth
 569             text = val["Text"]
 570 
 571             ftype = val["Type"]
 572             if ftype == "Pageof":
 573                 addtext = "Page " + str(self.page) + " of " + str(self.total_pages)
 574             elif ftype == "Page":
 575                 addtext = "Page " + str(self.page)
 576             elif ftype == "Num":
 577                 addtext = str(self.page)
 578             elif ftype == "Date":
 579                 addtext = self.GetDate()
 580             elif ftype == "Date & Time":
 581                 addtext = self.GetDateTime()
 582             else:
 583                 addtext = ""
 584 
 585             self.OutTextPageWidth(text+addtext, footer_pos, val["Align"], footer_indent, True)
 586 
 587 
 588     def LabelColorRow(self, colour):
 589         brush = wx.Brush(colour, wx.SOLID)
 590         self.DC.SetBrush(brush)
 591         height = self.label_space + self.label_pt_space_before + self.label_pt_space_after
 592         self.DC.DrawRectangle(self.column[0], self.y,
 593                               self.end_x-self.column[0]+1, height)
 594 
 595     def ColourRowCells(self, height):
 596         if self.draw == False:
 597             return
 598 
 599         col = 0
 600         for colour in self.column_bgcolour:
 601             cellcolour = self.GetCellColour(self.data_cnt, col)
 602             if cellcolour is not None:
 603                 colour = cellcolour
 604 
 605             brush = wx.Brush(colour, wx.SOLID)
 606             self.DC.SetBrush(brush)
 607             self.DC.SetPen(wx.Pen(wx.Colour('WHITE'), 0))
 608 
 609             start_x = self.column[col]
 610             width = self.column[col+1] - start_x + 2
 611             self.DC.DrawRectangle(int(start_x), int(self.y), int(width), int(height))
 612             col = col + 1
 613 
 614 
 615     def PrintRow(self, row_val, draw = True, align = wx.ALIGN_LEFT):
 616         self.SetPrintFont(self.text_font)
 617 
 618         self.pt_space_before = self.text_pt_space_before   # set the point spacing
 619         self.pt_space_after = self.text_pt_space_after
 620 
 621         self.col = 0
 622         max_y = 0
 623         for vtxt in row_val:
 624             if not isinstance(vtxt, str):
 625                 vtxt = str(vtxt)
 626             self.region = self.column[self.col+1] - self.column[self.col]
 627             self.indent = self.column[self.col]
 628             try:
 629                 self.align = self.column_align[self.col]
 630             except IndexError:
 631                 self.align = wx.ALIGN_LEFT
 632 
 633             try:
 634                 fcolour = self.column_txtcolour[self.col]       # set font colour
 635             except IndexError:
 636                 fcolour = wx.BLACK
 637 
 638             celltext = self.GetCellTextColour(self.data_cnt, self.col)
 639             if celltext is not None:
 640                 fcolour = celltext      # override the column colour
 641 
 642             self.DC.SetTextForeground(fcolour)
 643 
 644             max_out = self.OutTextRegion(vtxt, draw)
 645             if max_out > max_y:
 646                 max_y = max_out
 647             self.col = self.col + 1
 648         return max_y
 649 
 650 
 651     def GetCellColour(self, row, col):      # check if custom colour defined for the cell background
 652         try:
 653             set = self.cell_colour[row]
 654         except:
 655             return None
 656         try:
 657             colour = set[col]
 658             return colour
 659         except:
 660             return None
 661 
 662 
 663     def GetCellTextColour(self, row, col):      # check if custom colour defined for the cell text
 664         try:
 665             set = self.cell_text[row]
 666         except:
 667             return None
 668         try:
 669             colour = set[col]
 670             return colour
 671         except:
 672             return None
 673 
 674 
 675     def FinishDraw(self):
 676         self.DrawGridLine()     # draw last row line
 677         self.DrawColumns()      # draw all vertical lines
 678 
 679 
 680     def DrawGridLine(self):
 681         if self.draw == True \
 682         and len(self.column) > 2:    #supress grid lines if only one column
 683             try:
 684                 size = self.row_line_size[self.data_cnt]
 685             except:
 686                 size = self.row_def_line_size
 687 
 688             if size < 1: return
 689 
 690             try:
 691                 colour = self.row_line_colour[self.data_cnt]
 692             except:
 693                 colour = self.row_def_line_colour
 694 
 695             self.DC.SetPen(wx.Pen(colour, size))
 696 
 697             y_out = self.y
 698             #y_out = self.y + self.pt_space_before + self.pt_space_after     # adjust for extra spacing
 699             self.DC.DrawLine(int(self.column[0]), int(y_out), int(self.end_x), int(y_out))
 700 
 701 
 702     def DrawColumns(self):
 703         if self.draw == True \
 704         and len(self.column) > 2:   #surpress grid line if only one column
 705             col = 0
 706             for val in self.column:
 707                 try:
 708                     size = self.column_line_size[col]
 709                 except:
 710                     size = self.column_def_line_size
 711 
 712                 if size < 1: continue
 713 
 714                 try:
 715                     colour = self.column_line_colour[col]
 716                 except:
 717                     colour = self.column_def_line_colour
 718 
 719                 indent = val
 720 
 721                 self.DC.SetPen(wx.Pen(colour, size))
 722                 self.DC.DrawLine(int(indent), int(self.y_start), int(indent), int(self.y))
 723                 col = col + 1
 724 
 725 
 726     def DrawText(self):
 727         self.DoRefresh()
 728 
 729 
 730     def DoDrawing(self, DC):
 731         size = DC.GetSize()
 732         self.DC = DC
 733 
 734         self.DrawText()
 735 
 736         self.sizew = DC.MaxY()
 737         self.sizeh = DC.MaxX()
 738 
 739 #-------------------------------------------------------------------------------
 740 
 741 class PrintTable(object):
 742     """
 743     ...
 744     """
 745     def __init__(self, parentFrame=None, rowLabels=True, colLabels=True):
 746         self.data = []
 747         self.set_column = []
 748         self.label = []
 749         self.header = []
 750         self.footer = []
 751         self.rowLabels = rowLabels
 752         self.colLabels = colLabels
 753 
 754         self.set_column_align = {}
 755         self.set_column_bgcolour = {}
 756         self.set_column_txtcolour = {}
 757         self.set_cell_colour = {}
 758         self.set_cell_text = {}
 759         self.column_line_size = {}
 760         self.column_line_colour = {}
 761         self.row_line_size = {}
 762         self.row_line_colour = {}
 763 
 764         self.parentFrame = parentFrame
 765         self.SetPreviewSize()
 766 
 767         self.printData = wx.PrintData()
 768         self.scale = 1.0
 769 
 770         self.SetParms()
 771         self.SetColors()
 772         self.SetFonts()
 773         self.TextSpacing()
 774 
 775         self.SetPrinterOffset()
 776         self.SetHeaderValue()
 777         self.SetFooterValue()
 778         self.SetMargins()
 779         self.SetPortrait()
 780 
 781     #---------------------------------------------------------------------------
 782 
 783     def SetPreviewSize(self, position = wx.Point(0, 0), size="Full"):
 784         if size == "Full":
 785             r = wx.GetClientDisplayRect()
 786             self.preview_frame_size = r.GetSize()
 787             self.preview_frame_pos = r.GetPosition()
 788         else:
 789             self.preview_frame_size = size
 790             self.preview_frame_pos = position
 791 
 792 
 793     def SetPaperId(self, paper):
 794         self.printData.SetPaperId(paper)
 795 
 796 
 797     def SetOrientation(self, orient):
 798         self.printData.SetOrientation(orient)
 799 
 800 
 801     def SetColors(self):
 802         self.row_def_line_colour = wx.Colour('BLACK')
 803         self.row_def_line_size = 1
 804 
 805         self.column_def_line_colour = wx.Colour('BLACK')
 806         self.column_def_line_size = 1
 807         self.column_colour = wx.Colour('WHITE')
 808 
 809         self.label_colour = wx.Colour('LIGHT GREY')
 810 
 811 
 812     def SetFonts(self):
 813         self.label_font = {"Name": self.default_font_name,
 814                            "Size": 12,
 815                            "Colour": [0, 0, 0],
 816                            "Attr": [0, 0, 0]
 817                            }
 818         self.text_font = {"Name": self.default_font_name,
 819                           "Size": 10,
 820                           "Colour": [0, 0, 0],
 821                           "Attr": [0, 0, 0]
 822                           }
 823 
 824 
 825     def TextSpacing(self):
 826         self.label_pt_adj_before = 0     # point adjustment before and after the label text
 827         self.label_pt_adj_after = 0
 828 
 829         self.text_pt_adj_before = 0     # point adjustment before and after the row text
 830         self.text_pt_adj_after = 0
 831 
 832 
 833     def SetLabelSpacing(self, before, after):        # method to set the label space adjustment
 834         self.label_pt_adj_before = before
 835         self.label_pt_adj_after = after
 836 
 837 
 838     def SetRowSpacing(self, before, after):         # method to set the row space adjustment
 839         self.text_pt_adj_before = before
 840         self.text_pt_adj_after = after
 841 
 842 
 843     def SetPrinterOffset(self):        # offset to adjust for printer
 844         self.vertical_offset = -0.1
 845         self.horizontal_offset = -0.1
 846 
 847 
 848     def SetHeaderValue(self):
 849         self.header_margin = 0.25
 850         self.header_font = {"Name": self.default_font_name,
 851                             "Size": 11,
 852                             "Colour": [0, 0, 0],
 853                             "Attr": [0, 0, 0]
 854                             }
 855         self.header_align = wx.ALIGN_CENTRE
 856         self.header_indent = 0
 857         self.header_type = "Text"
 858 
 859 
 860     def SetFooterValue(self):
 861         self.footer_margin = 0.7
 862         self.footer_font = {"Name": self.default_font_name,
 863                             "Size": 11,
 864                             "Colour": [0, 0, 0],
 865                             "Attr": [0, 0, 0]
 866                             }
 867         self.footer_align = wx.ALIGN_CENTRE
 868         self.footer_indent = 0
 869         self.footer_type = "Pageof"
 870 
 871 
 872     def SetMargins(self):
 873         self.left_margin = 0.5
 874         self.right_margin = 0.5    # only used if no column sizes
 875 
 876         self.top_margin  = 0.8
 877         self.bottom_margin = 1.0
 878         self.cell_left_margin = 0.1
 879         self.cell_right_margin = 0.1
 880 
 881 
 882     def SetPortrait(self):
 883         self.printData.SetPaperId(wx.PAPER_A4)
 884         self.printData.SetOrientation(wx.PORTRAIT)
 885         self.page_width = 8.267716535433071
 886         self.page_height = 11.69291338582677
 887 
 888 
 889     def SetLandscape(self):
 890         self.printData.SetOrientation(wx.LANDSCAPE)
 891         self.page_width = 8.267716535433071
 892         self.page_height = 11.69291338582677
 893 
 894 
 895     def SetParms(self):
 896         self.ymax = 1
 897         self.xmax = 1
 898         self.page = 1
 899         self.total_pg = 100
 900 
 901         self.preview = None
 902         self.page = 0
 903 
 904         self.default_font_name = "Arial"
 905         self.default_font = {"Name": self.default_font_name,
 906                              "Size": 10,
 907                              "Colour": [0, 0, 0],
 908                              "Attr": [0, 0, 0]
 909                              }
 910 
 911 
 912     def SetColAlignment(self, col, align=wx.ALIGN_LEFT):
 913         self.set_column_align[col] = align
 914 
 915 
 916     def SetColBackgroundColour(self, col, colour):
 917         self.set_column_bgcolour[col] = colour
 918 
 919 
 920     def SetColTextColour(self, col, colour):
 921         self.set_column_txtcolour[col] = colour
 922 
 923 
 924     def SetCellColour(self, row, col, colour):      # cell background colour
 925         try:
 926             set = self.set_cell_colour[row]     # test if row already exists
 927             try:
 928                 set[col] = colour       # test if column already exists
 929             except:
 930                 set = { col: colour }       # create the column value
 931         except:
 932             set = { col: colour }           # create the column value
 933 
 934         self.set_cell_colour[row] = set    # create dictionary item for colour settings
 935 
 936 
 937     def SetCellText(self, row, col, colour):        # font colour for custom cells
 938         try:
 939             set = self.set_cell_text[row]     # test if row already exists
 940             try:
 941                 set[col] = colour       # test if column already exists
 942             except:
 943                 set = { col: colour }       # create the column value
 944         except:
 945             set = { col: colour }           # create the column value
 946 
 947         self.set_cell_text[row] = set    # create dictionary item for colour settings
 948 
 949 
 950     def SetColumnLineSize(self, col, size):      # column line size
 951         self.column_line_size[col] = size    # create dictionary item for column line settings
 952 
 953 
 954     def SetColumnLineColour(self, col, colour):
 955         self.column_line_colour[col] = colour
 956 
 957 
 958     def SetRowLineSize(self, row, size):
 959         self.row_line_size[row] = size
 960 
 961 
 962     def SetRowLineColour(self, row, colour):
 963         self.row_line_colour[row] = colour
 964 
 965 
 966     def GetColour(self, colour):        # returns colours based from wxColour value
 967         red = colour.Red()
 968         blue = colour.Blue()
 969         green = colour.Green()
 970         return [red, green, blue ]
 971 
 972 
 973     def SetHeader(self, text="", type="Text", font=None, align=None,
 974                   indent=None, colour=None, size=None):
 975         set = {"Text": text}
 976 
 977         if font is None:
 978             set["Font"] = copy.copy(self.default_font)
 979         else:
 980             set["Font"] = font
 981 
 982         if colour is not None:
 983             setfont = set["Font"]
 984             setfont["Colour"] = self.GetColour(colour)
 985 
 986         if size is not None:
 987             setfont = set["Font"]
 988             setfont["Size"] = size
 989 
 990         if align is None:
 991             set["Align"] = self.header_align
 992         else:
 993             set["Align"] = align
 994 
 995         if indent is None:
 996             set["Indent"] = self.header_indent
 997         else:
 998             set["Indent"] = indent
 999 
1000         if type is None:
1001             set["Type"] = self.header_type
1002         else:
1003             set["Type"] = type
1004 
1005         self.header.append(set)
1006 
1007 
1008     def SetFooter(self, text="", type=None, font=None, align=None,
1009                   indent=None, colour=None, size=None):
1010         set = { "Text": text }
1011 
1012         if font is None:
1013             set["Font"] = copy.copy(self.default_font)
1014         else:
1015             set["Font"] = font
1016 
1017         if colour is not None:
1018             setfont = set["Font"]
1019             setfont["Colour"] = self.GetColour(colour)
1020 
1021         if size is not None:
1022             setfont = set["Font"]
1023             setfont["Size"] = size
1024 
1025         if align is None:
1026             set["Align"] = self.footer_align
1027         else:
1028             set["Align"] = align
1029 
1030         if indent is None:
1031             set["Indent"] = self.footer_indent
1032         else:
1033             set["Indent"] = indent
1034 
1035         if type is None:
1036             set["Type"] = self.footer_type
1037         else:
1038             set["Type"] = type
1039 
1040         self.footer.append(set)
1041 
1042 
1043     def Preview(self):
1044         data = wx.PrintDialogData(self.printData)
1045         printout = SetPrintout(self)
1046         printout2 = SetPrintout(self)
1047         self.preview = wx.PrintPreview(printout, printout2, data)
1048         if not self.preview.IsOk():
1049             wx.MessageBox("There was a problem printing!", "Printing", wx.OK)
1050             return
1051 
1052         self.preview.SetZoom(85)        # initial zoom value
1053         frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview")
1054 
1055         frame.Initialize()
1056         if self.parentFrame:
1057             frame.SetPosition(self.preview_frame_pos)
1058             frame.SetSize(self.preview_frame_size)
1059         frame.Show(True)
1060 
1061 
1062     def Print(self):
1063         pdd = wx.PrintDialogData(self.printData)
1064         printer = wx.Printer(pdd)
1065         printout = SetPrintout(self)
1066         if not printer.Print(self.parentFrame, printout):
1067             if wx.Printer.GetLastError() == wx.PRINTER_ERROR:
1068                 wx.MessageBox("There was a problem printing.\n"
1069                               "Perhaps your current printer is not set correctly?",
1070                               "Printing", wx.OK)
1071         else:
1072             self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
1073         printout.Destroy()
1074 
1075 
1076     def DoDrawing(self, DC):
1077         size = DC.GetSize()
1078 
1079         table = PrintTableDraw(self, DC, size, self.colLabels)
1080         table.data = self.data
1081         table.set_column = self.set_column
1082         table.label = self.label
1083         table.SetPage(self.page)
1084 
1085         if self.preview is None:
1086             table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1087             table.SetPTSize(size[0], size[1])
1088             table.SetPreview(False)
1089         else:
1090             if self.preview == 1:
1091                 table.scale = self.scale
1092                 table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1093             else:
1094                 table.SetPSize(self.pwidth, self.pheight)
1095 
1096             table.SetPTSize(self.ptwidth, self.ptheight)
1097             table.SetPreview(self.preview)
1098 
1099         table.OutCanvas()
1100         self.page_total = table.total_pages     # total display pages
1101 
1102         self.ymax = DC.MaxY()
1103         self.xmax = DC.MaxX()
1104 
1105         self.sizeh = size[0]
1106         self.sizew = size[1]
1107 
1108 
1109     def GetTotalPages(self):
1110         self.page_total = 100
1111         return self.page_total
1112 
1113 
1114     def HasPage(self, page):
1115         if page <= self.page_total:
1116             return True
1117         else:
1118             return False
1119 
1120 
1121     def SetPage(self, page):
1122         self.page = page
1123 
1124 
1125     def SetPageSize(self, width, height):
1126         self.pwidth, self.pheight = width, height
1127 
1128 
1129     def SetTotalSize(self, width, height):
1130         self.ptwidth, self.ptheight = width, height
1131 
1132 
1133     def SetPreview(self, preview, scale):
1134         self.preview = preview
1135         self.scale = scale
1136 
1137 
1138     def SetTotalSize(self, width, height):
1139         self.ptwidth = width
1140         self.ptheight = height
1141 
1142 #-------------------------------------------------------------------------------
1143 
1144 class PrintGrid(object):
1145     """
1146     ...
1147     """
1148     def __init__(self, parent, grid, format=[], total_col=None,
1149                  total_row=None, rowLabels=True, colLabels=True):
1150         if total_row is None:
1151             total_row = grid.GetNumberRows()
1152         if total_col is None:
1153             total_col = grid.GetNumberCols()
1154 
1155         self.total_row = total_row
1156         self.total_col = total_col
1157         self.grid = grid
1158         self.rowLabels = rowLabels
1159         self.colLabels = colLabels
1160 
1161         data = []
1162         for row in range(total_row):
1163             row_val = []
1164             if rowLabels:
1165                 row_val.append(grid.GetRowLabelValue(row))
1166 
1167             for col in range(total_col):
1168                 try:
1169                     row_val.append(grid.GetCellValueAsString(row, col))
1170                 except:
1171                     row_val.append(grid.GetCellValue(row, col))
1172             data.append(row_val)
1173 
1174 
1175         if colLabels:
1176             label = [""] if rowLabels else []
1177             for col in range(total_col):
1178                 value = grid.GetColLabelValue(col)
1179                 label.append(value)
1180 
1181         d = float(grid.GetColSize(0))
1182         if format == []:
1183             if rowLabels:
1184                 format.append(grid.GetRowLabelSize())
1185             for col in range(total_col):
1186                 col_size = grid.GetColSize(col)
1187                 #print("Column size:", col,'\t',col_size)
1188                 format.append(col_size)
1189 
1190         self.table = PrintTable(parent, rowLabels, colLabels)
1191         if colLabels: self.table.label = label
1192         self.table.cell_left_margin = 0.0
1193         self.table.cell_right_margin = 0.0
1194 
1195         self.table.set_column = format
1196         self.table.data = data
1197 
1198     #---------------------------------------------------------------------------
1199 
1200     def GetTable(self):
1201         return self.table
1202 
1203 
1204     def SetAttributes(self):
1205         for row in range(self.total_row):
1206             for col in range(self.total_col):
1207                 colour = self.grid.GetCellTextColour(row, col)
1208                 self.table.SetCellText(row, col+self.rowLabels, colour)
1209 
1210                 colour = self.grid.GetCellBackgroundColour(row, col)
1211                 self.table.SetCellColour(row, col+self.rowLabels, colour)
1212 
1213                 #self.table.
1214 
1215 
1216     def Preview(self):
1217         self.table.Preview()
1218 
1219 
1220     def Print(self):
1221         self.table.Print()
1222 
1223 #-------------------------------------------------------------------------------
1224 
1225 class SetPrintout(wx.Printout):
1226     """
1227     ...
1228     """
1229     def __init__(self, canvas):
1230         wx.Printout.__init__(self)
1231         self.canvas = canvas
1232         self.end_pg = 1000
1233 
1234     #---------------------------------------------------------------------------
1235 
1236     def OnBeginDocument(self, start, end):
1237         return super(SetPrintout, self).OnBeginDocument(start, end)
1238 
1239 
1240     def OnEndDocument(self):
1241         super(SetPrintout, self).OnEndDocument()
1242 
1243 
1244     def HasPage(self, page):
1245         try:
1246             end = self.canvas.HasPage(page)
1247             return end
1248         except:
1249             return True
1250 
1251 
1252     def GetPageInfo(self):
1253         try:
1254             self.end_pg = self.canvas.GetTotalPages()
1255         except:
1256             pass
1257 
1258         end_pg = self.end_pg
1259         str_pg = 1
1260         return (str_pg, end_pg, str_pg, end_pg)
1261 
1262 
1263     def OnPreparePrinting(self):
1264         super(SetPrintout, self).OnPreparePrinting()
1265 
1266 
1267     def OnBeginPrinting(self):
1268         dc = self.GetDC()
1269 
1270         self.preview = self.IsPreview()
1271         if self.preview:
1272             self.pixelsPerInch = self.GetPPIScreen()
1273         else:
1274             self.pixelsPerInch = self.GetPPIPrinter()
1275 
1276         (w, h) = dc.GetSize()
1277         scaleX = float(w) / 1000
1278         scaleY = float(h) / 1000
1279         self.printUserScale = min(scaleX, scaleY)
1280 
1281         super(SetPrintout, self).OnBeginPrinting()
1282 
1283 
1284     def GetSize(self):
1285         self.psizew, self.psizeh = self.GetPPIPrinter()
1286         return self.psizew, self.psizeh
1287 
1288 
1289     def GetTotalSize(self):
1290         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1291         return self.ptsizew, self.ptsizeh
1292 
1293 
1294     def OnPrintPage(self, page):
1295         dc = self.GetDC()
1296         (w, h) = dc.GetSize()
1297         scaleX = float(w) / 1000
1298         scaleY = float(h) / 1000
1299         self.printUserScale = min(scaleX, scaleY)
1300         dc.SetUserScale(self.printUserScale, self.printUserScale)
1301 
1302         self.preview = self.IsPreview()
1303 
1304         self.canvas.SetPreview(self.preview, self.printUserScale)
1305         self.canvas.SetPage(page)
1306 
1307         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1308         self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh)
1309 
1310         self.psizew, self.psizeh = self.GetPPIPrinter()
1311         self.canvas.SetPageSize(self.psizew, self.psizeh)
1312 
1313         self.canvas.DoDrawing(dc)
1314         return True
1315 
1316 #-------------------------------------------------------------------------------
1317 
1318 class Frame(wx.Frame):
1319     """
1320     ...
1321     """
1322     def __init__(self, parent, id, title=""):
1323         wx.Frame.__init__(self,
1324                           parent,
1325                           id,
1326                           title,
1327                           size=(675, 460),
1328                           style=wx.DEFAULT_FRAME_STYLE)
1329 
1330         #------------
1331 
1332         # Simplified init method.
1333         self.SetProperties()
1334         self.CreateMenu()
1335         self.CreateCtrls()
1336         self.CreatePrintData()
1337         self.BindEvents()
1338         self.DoLayout()
1339 
1340         #------------
1341 
1342         self.CenterOnScreen()
1343 
1344     #---------------------------------------------------------------------------
1345 
1346     def SetProperties(self):
1347         """
1348         Set the main frame properties (title, icon...).
1349         """
1350 
1351         self.SetTitle("Dummy wx frame for testing printout.py")
1352 
1353 
1354     def CreateMenu(self):
1355         """
1356         ...
1357         """
1358 
1359         menub = wx.MenuBar()
1360 
1361         fmenu = wx.Menu()
1362         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
1363         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
1364         fmenu.AppendSeparator()
1365         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
1366         menub.Append(fmenu, "&File")
1367 
1368         self.SetMenuBar(menub)
1369 
1370 
1371     def CreateCtrls(self):
1372         """
1373         ...
1374         """
1375 
1376         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1377         font.SetWeight(wx.BOLD)
1378         font.SetPointSize(10)
1379 
1380         #------------
1381 
1382         # First create the controls.
1383         self.panel = wx.Panel(self, -1,
1384                               style=wx.BORDER_THEME|
1385                               wx.TAB_TRAVERSAL)
1386 
1387         #------------
1388 
1389         self.demo = wx.StaticText(self.panel,
1390                                   id=-1,
1391                                   label="Demonstrating :")
1392         self.demo.SetFont(font)
1393 
1394         self.info = wx.StaticText(self.panel,
1395                                   id=-1,
1396                                   label="1) Direct printing,\n"
1397                                         "2) Printout class,\n"
1398                                         "3) PrintTable class,\n"
1399                                         "4) Preview,\n"
1400                                         "5) Menu")
1401         self.info.SetForegroundColour("red")
1402         font.SetWeight(wx.NORMAL)
1403         self.info.SetFont(font)
1404 
1405         #------------
1406 
1407         self.testgrid = grid.Grid(self.panel, -1,
1408                                   style=wx.BORDER_THEME)
1409         self.testgrid.CreateGrid(5, 5)
1410         for i in range(5):
1411             d = i + 1
1412             self.testgrid.SetColLabelValue(i, 'Column %d' % d)
1413             self.testgrid.SetRowLabelValue(i, 'Row %d' % d)
1414             for j in range(5):
1415                 e = j + 1
1416                 self.testgrid.SetCellValue(i, j, 'Cell %02d.%02d' % (d, e))
1417         self.testgrid.SetCellBackgroundColour(0, 0, wx.RED)
1418         self.testgrid.SetCellBackgroundColour(4, 4, wx.GREEN)
1419         self.testgrid.SetCellBackgroundColour(3, 4, wx.BLUE)
1420         self.testgrid.SetCellBackgroundColour(4, 3, wx.YELLOW)
1421         self.testgrid.SetColSize(0, 71)
1422         self.testgrid.SetColSize(1, 71)
1423         self.testgrid.SetColSize(2, 107)
1424         self.testgrid.SetColSize(3, 130)
1425         self.testgrid.SetColSize(4, 130)
1426 
1427         #------------
1428 
1429         self.btnPreview = wx.Button(self.panel,
1430                                     id=wx.ID_PREVIEW,
1431                                     label="Print pre&view")
1432         self.btnPreview.SetFocus()
1433 
1434         self.btnPrint = wx.Button(self.panel,
1435                                   id=wx.ID_PRINT,
1436                                   label="&Print")
1437 
1438         self.btnClose = wx.Button(self.panel,
1439                                   id=wx.ID_CLOSE,
1440                                   label="E&xit")
1441 
1442 
1443     def CreatePrintData(self):
1444         """
1445         Create printing data.
1446         """
1447 
1448         testgrid = self.testgrid
1449 
1450         #------------
1451 
1452         self.grdprt = PrintGrid(self, testgrid, rowLabels=False, colLabels=False)
1453         self.grdprt.SetAttributes()
1454 
1455         #------------
1456 
1457         self.table = self.grdprt.GetTable()
1458         self.table.SetPortrait()
1459         self.table.SetHeader('This is the test HEADER')
1460         self.table.SetFooter()
1461 
1462 
1463     def BindEvents(self):
1464         """
1465         Bind all the events related to my application.
1466         """
1467 
1468         # Bind some menu events to an events handler.
1469         self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
1470         self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
1471         self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
1472 
1473         # Bind the close event to an event handler.
1474         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1475 
1476         # Bind some buttons events to an events handler.
1477         self.Bind(wx.EVT_BUTTON, self.OnPrintPreview, self.btnPreview)
1478         self.Bind(wx.EVT_BUTTON, self.OnPrint, self.btnPrint)
1479         self.Bind(wx.EVT_BUTTON, self.OnClose, self.btnClose)
1480 
1481 
1482     def DoLayout(self):
1483         """
1484         Manage widgets Layout.
1485         """
1486 
1487         # MainSizer is the top-level one that manages everything.
1488         mainSizer = wx.BoxSizer(wx.VERTICAL)
1489 
1490         #------------
1491 
1492         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
1493         hBox1.Add(self.info, 0, wx.ALL, 15)
1494 
1495         #------------
1496 
1497         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
1498         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
1499         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
1500         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
1501 
1502         #------------
1503 
1504         mainSizer.Add(self.demo, 0, wx.ALL, 10)
1505         mainSizer.Add(wx.StaticLine(self.panel),
1506                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
1507         mainSizer.Add(self.testgrid, 0, wx.ALL, 15)
1508         mainSizer.Add(hBox1, 0, wx.ALL, 5)
1509         mainSizer.Add(hBox2, 0, wx.ALL, 5)
1510 
1511         #------------
1512 
1513         # Finally, tell the panel to use the mainSizer for layout.
1514         self.panel.SetSizer(mainSizer)
1515 
1516 
1517     def OnPrintPreview(self, event):
1518         self.CreatePrintData()
1519         self.grdprt.Preview()
1520 
1521 
1522     def OnPrint(self, event):
1523         self.CreatePrintData()
1524         self.grdprt.Print()
1525 
1526 
1527     def OnClose(self, evt):
1528         self.Close()
1529 
1530 
1531     def OnCloseWindow(self, event):
1532         """
1533         ...
1534         """
1535 
1536         self.Destroy()
1537 
1538 #-------------------------------------------------------------------------------
1539 
1540 class App(wx.App):
1541     """
1542     ...
1543     """
1544     def OnInit(self):
1545 
1546         #------------
1547 
1548         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
1549 
1550         #------------
1551 
1552         frame = Frame(None, id=-1)
1553         self.SetTopWindow(frame)
1554         frame.Show(True)
1555 
1556         return True
1557 
1558 #-------------------------------------------------------------------------------
1559 
1560 def main():
1561     app = App(False)
1562     app.MainLoop()
1563 
1564 #-------------------------------------------------------------------------------
1565 
1566 if __name__ == "__main__" :
1567     main()


Second example

img_sample_five_b.png

   1 # sample_five_b.py
   2 
   3 #-------------------------------------------------------------------------------
   4 # Name:         printout.py
   5 # Purpose:      preview and printing class -> table/grid printing
   6 #
   7 # Author:       Lorne White (email: lorne.white@telusplanet.net)
   8 #
   9 # Created:
  10 # Version:      0.75
  11 # Date:         May 15, 2002
  12 # Licence:      wxWindows license
  13 #-------------------------------------------------------------------------------
  14 # Link:
  15 # https://raw.githubusercontent.com/wxWidgets/wxPython/master/wx/lib/printout.py
  16 #-------------------------------------------------------------------------------
  17 # Release Notes :
  18 # fixed bug for string wider than print region
  19 # add index to data list after parsing total pages for paging
  20 #-------------------------------------------------------------------------------
  21 # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net)
  22 # o 2.5 compatability update.
  23 #-------------------------------------------------------------------------------
  24 # 11/23/2004 - Vernon Cole (wnvcole@peppermillcas.com)
  25 # o Generalize for non-2-dimensional sequences and non-text data
  26 #   (can use as a simple text printer by supplying a list of strings.)
  27 # o Add a small _main_ for self test
  28 #-------------------------------------------------------------------------------
  29 
  30 import os
  31 import copy
  32 import wx
  33 
  34 # class PrintBase
  35 # class PrintTableDraw
  36 # class PrintTable
  37 # class PrintGrid
  38 # class SetPrintout
  39 # class Frame
  40 # class App
  41 
  42 #-------------------------------------------------------------------------------
  43 
  44 if os.name == "posix":
  45     print("\nPlatform : UNIX - Linux")
  46 elif os.name in ['nt', 'dos', 'ce']:
  47     print("\nPlatform : Windows")
  48 else:
  49     print("\nPlatform : ", platform.system())
  50 
  51 #-------------------------------------------------------------------------------
  52 
  53 class PrintBase(object):
  54     """
  55     ...
  56     """
  57     def SetPrintFont(self, font):      # set the DC font parameters
  58         fattr = font["Attr"]
  59         if fattr[0] == 1:
  60             weight = wx.BOLD
  61         else:
  62             weight = wx.NORMAL
  63 
  64         if fattr[1] == 1:
  65             set_style = wx.ITALIC
  66         else:
  67             set_style = wx.NORMAL
  68 
  69         underline = fattr[2]
  70         fcolour = self.GetFontColour(font)
  71         self.DC.SetTextForeground(fcolour)
  72 
  73         setfont = wx.Font(font["Size"], wx.SWISS, set_style, weight, underline)
  74         setfont.SetFaceName(font["Name"])
  75         self.DC.SetFont(setfont)
  76 
  77     #---------------------------------------------------------------------------
  78 
  79     def GetFontColour(self, font):
  80         fcolour = font["Colour"]
  81         return wx.Colour(fcolour[0], fcolour[1], fcolour[2])
  82 
  83 
  84     def OutTextRegion(self, textout, txtdraw = True):
  85         textlines = textout.split('\n')
  86         y = copy.copy(self.y) + self.pt_space_before
  87         for text in textlines:
  88             remain = 'X'
  89             while remain != "":
  90                 vout, remain = self.SetFlow(text, self.region)
  91                 if self.draw == True and txtdraw == True:
  92                     test_out = self.TestFull(vout)
  93                     if self.align == wx.ALIGN_LEFT:
  94                         self.DC.DrawText(test_out, int(self.indent+self.pcell_left_margin), int(y))
  95 
  96                     elif self.align == wx.ALIGN_CENTRE:
  97                         diff = self.GetCellDiff(test_out, self.region)
  98                         self.DC.DrawText(test_out, self.indent+diff/2, y)
  99 
 100                     elif self.align == wx.ALIGN_RIGHT:
 101                         diff = self.GetCellDiff(test_out, self.region)
 102                         self.DC.DrawText(test_out, self.indent+diff, y)
 103 
 104                     else:
 105                         self.DC.DrawText(test_out, int(self.indent+self.pcell_left_margin), int(y))
 106                 text = remain
 107                 y = y + self.space
 108         return y - self.space + self.pt_space_after
 109 
 110 
 111     def GetCellDiff(self, text, width):      # get the remaining cell size for adjustment
 112         w, h = self.DC.GetTextExtent(text)
 113         diff = width - w
 114         if diff < 0:
 115             diff = 0
 116         return diff
 117 
 118 
 119     def TestFull(self, text_test):
 120         w, h = self.DC.GetTextExtent(text_test)
 121         if w > self.region:     # trouble fitting into cell
 122             return self.SetChar(text_test, self.region)     # fit the text to the cell size
 123         else:
 124             return text_test
 125 
 126 
 127     def SetFlow(self, ln_text, width):
 128         width = width - self.pcell_right_margin
 129         text = ""
 130         split = ln_text.split()
 131         if len(split) == 1:
 132             return ln_text, ""
 133 
 134         try:
 135             w, h = self.DC.GetTextExtent(" " + split[0])
 136             if w >= width:
 137                 return ln_text, ""
 138         except:
 139             pass
 140 
 141         cnt = 0
 142         for word in split:
 143             bword = " " + word  # blank + word
 144             length = len(bword)
 145 
 146             w, h = self.DC.GetTextExtent(text + bword)
 147             if w < width:
 148                 text = text + bword
 149                 cnt = cnt + 1
 150             else:
 151                 remain = ' '.join(split[cnt:])
 152                 text = text.strip()
 153                 return text, remain
 154 
 155         remain = ' '.join(split[cnt:])
 156         vout = text.strip()
 157         return vout, remain
 158 
 159 
 160     def SetChar(self, ln_text, width):  # truncate string to fit into width
 161         width = width - self.pcell_right_margin - self.pcell_left_margin
 162         text = ""
 163         for val in ln_text:
 164             w, h = self.DC.GetTextExtent(text + val)
 165             if w > width:
 166                 text = text + ".."
 167                 return text     # fitted text value
 168             text = text + val
 169         return text
 170 
 171 
 172     def OutTextPageWidth(self, textout, y_out, align, indent, txtdraw = True):
 173         textlines = textout.split('\n')
 174         y = copy.copy(y_out)
 175 
 176         pagew = self.parent.page_width * self.pwidth        # full page width
 177         w, h = self.DC.GetTextExtent(textout)
 178         y_line = h
 179 
 180         for text in textlines:
 181             remain = 'X'
 182             while remain != "":
 183                 vout, remain = self.SetFlow(text, pagew)
 184                 if self.draw == True and txtdraw == True:
 185                     test_out = vout
 186                     if align == wx.ALIGN_LEFT:
 187                         self.DC.DrawText(test_out, indent, y)
 188 
 189                     elif align == wx.ALIGN_CENTRE:
 190                         diff = self.GetCellDiff(test_out, pagew)
 191                         self.DC.DrawText(test_out, int(indent+diff/2), int(y))
 192 
 193                     elif align == wx.ALIGN_RIGHT:
 194                         diff = self.GetCellDiff(test_out, pagew)
 195                         self.DC.DrawText(test_out, int(indent+diff), int(y))
 196 
 197                     else:
 198                         self.DC.DrawText(test_out, indent, y_out)
 199                 text = remain
 200                 y = y + y_line
 201         return y - y_line
 202 
 203 
 204     def GetDate(self):
 205         date, time = self.GetNow()
 206         return date
 207 
 208 
 209     def GetDateTime(self):
 210         date, time = self.GetNow()
 211         return date + ' ' + time
 212 
 213 
 214     def GetNow(self):
 215         now = wx.DateTime.Now()
 216         date = now.FormatDate()
 217         time = now.FormatTime()
 218         return date, time
 219 
 220 
 221     def SetPreview(self, preview):
 222         self.preview = preview
 223 
 224 
 225     def SetPSize(self, width, height):
 226         self.pwidth = width/self.scale
 227         self.pheight = height/self.scale
 228 
 229 
 230     def SetScale(self, scale):
 231         self.scale = scale
 232 
 233 
 234     def SetPTSize(self, width, height):
 235         self.ptwidth = width
 236         self.ptheight = height
 237 
 238 
 239     def getWidth(self):
 240         return self.sizew
 241 
 242 
 243     def getHeight(self):
 244         return self.sizeh
 245 
 246 #-------------------------------------------------------------------------------
 247 
 248 class PrintTableDraw(wx.ScrolledWindow, PrintBase):
 249     """
 250     ...
 251     """
 252     def __init__(self, parent, DC, size):
 253         self.parent = parent
 254         self.DC = DC
 255         self.scale = parent.scale
 256         self.width = size[0]
 257         self.height = size[1]
 258         self.SetDefaults()
 259 
 260     #---------------------------------------------------------------------------
 261 
 262     def SetDefaults(self):
 263         self.page = 1
 264         self.total_pages = None
 265 
 266         self.page_width = self.parent.page_width
 267         self.page_height = self.parent.page_height
 268 
 269         self.left_margin = self.parent.left_margin
 270         self.right_margin = self.parent.right_margin
 271 
 272         self.top_margin  = self.parent.top_margin
 273         self.bottom_margin = self.parent.bottom_margin
 274         self.cell_left_margin = self.parent.cell_left_margin
 275         self.cell_right_margin = self.parent.cell_right_margin
 276 
 277         self.label_colour = self.parent.label_colour
 278 
 279         self.row_line_colour = self.parent.row_line_colour
 280         self.row_line_size = self.parent.row_line_size
 281 
 282         self.row_def_line_colour = self.parent.row_def_line_colour
 283         self.row_def_line_size = self.parent.row_def_line_size
 284 
 285         self.column_line_colour = self.parent.column_line_colour
 286         self.column_line_size = self.parent.column_line_size
 287 
 288         self.column_def_line_size = self.parent.column_def_line_size
 289         self.column_def_line_colour = self.parent.column_def_line_colour
 290 
 291         self.text_font = self.parent.text_font
 292 
 293         self.label_font = self.parent.label_font
 294 
 295 
 296     def AdjustValues(self):
 297         self.vertical_offset = self.pheight * self.parent.vertical_offset
 298         self.horizontal_offset = self.pheight * self.parent.horizontal_offset
 299 
 300         self.pcell_left_margin = self.pwidth * self.cell_left_margin
 301         self.pcell_right_margin = self.pwidth * self.cell_right_margin
 302         self.ptop_margin = self.pheight * self.top_margin
 303         self.pbottom_margin = self.pheight * self.bottom_margin
 304 
 305         self.pheader_margin = self.pheight * self.parent.header_margin
 306         self.pfooter_margin = self.pheight * self.parent.footer_margin
 307 
 308         self.cell_colour = self.parent.set_cell_colour
 309         self.cell_text = self.parent.set_cell_text
 310 
 311         self.column = []
 312         self.column_align = []
 313         self.column_bgcolour = []
 314         self.column_txtcolour = []
 315 
 316         set_column_align = self.parent.set_column_align
 317         set_column_bgcolour = self.parent.set_column_bgcolour
 318         set_column_txtcolour = self.parent.set_column_txtcolour
 319 
 320         pos_x = self.left_margin * self.pwidth + self.horizontal_offset     # left margin
 321         self.column.append(pos_x)
 322 
 323         # Module logic expects two dimensional data -- fix input if needed
 324         if isinstance(self.data, str):
 325             self.data = [[copy.copy(self.data)]] # a string becomes a single cell
 326         try:
 327             rows = len(self.data)
 328         except TypeError:
 329             self.data = [[str(self.data)]] # a non-iterable becomes a single cell
 330             rows = 1
 331         first_value = self.data[0]
 332 
 333         if isinstance(first_value, str): # A sequence of strings
 334             if self.label == [] and self.set_column == []:
 335                 data = []
 336                 for x in self.data:     # Becomes one column
 337                     data.append([x])
 338             else:
 339                 data = [self.data]      # Becames one row
 340             self.data = data
 341             first_value = data[0]
 342         try:
 343             column_total = len(first_value)
 344         except TypeError:    # A sequence of non-iterables
 345             if self.label == [] and self.set_column == []:
 346                 data = []       # Becomes one column
 347                 for x in self.data:
 348                     data.append([str(x)])
 349                 column_total = 1
 350             else:
 351                 data = [self.data] # Becomes one row
 352                 column_total = len(self.data)
 353             self.data = data
 354             first_value = data[0]
 355 
 356         if self.set_column == []:
 357             table_width = self.page_width - self.left_margin - self.right_margin
 358             if self.label == []:
 359                 temp = first_value
 360             else:
 361                 temp = self.label
 362             width = table_width/(len(temp))
 363             for val in temp:
 364                 column_width = width * self.pwidth
 365                 pos_x = pos_x + column_width
 366                 self.column.append(pos_x)   # position of each column
 367         else:
 368             for val in self.set_column:
 369                 column_width = val * self.pwidth
 370                 pos_x = pos_x + column_width
 371                 self.column.append(pos_x)   # position of each column
 372 
 373         if pos_x > self.page_width * self.pwidth:    # check if it fits in page
 374             print("Warning, Too Wide for Page")
 375             return
 376 
 377         if self.label != []:
 378             if len(self.column) -1 != len(self.label):
 379                 print("Column Settings Incorrect", "\nColumn Value: " + str(self.column), "\nLabel Value: " + str(self.label))
 380                 return
 381 
 382         if column_total != len(self.column) -1:
 383             print("Cannot fit", first_value, 'in', len(self.column)-1, 'columns.')
 384             return
 385 
 386         for col in range(column_total):
 387             try:
 388                 align = set_column_align[col]       # check if custom column alignment
 389             except:
 390                 align = wx.ALIGN_LEFT
 391             self.column_align.append(align)
 392 
 393             try:
 394                 colour = set_column_bgcolour[col]     # check if custom column background colour
 395             except:
 396                 colour = self.parent.column_colour
 397             self.column_bgcolour.append(colour)
 398 
 399             try:
 400                 colour = set_column_txtcolour[col]     # check if custom column text colour
 401             except:
 402                 colour = self.GetFontColour(self.parent.text_font)
 403             self.column_txtcolour.append(colour)
 404 
 405 
 406     def SetPointAdjust(self):
 407         f = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)     # setup using 10 point
 408         self.DC.SetFont(f)
 409         f.SetFaceName(self.text_font["Name"])
 410         x, y = self.DC.GetTextExtent("W")
 411 
 412         self.label_pt_space_before = self.parent.label_pt_adj_before * y/10        # extra spacing for label per point value
 413         self.label_pt_space_after = self.parent.label_pt_adj_after * y/10
 414 
 415         self.text_pt_space_before = self.parent.text_pt_adj_before * y/10        # extra spacing for row text per point value
 416         self.text_pt_space_after = self.parent.text_pt_adj_after * y/10
 417 
 418 
 419     def SetPage(self, page):
 420         self.page = page
 421 
 422 
 423     def SetColumns(self, col):
 424         self.column = col
 425 
 426 
 427     def OutCanvas(self):
 428         self.AdjustValues()
 429         self.SetPointAdjust()
 430 
 431         self.y_start = self.ptop_margin + self.vertical_offset
 432         self.y_end = self.parent.page_height * self.pheight - self.pbottom_margin + self.vertical_offset
 433 
 434         self.SetPrintFont(self.label_font)
 435 
 436         x, y = self.DC.GetTextExtent("W")
 437         self.label_space = y
 438 
 439         self.SetPrintFont(self.text_font)
 440 
 441         x, y = self.DC.GetTextExtent("W")
 442         self.space = y
 443 
 444         if self.total_pages is None:
 445             self.GetTotalPages()    # total pages for display/printing
 446 
 447         self.data_cnt = self.page_index[self.page-1]
 448 
 449         self.draw = True
 450         self.PrintHeader()
 451         self.PrintFooter()
 452         self.OutPage()
 453 
 454 
 455     def GetTotalPages(self):
 456         self.data_cnt = 0
 457         self.draw = False
 458         self.page_index = [0]
 459 
 460         cnt = 0
 461         while 1:
 462             test = self.OutPage()
 463             self.page_index.append(self.data_cnt)
 464             if  test == False:
 465                 break
 466             cnt = cnt + 1
 467 
 468         self.total_pages = cnt + 1
 469 
 470 
 471     def OutPage(self):
 472         self.y = self.y_start
 473         self.end_x = self.column[-1]
 474 
 475         if self.data_cnt < len(self.data):  # if there data for display on the page
 476             if self.label != []:        # check if header defined
 477                 self.PrintLabel()
 478         else:
 479             return False
 480 
 481         for val in self.data:
 482             try:
 483                 row_val = self.data[self.data_cnt]
 484             except:
 485                 self.FinishDraw()
 486                 return False
 487 
 488             max_y = self.PrintRow(row_val, False)       # test to see if row will fit in remaining space
 489             test = max_y + self.space
 490 
 491             if test > self.y_end:
 492                 break
 493 
 494             self.ColourRowCells(max_y-self.y+self.space)       # colour the row/column
 495             max_y = self.PrintRow(row_val, True)      # row fits - print text
 496             self.DrawGridLine()     # top line of cell
 497             self.y = max_y + self.space
 498 
 499             if self.y > self.y_end:
 500                 break
 501 
 502             self.data_cnt = self.data_cnt + 1
 503 
 504         self.FinishDraw()
 505 
 506         if self.data_cnt == len(self.data):    # last value in list
 507             return False
 508 
 509         return True
 510 
 511 
 512     def PrintLabel(self):
 513         self.pt_space_before = self.label_pt_space_before   # set the point spacing
 514         self.pt_space_after = self.label_pt_space_after
 515 
 516         self.LabelColorRow(self.label_colour)
 517         self.SetPrintFont(self.label_font)
 518 
 519         self.col = 0
 520         max_y = 0
 521         for vtxt in self.label:
 522             self.region = self.column[self.col+1] - self.column[self.col]
 523             self.indent = self.column[self.col]
 524 
 525             self.align = wx.ALIGN_LEFT
 526 
 527             max_out = self.OutTextRegion(vtxt, True)
 528             if max_out > max_y:
 529                 max_y = max_out
 530             self.col = self.col + 1
 531 
 532         self.DrawGridLine()     # top line of label
 533         self.y = max_y + self.label_space
 534 
 535 
 536     def PrintHeader(self):      # print the header array
 537         if self.draw == False:
 538             return
 539 
 540         for val in self.parent.header:
 541             self.SetPrintFont(val["Font"])
 542 
 543             header_indent = val["Indent"] * self.pwidth
 544             text = val["Text"]
 545 
 546             htype = val["Type"]
 547             if htype == "Date":
 548                 addtext = self.GetDate()
 549             elif htype == "Date & Time":
 550                 addtext = self.GetDateTime()
 551             else:
 552                 addtext = ""
 553 
 554             self.OutTextPageWidth(text+addtext, self.pheader_margin, val["Align"], header_indent, True)
 555 
 556 
 557     def PrintFooter(self):      # print the header array
 558         if self.draw == False:
 559             return
 560 
 561         footer_pos = self.parent.page_height * self.pheight - self.pfooter_margin + self.vertical_offset
 562         for val in self.parent.footer:
 563             self.SetPrintFont(val["Font"])
 564 
 565             footer_indent = val["Indent"] * self.pwidth
 566             text = val["Text"]
 567 
 568             ftype = val["Type"]
 569             if ftype == "Pageof":
 570                 addtext = "Page " + str(self.page) + " of " + str(self.total_pages)
 571             elif ftype == "Page":
 572                 addtext = "Page " + str(self.page)
 573             elif ftype == "Num":
 574                 addtext = str(self.page)
 575             elif ftype == "Date":
 576                 addtext = self.GetDate()
 577             elif ftype == "Date & Time":
 578                 addtext = self.GetDateTime()
 579             else:
 580                 addtext = ""
 581 
 582             self.OutTextPageWidth(text+addtext, footer_pos, val["Align"], footer_indent, True)
 583 
 584 
 585     def LabelColorRow(self, colour):
 586         brush = wx.Brush(colour, wx.SOLID)
 587         self.DC.SetBrush(brush)
 588         height = self.label_space + self.label_pt_space_before + self.label_pt_space_after
 589         self.DC.DrawRectangle(int(self.column[0]), int(self.y),
 590                               int(self.end_x-self.column[0]+1), int(height))
 591 
 592 
 593     def ColourRowCells(self, height):
 594         if self.draw == False:
 595             return
 596 
 597         col = 0
 598         for colour in self.column_bgcolour:
 599             cellcolour = self.GetCellColour(self.data_cnt, col)
 600             if cellcolour is not None:
 601                 colour = cellcolour
 602 
 603             brush = wx.Brush(colour, wx.SOLID)
 604             self.DC.SetBrush(brush)
 605             self.DC.SetPen(wx.Pen(wx.Colour('WHITE'), 0))
 606 
 607             start_x = self.column[col]
 608             width = self.column[col+1] - start_x + 2
 609             self.DC.DrawRectangle(int(start_x), int(self.y), int(width), int(height))
 610             col = col + 1
 611 
 612 
 613     def PrintRow(self, row_val, draw = True, align = wx.ALIGN_LEFT):
 614         self.SetPrintFont(self.text_font)
 615 
 616         self.pt_space_before = self.text_pt_space_before   # set the point spacing
 617         self.pt_space_after = self.text_pt_space_after
 618 
 619         self.col = 0
 620         max_y = 0
 621         for vtxt in row_val:
 622             if not isinstance(vtxt, str):
 623                 vtxt = str(vtxt)
 624             self.region = self.column[self.col+1] - self.column[self.col]
 625             self.indent = self.column[self.col]
 626             self.align = self.column_align[self.col]
 627 
 628             fcolour = self.column_txtcolour[self.col]       # set font colour
 629             celltext = self.GetCellTextColour(self.data_cnt, self.col)
 630             if celltext is not None:
 631                 fcolour = celltext      # override the column colour
 632 
 633             self.DC.SetTextForeground(fcolour)
 634 
 635             max_out = self.OutTextRegion(vtxt, draw)
 636             if max_out > max_y:
 637                 max_y = max_out
 638             self.col = self.col + 1
 639         return max_y
 640 
 641 
 642     def GetCellColour(self, row, col):      # check if custom colour defined for the cell background
 643         try:
 644             set = self.cell_colour[row]
 645         except:
 646             return None
 647         try:
 648             colour = set[col]
 649             return colour
 650         except:
 651             return None
 652 
 653 
 654     def GetCellTextColour(self, row, col):      # check if custom colour defined for the cell text
 655         try:
 656             set = self.cell_text[row]
 657         except:
 658             return None
 659         try:
 660             colour = set[col]
 661             return colour
 662         except:
 663             return None
 664 
 665 
 666     def FinishDraw(self):
 667         self.DrawGridLine()     # draw last row line
 668         self.DrawColumns()      # draw all vertical lines
 669 
 670 
 671     def DrawGridLine(self):
 672         if self.draw == True \
 673         and len(self.column) > 2:    #supress grid lines if only one column
 674             try:
 675                 size = self.row_line_size[self.data_cnt]
 676             except:
 677                 size = self.row_def_line_size
 678 
 679             if size < 1: return
 680 
 681             try:
 682                 colour = self.row_line_colour[self.data_cnt]
 683             except:
 684                 colour = self.row_def_line_colour
 685 
 686             self.DC.SetPen(wx.Pen(colour, size))
 687 
 688             y_out = self.y
 689             #y_out = self.y + self.pt_space_before + self.pt_space_after     # adjust for extra spacing
 690             self.DC.DrawLine(int(self.column[0]), int(y_out), int(self.end_x), int(y_out))
 691 
 692 
 693     def DrawColumns(self):
 694         if self.draw == True \
 695         and len(self.column) > 2:   #surpress grid line if only one column
 696             col = 0
 697             for val in self.column:
 698                 try:
 699                     size = self.column_line_size[col]
 700                 except:
 701                     size = self.column_def_line_size
 702 
 703                 if size < 1: continue
 704 
 705                 try:
 706                     colour = self.column_line_colour[col]
 707                 except:
 708                     colour = self.column_def_line_colour
 709 
 710                 indent = val
 711 
 712                 self.DC.SetPen(wx.Pen(colour, size))
 713                 self.DC.DrawLine(int(indent), int(self.y_start), int(indent), int(self.y))
 714                 col = col + 1
 715 
 716 
 717     def DrawText(self):
 718         self.DoRefresh()
 719 
 720 
 721     def DoDrawing(self, DC):
 722         size = DC.GetSize()
 723         self.DC = DC
 724 
 725         self.DrawText()
 726 
 727         self.sizew = DC.MaxY()
 728         self.sizeh = DC.MaxX()
 729 
 730 #-------------------------------------------------------------------------------
 731 
 732 class PrintTable(object):
 733     """
 734     ...
 735     """
 736     def __init__(self, parentFrame=None):
 737         self.data = []
 738         self.set_column = []
 739         self.label = []
 740         self.header = []
 741         self.footer = []
 742 
 743         self.set_column_align = {}
 744         self.set_column_bgcolour = {}
 745         self.set_column_txtcolour = {}
 746         self.set_cell_colour = {}
 747         self.set_cell_text = {}
 748         self.column_line_size = {}
 749         self.column_line_colour = {}
 750         self.row_line_size = {}
 751         self.row_line_colour = {}
 752 
 753         self.parentFrame = parentFrame
 754         self.SetPreviewSize()
 755 
 756         self.printData = wx.PrintData()
 757         self.scale = 1.0
 758 
 759         self.SetParms()
 760         self.SetColors()
 761         self.SetFonts()
 762         self.TextSpacing()
 763 
 764         self.SetPrinterOffset()
 765         self.SetHeaderValue()
 766         self.SetFooterValue()
 767         self.SetMargins()
 768         self.SetPortrait()
 769 
 770     #---------------------------------------------------------------------------
 771 
 772     def SetPreviewSize(self, position = wx.Point(0, 0), size="Full"):
 773         if size == "Full":
 774             r = wx.GetClientDisplayRect()
 775             self.preview_frame_size = r.GetSize()
 776             self.preview_frame_pos = r.GetPosition()
 777         else:
 778             self.preview_frame_size = size
 779             self.preview_frame_pos = position
 780 
 781 
 782     def SetPaperId(self, paper):
 783         self.printData.SetPaperId(paper)
 784 
 785 
 786     def SetOrientation(self, orient):
 787         self.printData.SetOrientation(orient)
 788 
 789 
 790     def SetColors(self):
 791         self.row_def_line_colour = wx.Colour('BLACK')
 792         self.row_def_line_size = 1
 793 
 794         self.column_def_line_colour = wx.Colour('BLACK')
 795         self.column_def_line_size = 1
 796         self.column_colour = wx.Colour('WHITE')
 797 
 798         self.label_colour = wx.Colour('LIGHT GREY')
 799 
 800 
 801     def SetFonts(self):
 802         self.label_font = { "Name": self.default_font_name, "Size": 12, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 803         self.text_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 804 
 805 
 806     def TextSpacing(self):
 807         self.label_pt_adj_before = 0     # point adjustment before and after the label text
 808         self.label_pt_adj_after = 0
 809 
 810         self.text_pt_adj_before = 0     # point adjustment before and after the row text
 811         self.text_pt_adj_after = 0
 812 
 813 
 814     def SetLabelSpacing(self, before, after):        # method to set the label space adjustment
 815         self.label_pt_adj_before = before
 816         self.label_pt_adj_after = after
 817 
 818 
 819     def SetRowSpacing(self, before, after):         # method to set the row space adjustment
 820         self.text_pt_adj_before = before
 821         self.text_pt_adj_after = after
 822 
 823 
 824     def SetPrinterOffset(self):        # offset to adjust for printer
 825         self.vertical_offset = -0.1
 826         self.horizontal_offset = -0.1
 827 
 828 
 829     def SetHeaderValue(self):
 830         self.header_margin = 0.25
 831         self.header_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 832         self.header_align = wx.ALIGN_CENTRE
 833         self.header_indent = 0
 834         self.header_type = "Text"
 835 
 836 
 837     def SetFooterValue(self):
 838         self.footer_margin = 0.7
 839         self.footer_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 840         self.footer_align = wx.ALIGN_CENTRE
 841         self.footer_indent = 0
 842         self.footer_type = "Pageof"
 843 
 844 
 845     def SetMargins(self):
 846         self.left_margin = 0.5
 847         self.right_margin = 0.5    # only used if no column sizes
 848 
 849         self.top_margin  = 0.8
 850         self.bottom_margin = 1.0
 851         self.cell_left_margin = 0.1
 852         self.cell_right_margin = 0.1
 853 
 854 
 855     def SetPortrait(self):
 856         self.printData.SetPaperId(wx.PAPER_LETTER)
 857         self.printData.SetOrientation(wx.PORTRAIT)
 858         self.page_width = 8.5
 859         self.page_height = 11.0
 860 
 861 
 862     def SetLandscape(self):
 863         self.printData.SetOrientation(wx.LANDSCAPE)
 864         self.page_width = 11.0
 865         self.page_height = 8.5
 866 
 867 
 868     def SetParms(self):
 869         self.ymax = 1
 870         self.xmax = 1
 871         self.page = 1
 872         self.total_pg = 100
 873 
 874         self.preview = None
 875         self.page = 0
 876 
 877         self.default_font_name = "Arial"
 878         self.default_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 879 
 880 
 881     def SetColAlignment(self, col, align=wx.ALIGN_LEFT):
 882         self.set_column_align[col] = align
 883 
 884 
 885     def SetColBackgroundColour(self, col, colour):
 886         self.set_column_bgcolour[col] = colour
 887 
 888 
 889     def SetColTextColour(self, col, colour):
 890         self.set_column_txtcolour[col] = colour
 891 
 892 
 893     def SetCellColour(self, row, col, colour):      # cell background colour
 894         try:
 895             set = self.set_cell_colour[row]     # test if row already exists
 896             try:
 897                 set[col] = colour       # test if column already exists
 898             except:
 899                 set = { col: colour }       # create the column value
 900         except:
 901             set = { col: colour }           # create the column value
 902 
 903         self.set_cell_colour[row] = set    # create dictionary item for colour settings
 904 
 905 
 906     def SetCellText(self, row, col, colour):        # font colour for custom cells
 907         try:
 908             set = self.set_cell_text[row]     # test if row already exists
 909             try:
 910                 set[col] = colour       # test if column already exists
 911             except:
 912                 set = { col: colour }       # create the column value
 913         except:
 914             set = { col: colour }           # create the column value
 915 
 916         self.set_cell_text[row] = set    # create dictionary item for colour settings
 917 
 918 
 919     def SetColumnLineSize(self, col, size):      # column line size
 920         self.column_line_size[col] = size    # create dictionary item for column line settings
 921 
 922 
 923     def SetColumnLineColour(self, col, colour):
 924         self.column_line_colour[col] = colour
 925 
 926 
 927     def SetRowLineSize(self, row, size):
 928         self.row_line_size[row] = size
 929 
 930 
 931     def SetRowLineColour(self, row, colour):
 932         self.row_line_colour[row] = colour
 933 
 934 
 935     def GetColour(self, colour):        # returns colours based from wxColour value
 936         red = colour.Red()
 937         blue = colour.Blue()
 938         green = colour.Green()
 939         return [red, green, blue ]
 940 
 941 
 942     def SetHeader(self, text = "", type = "Text", font=None, align = None, indent = None, colour = None, size = None):
 943         set = { "Text": text }
 944 
 945         if font is None:
 946             set["Font"] = copy.copy(self.default_font)
 947         else:
 948             set["Font"] = font
 949 
 950         if colour is not None:
 951             setfont = set["Font"]
 952             setfont["Colour"] = self.GetColour(colour)
 953 
 954         if size is not None:
 955             setfont = set["Font"]
 956             setfont["Size"] = size
 957 
 958         if align is None:
 959             set["Align"] = self.header_align
 960         else:
 961             set["Align"] = align
 962 
 963         if indent is None:
 964             set["Indent"] = self.header_indent
 965         else:
 966             set["Indent"] = indent
 967 
 968         if type is None:
 969             set["Type"] = self.header_type
 970         else:
 971             set["Type"] = type
 972 
 973         self.header.append(set)
 974 
 975 
 976     def SetFooter(self, text = "", type = None, font=None, align = None, indent = None, colour = None, size = None):
 977         set = { "Text": text }
 978 
 979         if font is None:
 980             set["Font"] = copy.copy(self.default_font)
 981         else:
 982             set["Font"] = font
 983 
 984         if colour is not None:
 985             setfont = set["Font"]
 986             setfont["Colour"] = self.GetColour(colour)
 987 
 988         if size is not None:
 989             setfont = set["Font"]
 990             setfont["Size"] = size
 991 
 992         if align is None:
 993             set["Align"] = self.footer_align
 994         else:
 995             set["Align"] = align
 996 
 997         if indent is None:
 998             set["Indent"] = self.footer_indent
 999         else:
1000             set["Indent"] = indent
1001 
1002         if type is None:
1003             set["Type"] = self.footer_type
1004         else:
1005             set["Type"] = type
1006 
1007         self.footer.append(set)
1008 
1009 
1010     def Preview(self):
1011         data = wx.PrintDialogData(self.printData)
1012 
1013         text = self.parentFrame.tc.GetValue()
1014 
1015         printout = SetPrintout(self, text)
1016         printout2 = SetPrintout(self, text)
1017         self.preview = wx.PrintPreview(printout, printout2, data)
1018         if not self.preview.IsOk():
1019             wx.MessageBox("There was a problem printing!", "Printing", wx.OK)
1020             return
1021 
1022         self.preview.SetZoom(60)        # initial zoom value
1023         frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview")
1024 
1025         frame.Initialize()
1026         if self.parentFrame:
1027             frame.SetPosition(self.preview_frame_pos)
1028             frame.SetSize(self.preview_frame_size)
1029         frame.Show(True)
1030 
1031 
1032     def Print(self):
1033         pdd = wx.PrintDialogData(self.printData)
1034         printer = wx.Printer(pdd)
1035 
1036         text = self.parentFrame.tc.GetValue()
1037 
1038         printout = SetPrintout(self, text)
1039         if not printer.Print(self.parentFrame, printout):
1040             if wx.Printer.GetLastError() == wx.PRINTER_ERROR:
1041                 wx.MessageBox("There was a problem printing.\n"
1042                               "Perhaps your current printer is not set correctly?",
1043                               "Printing", wx.OK)
1044         else:
1045             self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
1046         printout.Destroy()
1047 
1048 
1049     def DoDrawing(self, DC):
1050         size = DC.GetSize()
1051 
1052         table = PrintTableDraw(self, DC, size)
1053         table.data = self.data
1054         table.set_column = self.set_column
1055         table.label = self.label
1056         table.SetPage(self.page)
1057 
1058         if self.preview is None:
1059             table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1060             table.SetPTSize(size[0], size[1])
1061             table.SetPreview(False)
1062         else:
1063             if self.preview == 1:
1064                 table.scale = self.scale
1065                 table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1066             else:
1067                 table.SetPSize(self.pwidth, self.pheight)
1068 
1069             table.SetPTSize(self.ptwidth, self.ptheight)
1070             table.SetPreview(self.preview)
1071 
1072         table.OutCanvas()
1073         self.page_total = table.total_pages     # total display pages
1074 
1075         self.ymax = DC.MaxY()
1076         self.xmax = DC.MaxX()
1077 
1078         self.sizeh = size[0]
1079         self.sizew = size[1]
1080 
1081 
1082     def GetTotalPages(self):
1083         self.page_total = 100
1084         return self.page_total
1085 
1086 
1087     def HasPage(self, page):
1088         if page <= self.page_total:
1089             return True
1090         else:
1091             return False
1092 
1093 
1094     def SetPage(self, page):
1095         self.page = page
1096 
1097 
1098     def SetPageSize(self, width, height):
1099         self.pwidth, self.pheight = width, height
1100 
1101 
1102     def SetTotalSize(self, width, height):
1103         self.ptwidth, self.ptheight = width, height
1104 
1105 
1106     def SetPreview(self, preview, scale):
1107         self.preview = preview
1108         self.scale = scale
1109 
1110 
1111     def SetTotalSize(self, width, height):
1112         self.ptwidth = width
1113         self.ptheight = height
1114 
1115 #-------------------------------------------------------------------------------
1116 
1117 class PrintGrid(object):
1118     """
1119     ...
1120     """
1121     def __init__(self, parent, grid, format = [], total_col = None, total_row = None):
1122         if total_row is None:
1123             total_row = grid.GetNumberRows()
1124         if total_col is None:
1125             total_col = grid.GetNumberCols()
1126 
1127         self.total_row = total_row
1128         self.total_col = total_col
1129         self.grid = grid
1130 
1131         data = []
1132         for row in range(total_row):
1133             row_val = []
1134             value = grid.GetRowLabelValue(row)
1135             row_val.append(value)
1136 
1137             for col in range(total_col):
1138                 value = grid.GetCellValue(row, col)
1139                 row_val.append(value)
1140             data.append(row_val)
1141 
1142         label = [""]
1143         for col in range(total_col):
1144             value = grid.GetColLabelValue(col)
1145             label.append(value)
1146 
1147         self.table = PrintTable(parent)
1148         self.table.cell_left_margin = 0.0
1149         self.table.cell_right_margin = 0.0
1150 
1151         self.table.label = label
1152         self.table.set_column = format
1153         self.table.data = data
1154 
1155     #---------------------------------------------------------------------------
1156 
1157     def GetTable(self):
1158         return self.table
1159 
1160 
1161     def SetAttributes(self):
1162         for row in range(self.total_row):
1163             for col in range(self.total_col):
1164                 colour = self.grid.GetCellTextColour(row, col-1)
1165                 self.table.SetCellText(row, col, colour)
1166 
1167                 colour = self.grid.GetCellBackgroundColour(row, col-1)
1168                 self.table.SetCellColour(row, col, colour)
1169 
1170 
1171     def Preview(self):
1172         self.table.Preview()
1173 
1174 
1175     def Print(self):
1176         self.table.Print()
1177 
1178 #-------------------------------------------------------------------------------
1179 
1180 class SetPrintout(wx.Printout):
1181     """
1182     ...
1183     """
1184     def __init__(self, canvas, text):
1185         wx.Printout.__init__(self)
1186 
1187         self.canvas = canvas
1188         self.end_pg = 1000
1189         self.lines = text
1190 
1191     #---------------------------------------------------------------------------
1192 
1193     def OnBeginDocument(self, start, end):
1194         return super(SetPrintout, self).OnBeginDocument(start, end)
1195 
1196 
1197     def OnEndDocument(self):
1198         super(SetPrintout, self).OnEndDocument()
1199 
1200 
1201     def HasPage(self, page):
1202         try:
1203             end = self.canvas.HasPage(page)
1204             return end
1205         except:
1206             return True
1207 
1208 
1209     def GetPageInfo(self):
1210         try:
1211             self.end_pg = self.canvas.GetTotalPages()
1212         except:
1213             pass
1214 
1215         end_pg = self.end_pg
1216         str_pg = 1
1217         return (str_pg, end_pg, str_pg, end_pg)
1218 
1219 
1220     def OnPreparePrinting(self):
1221         super(SetPrintout, self).OnPreparePrinting()
1222 
1223 
1224     def OnBeginPrinting(self):
1225         dc = self.GetDC()
1226 
1227         self.preview = self.IsPreview()
1228         if (self.preview):
1229             self.pixelsPerInch = self.GetPPIScreen()
1230         else:
1231             self.pixelsPerInch = self.GetPPIPrinter()
1232 
1233         (w, h) = dc.GetSize()
1234         scaleX = float(w) / 1000
1235         scaleY = float(h) / 1000
1236         self.printUserScale = min(scaleX, scaleY)
1237 
1238         super(SetPrintout, self).OnBeginPrinting()
1239 
1240 
1241     def GetSize(self):
1242         self.psizew, self.psizeh = self.GetPPIPrinter()
1243         return self.psizew, self.psizeh
1244 
1245 
1246     def GetTotalSize(self):
1247         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1248         return self.ptsizew, self.ptsizeh
1249 
1250 
1251     def OnPrintPage(self, page):
1252         dc = self.GetDC()
1253         (w, h) = dc.GetSize()
1254         scaleX = float(w) / 1000
1255         scaleY = float(h) / 1000
1256         self.printUserScale = min(scaleX, scaleY)
1257         dc.SetUserScale(self.printUserScale, self.printUserScale)
1258 
1259         self.preview = self.IsPreview()
1260 
1261         self.canvas.SetPreview(self.preview, self.printUserScale)
1262         self.canvas.SetPage(page)
1263 
1264         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1265         self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh)
1266 
1267         self.psizew, self.psizeh = self.GetPPIPrinter()
1268         self.canvas.SetPageSize(self.psizew, self.psizeh)
1269 
1270         self.canvas.DoDrawing(dc)
1271         return True
1272 
1273 #-------------------------------------------------------------------------------
1274 
1275 class Frame(wx.Frame):
1276     """
1277     ...
1278     """
1279     def __init__(self, parent, id, title=""):
1280         wx.Frame.__init__(self,
1281                           parent,
1282                           id,
1283                           title,
1284                           size=(600, 450),
1285                           style=wx.DEFAULT_FRAME_STYLE)
1286 
1287         #------------
1288 
1289         # Simplified init method.
1290         self.SetProperties()
1291         self.CreateMenu()
1292         self.CreateCtrls()
1293         self.CreatePrintData()
1294         self.BindEvents()
1295         self.DoLayout()
1296 
1297         #------------
1298 
1299         self.CenterOnScreen()
1300 
1301     #---------------------------------------------------------------------------
1302 
1303     def SetProperties(self):
1304         """
1305         Set the main frame properties (title, icon...).
1306         """
1307 
1308         self.SetTitle("Dummy wx frame for testing printout.py")
1309 
1310 
1311     def CreateMenu(self):
1312         """
1313         ...
1314         """
1315 
1316         menub = wx.MenuBar()
1317 
1318         fmenu = wx.Menu()
1319         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
1320         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
1321         fmenu.AppendSeparator()
1322         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
1323         menub.Append(fmenu, "&File")
1324 
1325         self.SetMenuBar(menub)
1326 
1327 
1328     def CreateCtrls(self):
1329         """
1330         ...
1331         """
1332 
1333         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1334         font.SetWeight(wx.BOLD)
1335         font.SetPointSize(10)
1336 
1337         #------------
1338 
1339         # First create the controls.
1340         self.panel = wx.Panel(self, -1,
1341                               style=wx.BORDER_THEME|
1342                               wx.TAB_TRAVERSAL)
1343 
1344         self.demo = wx.StaticText(self.panel,
1345                                   id=-1,
1346                                   label="Demonstrating :")
1347         self.demo.SetFont(font)
1348 
1349         self.info = wx.StaticText(self.panel,
1350                                   id=-1,
1351                                   label="1) Direct printing,\n"
1352                                         "2) Printout class,\n"
1353                                         "3) PrintTable class,\n"
1354                                         "4) Preview,\n"
1355                                         "5) Menu")
1356         self.info.SetForegroundColour("red")
1357         font.SetWeight(wx.NORMAL)
1358         self.info.SetFont(font)
1359 
1360         text = ('This the first line of text.\n'\
1361                 'This is the second line and the third. The fourth will be the number 4.0.\n'\
1362                 '4.0\n'\
1363                 'This is the fifth line, but by design it is too long to fit in the width of a standard'\
1364                 'page, so it will be forced to wrap around in order to fit without having'\
1365                 'some of its verbose verbage truncated.\n'
1366                 'Here we have the final line.')
1367 
1368         self.tc = wx.TextCtrl(self.panel,
1369                               id=-1,
1370                               size=(200, -1),
1371                               value=text,
1372                               style=wx.TE_MULTILINE|wx.TE_DONTWRAP)
1373 
1374         self.btnPreview = wx.Button(self.panel,
1375                                     id=wx.ID_PREVIEW,
1376                                     label="Print pre&view")
1377         self.btnPreview.SetFocus()
1378 
1379         self.btnPrint = wx.Button(self.panel,
1380                                   id=wx.ID_PRINT,
1381                                   label="&Print")
1382 
1383         self.btnClose = wx.Button(self.panel,
1384                                   id=wx.ID_CLOSE,
1385                                   label="E&xit")
1386 
1387 
1388     def CreatePrintData(self):
1389         """
1390         Create printing data.
1391         """
1392 
1393         self.ptbl = PrintTable(self)
1394         self.ptbl.SetHeader('This is the test HEADER')
1395         self.ptbl.SetFooter()
1396 
1397         #... but, if labels or columns are defined, a single sequence will print out as a single row
1398         self.ptbl.label = ('One','Two','Three','Four','5')
1399 
1400 
1401     def BindEvents(self):
1402         """
1403         Bind all the events related to my application.
1404         """
1405 
1406         # Bind some menu events to an events handler.
1407         self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
1408         self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
1409         self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
1410 
1411         # Bind the close event to an event handler.
1412         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1413 
1414         # Bind some buttons events to an events handler.
1415         self.Bind(wx.EVT_BUTTON, self.OnPrintPreview, self.btnPreview)
1416         self.Bind(wx.EVT_BUTTON, self.OnPrint, self.btnPrint)
1417         self.Bind(wx.EVT_BUTTON, self.OnClose, self.btnClose)
1418 
1419 
1420     def DoLayout(self):
1421         """
1422         Manage widgets Layout.
1423         """
1424 
1425         # MainSizer is the top-level one that manages everything.
1426         mainSizer = wx.BoxSizer(wx.VERTICAL)
1427 
1428         #------------
1429 
1430         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
1431         hBox1.Add(self.info, 0, wx.ALL, 15)
1432 
1433         #------------
1434 
1435         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
1436         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
1437         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
1438         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
1439 
1440         #------------
1441 
1442         mainSizer.Add(self.demo, 0, wx.ALL, 10)
1443         mainSizer.Add(wx.StaticLine(self.panel),
1444                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
1445         mainSizer.Add(self.tc, 1, wx.EXPAND | wx.ALL, 15)
1446         mainSizer.Add(hBox1, 0, wx.ALL, 5)
1447         mainSizer.Add(hBox2, 0, wx.ALL, 5)
1448 
1449         #------------
1450 
1451         # Finally, tell the panel to use the mainSizer for layout.
1452         self.panel.SetSizer(mainSizer)
1453 
1454 
1455     def OnPrintPreview(self, event):
1456         text = self.tc.GetValue()
1457         resultat = text.splitlines()
1458         self.ptbl.data = (resultat)
1459         self.ptbl.Preview()
1460 
1461 
1462     def OnPrint(self, event):
1463         text = self.tc.GetValue()
1464         resultat = text.splitlines()
1465         self.ptbl.data = (resultat)
1466         self.ptbl.Print()
1467 
1468 
1469     def OnClose(self, evt):
1470         self.Close()
1471 
1472 
1473     def OnCloseWindow(self, event):
1474         """
1475         ...
1476         """
1477 
1478         self.Destroy()
1479 
1480 #-------------------------------------------------------------------------------
1481 
1482 class App(wx.App):
1483     """
1484     ...
1485     """
1486     def OnInit(self):
1487 
1488         #------------
1489 
1490         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
1491 
1492         #------------
1493 
1494         frame = Frame(None, id=-1)
1495         self.SetTopWindow(frame)
1496         frame.Show(True)
1497 
1498         return True
1499 
1500 #-------------------------------------------------------------------------------
1501 
1502 def main():
1503     app = App(False)
1504     app.MainLoop()
1505 
1506 #-------------------------------------------------------------------------------
1507 
1508 if __name__ == "__main__" :
1509     main()


Note : you should create the printing data structures only for printing and destroy them after printing again. There is no point in storing them permanently as self.grdprt.

Thanks to Dietmar Schwertberger for this info.


Special concerns or comments about the Easy Printing approach :


Easy html direct printing

img_sample_six.png

   1 # sample_six.py
   2 
   3 import os
   4 import wx
   5 from wx.html import HtmlEasyPrinting
   6 from wx.html import HtmlWindow
   7 
   8 # class MyHtmlPrinter
   9 # class MyFrame
  10 # class MyApp
  11 
  12 #-------------------------------------------------------------------------------
  13 
  14 if os.name == "posix":
  15     print("\nPlatform : UNIX - Linux")
  16 elif os.name in ['nt', 'dos', 'ce']:
  17     print("\nPlatform : Windows")
  18 else:
  19     print("\nPlatform : ", platform.system())
  20 
  21 #-------------------------------------------------------------------------------
  22 
  23 # Sample html.
  24 sample_html = """<html>
  25 <body>
  26 <h2><FONT COLOR=\"blue\">Sample printing </FONT></h2>
  27 <p><B>Vestibulum</B> in tellus non nunc mollis sagittis sit amet ac purus.
  28 Nam convallis vulputate tortor nec elementum. Nunc dictum accumsan
  29 arcu ut lacinia. Nullam enim neque, consequat quis bibendum vitae,
  30 gravida nec arcu. Nullam molestie dapibus sapien quis consectetur.
  31 Donec lacinia, ante non faucibus ornare, purus sapien venenatis
  32 turpis, ut eleifend lorem purus eu nisl. Pellentesque eget leo a augue
  33 ullamcorper interdum at et nibh. Sed aliquet convallis dui, id
  34 condimentum orci viverra ac. Morbi quis mauris nisl, vel malesuada
  35 libero. Nam eleifend odio velit. Nulla vulputate facilisis mi
  36 tincidunt tempus. Nam eu metus elit. <B>Vestibulum</B> ante ipsum primis in
  37 faucibus orci luctus et ultrices posuere cubilia Curae; <B>Vestibulum</B> eu
  38 risus accumsan leo egestas rutrum vitae in urna. Morbi diam orci,
  39 eleifend a tempor sit amet, cursus sit amet est.</p>
  40 <p><FONT COLOR=\"red\">WxPython </FONT><B>HtmlEasyPrinting </B>test.</p>
  41 </body>
  42 </html>"""
  43 
  44 #-------------------------------------------------------------------------------
  45 
  46 class MyHtmlPrinter(HtmlEasyPrinting):
  47     """
  48     ...
  49     """
  50     def __init__(self, parent):
  51 
  52         # Get the window name.
  53         name = "My document"
  54 
  55         # Init the HtmlEasyPrinting.
  56         HtmlEasyPrinting.__init__(self, name, parent)
  57 
  58         # Get the current script directory.
  59         self.current_dir = os.path.normpath(os.path.dirname(__file__))
  60 
  61         # Set some default printer and page options.
  62         self.GetPrintData().SetPaperId(wx.PAPER_LETTER)  # wx.PAPER_A4
  63         self.GetPrintData().SetOrientation(wx.LANDSCAPE)  # wx.PORTRAIT
  64         # Black and white printing if False.
  65         self.GetPrintData().SetColour(True)
  66         self.GetPageSetupData().SetMarginTopLeft((20, 20))
  67         self.GetPageSetupData().SetMarginBottomRight((20, 20))
  68 
  69     #---------------------------------------------------------------------------
  70 
  71     def page_setup(self):
  72         """
  73         Show page setup.
  74         """
  75 
  76         self.PageSetup()
  77 
  78 
  79     def print_text(self, text):
  80         """
  81         Print the text.
  82         """
  83 
  84         return self.PrintText(text, basepath=self.current_dir)
  85 
  86 
  87     def preview_text(self, text):
  88         """
  89         Preview html text.
  90         """
  91 
  92         # @DATE @ is replaced by the current date in default format.
  93         # @PAGENUM@ is replaced by page number.
  94         # @PAGESCNT@ is replaced by total number of pages.
  95         # @TIME @ is replaced by the current time in default format.
  96         # @TITLE@ is replaced with the title of the document.
  97 
  98         header = "My document"
  99         footer = "Page @PAGENUM@ of @PAGESCNT@"
 100 
 101         self.SetHeader(header)
 102         self.SetFooter(footer)
 103 
 104         return self.PreviewText(text, basepath=self.current_dir)
 105 
 106 
 107     def print_file(self, file):
 108         """
 109         Print the text.
 110         """
 111 
 112         return self.PrintFile(file)
 113 
 114 
 115     def preview_file(self, file):
 116         """
 117         Preview html file.
 118         """
 119 
 120         return self.PreviewFile(file)
 121 
 122 #-------------------------------------------------------------------------------
 123 
 124 class MyFrame(wx.Frame):
 125     """
 126     Create a main frame for my application.
 127     """
 128     def __init__ (self, parent, id, title=""):
 129         wx.Frame.__init__(self,
 130                           parent,
 131                           id,
 132                           title,
 133                           size=(600, 610),
 134                           style=wx.DEFAULT_FRAME_STYLE)
 135 
 136         #------------
 137 
 138         # Simplified init method.
 139         self.SetProperties()
 140         self.CreateMenu()
 141         self.CreateCtrls()
 142         self.CreatePrinter()
 143         self.BindEvents()
 144         self.DoLayout()
 145 
 146         #------------
 147 
 148         self.CenterOnScreen()
 149 
 150     #---------------------------------------------------------------------------
 151 
 152     def SetProperties(self):
 153         """
 154         Set the main frame properties (title, icon...).
 155         """
 156 
 157         self.SetTitle("Html easy printing...")
 158 
 159 
 160     def CreateMenu(self):
 161         """
 162         Make the frame menus.
 163         """
 164 
 165         menub = wx.MenuBar()
 166 
 167         fmenu = wx.Menu()
 168         fmenu.Append(wx.ID_PAGE_SETUP, "Page set&up\tCtrl+U")
 169         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
 170         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
 171         fmenu.AppendSeparator()
 172         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
 173         menub.Append(fmenu, "&File")
 174 
 175         self.SetMenuBar(menub)
 176 
 177 
 178     def CreateCtrls(self):
 179         """
 180         Make widgets for my application.
 181         """
 182 
 183         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 184         font.SetWeight(wx.BOLD)
 185         font.SetPointSize(10)
 186 
 187         #------------
 188 
 189         # First create the controls.
 190         self.panel = wx.Panel(self,
 191                               id=-1,
 192                               style=wx.BORDER_THEME|
 193                               wx.TAB_TRAVERSAL)
 194 
 195         self.demo = wx.StaticText(self.panel,
 196                                   id=-1,
 197                                   label="Demonstrating :")
 198         self.demo.SetFont(font)
 199 
 200         self.winHtml = HtmlWindow(self.panel,
 201                                   id=-1,
 202                                   style=wx.BORDER_THEME|
 203                                   wx.NO_FULL_REPAINT_ON_RESIZE)
 204         self.winHtml.SetPage(sample_html)
 205 
 206         self.info = wx.StaticText(self.panel,
 207                                   id=-1,
 208                                   label="1) Direct printing,\n"
 209                                         "2) HtmlWindow,\n"
 210                                         "3) HtmlEasyPrinting class,\n"
 211                                         "4) Preview,\n"
 212                                         "5) Menu,\n"
 213                                         "6) Page setup.")
 214         self.info.SetForegroundColour("red")
 215         font.SetWeight(wx.NORMAL)
 216         self.info.SetFont(font)
 217 
 218         self.btnSetup = wx.Button(self.panel,
 219                                   id=wx.ID_PAGE_SETUP,
 220                                   label="Page set&up")
 221 
 222         self.btnPreview = wx.Button(self.panel,
 223                                     wx.ID_PREVIEW,
 224                                     label="Pre&view text")
 225         self.btnPreview.SetFocus()
 226 
 227         self.btnPrint = wx.Button(self.panel,
 228                                   id=wx.ID_PRINT,
 229                                   label="&Print")
 230 
 231         self.btnClose = wx.Button(self.panel,
 232                                   id=wx.ID_CLOSE,
 233                                   label="E&xit")
 234 
 235 
 236     def CreatePrinter(self):
 237         """
 238         Create the printer.
 239         """
 240 
 241         self.printer = MyHtmlPrinter(self)
 242 
 243 
 244     def BindEvents(self):
 245         """
 246         Bind all the events related to my application.
 247         """
 248 
 249         # Bind some menu events to an events handler.
 250         self.Bind(wx.EVT_MENU, self.OnBtnPageSetup, id=wx.ID_PAGE_SETUP)
 251         self.Bind(wx.EVT_MENU, self.OnBtnPreview, id=wx.ID_PREVIEW)
 252         self.Bind(wx.EVT_MENU, self.OnBtnPrint, id=wx.ID_PRINT)
 253         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 254 
 255         # Bind some buttons events to an events handler.
 256         self.Bind(wx.EVT_BUTTON, self.OnBtnPageSetup, self.btnSetup)
 257         self.Bind(wx.EVT_BUTTON, self.OnBtnPreview, self.btnPreview)
 258         self.Bind(wx.EVT_BUTTON, self.OnBtnPrint, self.btnPrint)
 259         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 260 
 261         # Bind the close event to an event handler.
 262         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 263 
 264 
 265     def DoLayout(self):
 266         """
 267         Manage widgets Layout.
 268         """
 269 
 270         # MainSizer is the top-level one that manages everything.
 271         mainSizer = wx.BoxSizer(wx.VERTICAL)
 272 
 273         #------------
 274 
 275         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 276         hBox1.Add(self.info, 0, wx.ALL, 15)
 277 
 278         #------------
 279 
 280         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 281         hBox2.Add(self.btnSetup, 0, wx.ALL, 10)
 282         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
 283         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
 284         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 285 
 286         #------------
 287 
 288         mainSizer.Add(self.demo, 0, wx.ALL, 10)
 289         mainSizer.Add(wx.StaticLine(self.panel),
 290                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 291         mainSizer.Add(self.winHtml, 1, wx.EXPAND | wx.ALL, 15)
 292         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 293         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 294 
 295         #------------
 296 
 297         # Finally, tell the panel to use the mainSizer for layout.
 298         self.panel.SetSizer(mainSizer)
 299 
 300 
 301     def OnBtnPageSetup(self, event):
 302         """
 303         Page setup click.
 304         """
 305 
 306         # Page setup dialog.
 307         self.printer.page_setup()
 308 
 309 
 310     def OnBtnPreview(self, event):
 311         """
 312         Print preview click.
 313         """
 314 
 315         # Preview html text.
 316         print("Preview result :", self.printer.preview_text(sample_html))
 317 
 318 
 319     def OnBtnPrint(self, event):
 320         """
 321         Print click.
 322         """
 323 
 324         # Print html text.
 325         print("Print result :", self.printer.print_text(sample_html))
 326 
 327 
 328     def OnBtnClose(self, event):
 329         """
 330         Close application.
 331         """
 332 
 333         self.Close(True)
 334 
 335 
 336     def OnCloseWindow(self, event):
 337         """
 338         Destroy application.
 339         """
 340 
 341         self.Destroy()
 342 
 343 #-------------------------------------------------------------------------------
 344 
 345 class MyApp(wx.App):
 346     """
 347     wx.App sub-class that is the example application.
 348     """
 349     def OnInit(self):
 350         """
 351         Init MyApp instance.
 352         """
 353 
 354         #------------
 355 
 356         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 357 
 358         #------------
 359 
 360         frame = MyFrame(None, id=-1)
 361         self.SetTopWindow(frame)
 362         frame.Show(True)
 363 
 364         return True
 365 
 366 #-------------------------------------------------------------------------------
 367 
 368 def main():
 369     app = MyApp(False)
 370     app.MainLoop()
 371 
 372 #-------------------------------------------------------------------------------
 373 
 374 if __name__ == "__main__" :
 375     main()


Easy html multilines printing

img_sample_seven.png

   1 # sample_seven.py
   2 
   3 import os
   4 import wx
   5 from wx.html import HtmlEasyPrinting
   6 
   7 # class MyHtmlPrinter
   8 # class MyFrame
   9 # class MyApp
  10 
  11 #-------------------------------------------------------------------------------
  12 
  13 if os.name == "posix":
  14     print("\nPlatform : UNIX - Linux")
  15 elif os.name in ['nt', 'dos', 'ce']:
  16     print("\nPlatform : Windows")
  17 else:
  18     print("\nPlatform : ", platform.system())
  19 
  20 #-------------------------------------------------------------------------------
  21 
  22 class MyHtmlPrinter(HtmlEasyPrinting):
  23     """
  24     ...
  25     """
  26     def __init__(self, parent):
  27 
  28         # Get the window name.
  29         name = "My document"
  30 
  31         # Init the HtmlEasyPrinting.
  32         HtmlEasyPrinting.__init__(self, name, parent)
  33 
  34         # Get the current script directory.
  35         self.current_dir = os.path.normpath(os.path.dirname(__file__))
  36 
  37         # Set some default printer and page options.
  38         self.GetPrintData().SetPaperId(wx.PAPER_LETTER)  # wx.PAPER_A4
  39         self.GetPrintData().SetOrientation(wx.LANDSCAPE)  # wx.PORTRAIT
  40         # Black and white printing if False.
  41         self.GetPrintData().SetColour(True)
  42         self.GetPageSetupData().SetMarginTopLeft((20, 20))
  43         self.GetPageSetupData().SetMarginBottomRight((20, 20))
  44 
  45     #---------------------------------------------------------------------------
  46 
  47     def GetHtmlText(self, text):
  48         """
  49         Simple conversion of text.
  50         Use a more powerful version.
  51         """
  52 
  53         html_text = text.replace("\n\n", "<P>")
  54         html_text = text.replace("\n", "<BR>")
  55 
  56         return html_text
  57 
  58 
  59     def page_setup(self):
  60         """
  61         Show page setup.
  62         """
  63 
  64         self.PageSetup()
  65 
  66 
  67     def print_text(self, text):
  68         """
  69         Print the text.
  70         """
  71 
  72         return self.PrintText(self.GetHtmlText(text), basepath=self.current_dir)
  73 
  74 
  75     def preview_text(self, text):
  76         """
  77         Preview html text.
  78         """
  79 
  80         # @DATE @ is replaced by the current date in default format.
  81         # @PAGENUM@ is replaced by page number.
  82         # @PAGESCNT@ is replaced by total number of pages.
  83         # @TIME @ is replaced by the current time in default format.
  84         # @TITLE@ is replaced with the title of the document.
  85 
  86         header = "My document"
  87         footer = "Page @PAGENUM@ of @PAGESCNT@"
  88 
  89         self.SetHeader(header)
  90         self.SetFooter(footer)
  91 
  92         return self.PreviewText(self.GetHtmlText(text), basepath=self.current_dir)
  93 
  94 
  95     def print_file(self, file):
  96         """
  97         Print the text.
  98         """
  99 
 100         return self.PrintFile(file)
 101 
 102 
 103     def preview_file(self, file):
 104         """
 105         Preview html file.
 106         """
 107 
 108         return self.PreviewFile(file)
 109 
 110 #-------------------------------------------------------------------------------
 111 
 112 class MyFrame(wx.Frame):
 113     """
 114     Create a main frame for my application.
 115     """
 116     def __init__ (self, parent, id, title=""):
 117         wx.Frame.__init__(self,
 118                           parent,
 119                           id,
 120                           title,
 121                           size=(600, 450),
 122                           style=wx.DEFAULT_FRAME_STYLE)
 123 
 124         #------------
 125 
 126         # Simplified init method.
 127         self.SetProperties()
 128         self.CreateMenu()
 129         self.CreateCtrls()
 130         self.CreatePrinter()
 131         self.BindEvents()
 132         self.DoLayout()
 133 
 134         #------------
 135 
 136         self.CenterOnScreen()
 137 
 138     #---------------------------------------------------------------------------
 139 
 140     def SetProperties(self):
 141         """
 142         Set the main frame properties (title, icon...).
 143         """
 144 
 145         self.SetTitle("Html easy printing...")
 146 
 147 
 148     def CreateMenu(self):
 149         """
 150         Make the frame menus.
 151         """
 152 
 153         menub = wx.MenuBar()
 154 
 155         fmenu = wx.Menu()
 156         fmenu.Append(wx.ID_PAGE_SETUP, "Page set&up\tCtrl+U")
 157         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
 158         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
 159         fmenu.AppendSeparator()
 160         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
 161         menub.Append(fmenu, "&File")
 162 
 163         self.SetMenuBar(menub)
 164 
 165 
 166     def CreateCtrls(self):
 167         """
 168         Make widgets for my application.
 169         """
 170 
 171         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 172         font.SetWeight(wx.BOLD)
 173         font.SetPointSize(10)
 174 
 175         #------------
 176 
 177         # First create the controls.
 178         self.panel = wx.Panel(self,
 179                               id=-1,
 180                               style=wx.BORDER_THEME|
 181                               wx.TAB_TRAVERSAL)
 182 
 183         self.demo = wx.StaticText(self.panel,
 184                                   id=-1,
 185                                   label="Demonstrating :")
 186         self.demo.SetFont(font)
 187 
 188         self.info = wx.StaticText(self.panel,
 189                                   id=-1,
 190                                   label="1) Direct printing,\n"
 191                                         "2) HtmlEasyPrinting class,\n"
 192                                         "3) Preview,\n"
 193                                         "4) Menu,\n"
 194                                         "5) Page setup.")
 195         self.info.SetForegroundColour("red")
 196         font.SetWeight(wx.NORMAL)
 197         self.info.SetFont(font)
 198 
 199         text = ('This the first line of text.\n'\
 200                 'This is the second line\nand the third. The fourth will be the number 4.0.\n'\
 201                 '4.0\n'\
 202                 'This is the fifth line, but by design it is too long to fit in the width of a standard'\
 203                 'page, so it will be forced to wrap around in order to fit without having'\
 204                 'some of its verbose verbage truncated.\n'\
 205                 'Here we have the final line.')
 206 
 207         self.tc = wx.TextCtrl(self.panel,
 208                               id=-1,
 209                               size=(200, -1),
 210                               value=text,
 211                               style=wx.TE_MULTILINE|wx.TE_DONTWRAP)
 212 
 213         self.btnSetup = wx.Button(self.panel,
 214                                   id=wx.ID_PAGE_SETUP,
 215                                   label="Page set&up")
 216 
 217         self.btnPreview = wx.Button(self.panel,
 218                                     wx.ID_PREVIEW,
 219                                     label="Pre&view text")
 220         self.btnPreview.SetFocus()
 221 
 222         self.btnPrint = wx.Button(self.panel,
 223                                   id=wx.ID_PRINT,
 224                                   label="&Print")
 225 
 226         self.btnClose = wx.Button(self.panel,
 227                                   id=wx.ID_CLOSE,
 228                                   label="E&xit")
 229 
 230 
 231     def CreatePrinter(self):
 232         """
 233         Create the printer.
 234         """
 235 
 236         self.printer = MyHtmlPrinter(self)
 237 
 238 
 239     def BindEvents(self):
 240         """
 241         Bind all the events related to my application.
 242         """
 243 
 244         # Bind some menu events to an events handler.
 245         self.Bind(wx.EVT_MENU, self.OnBtnPageSetup, id=wx.ID_PAGE_SETUP)
 246         self.Bind(wx.EVT_MENU, self.OnBtnPreview, id=wx.ID_PREVIEW)
 247         self.Bind(wx.EVT_MENU, self.OnBtnPrint, id=wx.ID_PRINT)
 248         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 249 
 250         # Bind some buttons events to an events handler.
 251         self.Bind(wx.EVT_BUTTON, self.OnBtnPageSetup, self.btnSetup)
 252         self.Bind(wx.EVT_BUTTON, self.OnBtnPreview, self.btnPreview)
 253         self.Bind(wx.EVT_BUTTON, self.OnBtnPrint, self.btnPrint)
 254         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 255 
 256         # Bind the close event to an event handler.
 257         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 258 
 259 
 260     def DoLayout(self):
 261         """
 262         Manage widgets Layout.
 263         """
 264 
 265         # MainSizer is the top-level one that manages everything.
 266         mainSizer = wx.BoxSizer(wx.VERTICAL)
 267 
 268         #------------
 269 
 270         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 271         hBox1.Add(self.info, 0, wx.ALL, 15)
 272 
 273         #------------
 274 
 275         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 276         hBox2.Add(self.btnSetup, 0, wx.ALL, 10)
 277         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
 278         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
 279         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 280 
 281         #------------
 282 
 283         mainSizer.Add(self.demo, 0, wx.ALL, 10)
 284         mainSizer.Add(wx.StaticLine(self.panel),
 285                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 286         mainSizer.Add(self.tc, 1, wx.EXPAND | wx.ALL, 15)
 287         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 288         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 289 
 290         #------------
 291 
 292         # Finally, tell the panel to use the mainSizer for layout.
 293         self.panel.SetSizer(mainSizer)
 294 
 295 
 296     def OnBtnPageSetup(self, event):
 297         """
 298         Page setup click.
 299         """
 300 
 301         # Page setup dialog.
 302         self.printer.page_setup()
 303 
 304 
 305     def OnBtnPreview(self, event):
 306         """
 307         Print preview click.
 308         """
 309 
 310         self.sample_html = self.tc.GetValue()
 311 
 312         # Preview html text.
 313         print("Preview result :", self.printer.preview_text(self.sample_html))
 314 
 315 
 316     def OnBtnPrint(self, event):
 317         """
 318         Print click.
 319         """
 320 
 321         self.sample_html = self.tc.GetValue()
 322 
 323         # Print html text.
 324         print("Print result :", self.printer.print_text(self.sample_html))
 325 
 326 
 327     def OnBtnClose(self, event):
 328         """
 329         Close application.
 330         """
 331 
 332         self.Close(True)
 333 
 334 
 335     def OnCloseWindow(self, event):
 336         """
 337         Destroy application.
 338         """
 339 
 340         self.Destroy()
 341 
 342 #-------------------------------------------------------------------------------
 343 
 344 class MyApp(wx.App):
 345     """
 346     wx.App sub-class that is the example application.
 347     """
 348     def OnInit(self):
 349         """
 350         Init MyApp instance.
 351         """
 352 
 353         #------------
 354 
 355         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 356 
 357         #------------
 358 
 359         frame = MyFrame(None, id=-1)
 360         self.SetTopWindow(frame)
 361         frame.Show(True)
 362 
 363         return True
 364 
 365 #-------------------------------------------------------------------------------
 366 
 367 def main():
 368     app = MyApp(False)
 369     app.MainLoop()
 370 
 371 #-------------------------------------------------------------------------------
 372 
 373 if __name__ == "__main__" :
 374     main()


Easy html grid printing

img_sample_eight.png


HTML file : template.html

   1 <!doctype html>
   2 <html>
   3 <head>
   4   <meta http-equiv="Content-Type" content="text/html" charset="utf-8">
   5 </head>
   6 <body>
   7      <table width="50%" cellspacing='2' cellpadding='0' border='0' bgcolor="black">
   8 
   9              <tr>
  10                  <td align=center colspan="2" rowspan="1" width="20%" bgcolor="red">
  11                <table cellspacing="7" cellpadding="0" border="0"><tr><td align=center><b><font face="Tahoma" color="white" size="3">&nbsp;FIRSTNAME&nbsp;</font></b></td></tr></table>
  12            </td>
  13 
  14                  <td align=center  colspan="2" rowspan="1" width="80%" bgcolor="yellow">
  15                <table cellspacing="7" cellpadding="0" border="0"><tr><td align=center><b><font face="Tahoma" color="black" size="3">&nbsp;{{FIRSTNAME}}&nbsp;</font></b></td></tr></table>
  16            </td>
  17              </tr>
  18 
  19 
  20 
  21              <tr>
  22                  <td align=center colspan="2" rowspan="1" width="20%" bgcolor="red">
  23                <table cellspacing="7" cellpadding="0" border="0"><tr><td align=center><b><font face="Tahoma" color="white" size="3">&nbsp;SURNAME&nbsp;</font></b></td></tr></table>
  24            </td>
  25 
  26                  <td align=center  colspan="2" rowspan="1" width="80%" bgcolor="yellow">
  27                <table cellspacing="7" cellpadding="0" border="0"><tr><td align=center><b><font face="Tahoma" color="black" size="3">&nbsp;{{SURNAME}}&nbsp;</font></b></td></tr></table>
  28            </td>
  29              </tr>
  30 
  31 
  32 
  33              <tr>
  34                  <td align=center colspan="2" rowspan="1" width="20%" bgcolor="red">
  35                <table cellspacing="7" cellpadding="0" border="0"><tr><td align=center><b><font face="Tahoma" color="white" size="3">&nbsp;AGE&nbsp;</font></b></td></tr></table>
  36            </td>
  37 
  38                  <td align=center  colspan="2" rowspan="1" width="80%" bgcolor="yellow">
  39                <table cellspacing="7" cellpadding="0" border="0"><tr><td align=center><b><font face="Tahoma" color="black" size="3">&nbsp;{{AGE}}&nbsp;</font></b></td></tr></table>
  40            </td>
  41              </tr>
  42 
  43      </table>
  44 </body>
  45 </html>

   1 # sample_eight.py
   2 
   3 import os
   4 import sys
   5 import wx
   6 from wx.html import HtmlEasyPrinting
   7 from wx.html import HtmlWindow
   8 
   9 # class MyHtmlPrinter
  10 # class MyFrame
  11 # class MyApp
  12 
  13 app_dir = os.path.split(os.path.abspath(sys.argv[0]))[0]
  14 html_file = os.path.join(app_dir, "template.html")
  15 
  16 #-------------------------------------------------------------------------------
  17 
  18 if os.name == "posix":
  19     print("\nPlatform : UNIX - Linux")
  20 elif os.name in ['nt', 'dos', 'ce']:
  21     print("\nPlatform : Windows")
  22 else:
  23     print("\nPlatform : ", platform.system())
  24 
  25 #-------------------------------------------------------------------------------
  26 
  27 class MyHtmlPrinter(HtmlEasyPrinting):
  28     """
  29     ...
  30     """
  31     def __init__(self, parent):
  32 
  33         # Get the window name.
  34         name = "Person"
  35 
  36         # Init the HtmlEasyPrinting.
  37         HtmlEasyPrinting.__init__(self, name, parent)
  38 
  39         # Get the current script directory.
  40         self.current_dir = os.path.normpath(os.path.dirname(__file__))
  41 
  42         # Set some default printer and page options.
  43         self.GetPrintData().SetPaperId(wx.PAPER_LETTER)  # wx.PAPER_A4
  44         self.GetPrintData().SetOrientation(wx.LANDSCAPE)  # wx.PORTRAIT
  45         # Black and white printing if False.
  46         self.GetPrintData().SetColour(True)
  47         self.GetPageSetupData().SetMarginTopLeft((20, 20))
  48         self.GetPageSetupData().SetMarginBottomRight((20, 20))
  49 
  50     #---------------------------------------------------------------------------
  51 
  52     def page_setup(self):
  53         """
  54         Show page setup.
  55         """
  56 
  57         self.PageSetup()
  58 
  59 
  60     def print_text(self, text):
  61         """
  62         Print the text.
  63         """
  64 
  65         return self.PrintText(text, basepath=self.current_dir)
  66 
  67 
  68     def preview_text(self, text):
  69         """
  70         Preview html text.
  71         """
  72 
  73         # @DATE @ is replaced by the current date in default format.
  74         # @PAGENUM@ is replaced by page number.
  75         # @PAGESCNT@ is replaced by total number of pages.
  76         # @TIME @ is replaced by the current time in default format.
  77         # @TITLE@ is replaced with the title of the document.
  78 
  79         header = "Person :"
  80         footer = "Page @PAGENUM@ of @PAGESCNT@"
  81 
  82         self.SetHeader(header)
  83         self.SetFooter(footer)
  84 
  85         return self.PreviewText(text, basepath=self.current_dir)
  86 
  87 
  88     def print_file(self, file):
  89         """
  90         Print the text.
  91         """
  92 
  93         return self.PrintFile(file)
  94 
  95 
  96     def preview_file(self, file):
  97         """
  98         Preview html file.
  99         """
 100 
 101         return self.PreviewFile(file)
 102 
 103 #-------------------------------------------------------------------------------
 104 
 105 class MyFrame(wx.Frame):
 106     """
 107     Create a main frame for my application.
 108     """
 109     def __init__ (self, parent, id, title=""):
 110         wx.Frame.__init__(self,
 111                           parent,
 112                           id,
 113                           title,
 114                           size=(600, 417),
 115                           style=wx.DEFAULT_FRAME_STYLE)
 116 
 117         #------------
 118 
 119         # Sample html.
 120         self.sample_html = None
 121 
 122         #------------
 123 
 124         # Simplified init method.
 125         self.SetProperties()
 126         self.CreateMenu()
 127         self.CreateCtrls()
 128         self.CreatePrinter()
 129         self.BindEvents()
 130         self.DoLayout()
 131 
 132         #------------
 133 
 134         self.CenterOnScreen()
 135 
 136     #---------------------------------------------------------------------------
 137 
 138     def SetProperties(self):
 139         """
 140         Set the main frame properties (title, icon...).
 141         """
 142 
 143         self.SetTitle("Html easy printing...")
 144 
 145 
 146     def CreateMenu(self):
 147         """
 148         Make the frame menus.
 149         """
 150 
 151         menub = wx.MenuBar()
 152 
 153         fmenu = wx.Menu()
 154         fmenu.Append(wx.ID_PAGE_SETUP, "Page set&up\tCtrl+U")
 155         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
 156         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
 157         fmenu.AppendSeparator()
 158         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
 159         menub.Append(fmenu, "&File")
 160 
 161         self.SetMenuBar(menub)
 162 
 163 
 164     def CreateCtrls(self):
 165         """
 166         Make widgets for my application.
 167         """
 168 
 169         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 170         font.SetWeight(wx.BOLD)
 171         font.SetPointSize(10)
 172 
 173         #------------
 174 
 175         # First create the controls.
 176         self.panel = wx.Panel(self,
 177                               id=-1,
 178                               style=wx.BORDER_THEME|
 179                               wx.TAB_TRAVERSAL)
 180 
 181         self.demo = wx.StaticText(self.panel,
 182                                   id=-1,
 183                                   label="Demonstrating :")
 184         self.demo.SetFont(font)
 185 
 186         self.stFirstname = wx.StaticText(self.panel,
 187                                   id=-1,
 188                                   label="Firstname : ")
 189 
 190         self.tcFirstname = wx.TextCtrl(self.panel,
 191                                        id=-1,
 192                                        size=(200, -1),
 193                                        value="John")
 194 
 195         self.stSurname = wx.StaticText(self.panel,
 196                                   id=-1,
 197                                   label="Surname : ")
 198 
 199         self.tcSurname = wx.TextCtrl(self.panel,
 200                                      id=-1,
 201                                      size=(200, -1),
 202                                      value="Doe")
 203 
 204         self.stAge = wx.StaticText(self.panel,
 205                                   id=-1,
 206                                   label="Age : ")
 207 
 208         self.tcAge = wx.TextCtrl(self.panel,
 209                                        id=-1,
 210                                        size=(200, -1),
 211                                        value="32")
 212 
 213         self.info = wx.StaticText(self.panel,
 214                                   id=-1,
 215                                   label="1) Direct printing,\n"
 216                                         "2) HtmlEasyPrinting class,\n"
 217                                         "3) Html file loading,\n"
 218                                         "4) Preview,\n"
 219                                         "5) Menu,\n"
 220                                         "6) Page setup.")
 221         self.info.SetForegroundColour("red")
 222         font.SetWeight(wx.NORMAL)
 223         self.info.SetFont(font)
 224 
 225         self.btnSetup = wx.Button(self.panel,
 226                                   id=wx.ID_PAGE_SETUP,
 227                                   label="Page set&up")
 228 
 229         self.btnPreview = wx.Button(self.panel,
 230                                     wx.ID_PREVIEW,
 231                                     label="Pre&view text")
 232         self.btnPreview.SetFocus()
 233 
 234         self.btnPrint = wx.Button(self.panel,
 235                                   id=wx.ID_PRINT,
 236                                   label="&Print")
 237 
 238         self.btnClose = wx.Button(self.panel,
 239                                   id=wx.ID_CLOSE,
 240                                   label="E&xit")
 241 
 242 
 243     def CreatePrinter(self):
 244         """
 245         Create the printer.
 246         """
 247 
 248         self.printer = MyHtmlPrinter(self)
 249 
 250 
 251     def LoadTemplate(self, event):
 252         """
 253         Load html template.
 254         """
 255 
 256 
 257         sSurname = self.tcSurname.GetValue()
 258         sFirstname = self.tcFirstname.GetValue()
 259         sAge = self.tcAge.GetValue()
 260 
 261         #------------
 262 
 263         # Thanks to Pascal Faut.
 264         # Returns html file ("template.html").
 265         with open(html_file, "r") as MyTemplate:
 266             strTemplate = MyTemplate.read()
 267             self.sample_html = strTemplate
 268 
 269             self.sample_html = self.sample_html.replace("{{SURNAME}}", sSurname)
 270             self.sample_html = self.sample_html.replace("{{FIRSTNAME}}", sFirstname)
 271             self.sample_html = self.sample_html.replace("{{AGE}}", sAge)
 272 
 273 
 274     def BindEvents(self):
 275         """
 276         Bind all the events related to my application.
 277         """
 278 
 279         # Bind some menu events to an events handler.
 280         self.Bind(wx.EVT_MENU, self.OnBtnPageSetup, id=wx.ID_PAGE_SETUP)
 281         self.Bind(wx.EVT_MENU, self.OnBtnPreview, id=wx.ID_PREVIEW)
 282         self.Bind(wx.EVT_MENU, self.OnBtnPrint, id=wx.ID_PRINT)
 283         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 284 
 285         # Bind some buttons events to an events handler.
 286         self.Bind(wx.EVT_BUTTON, self.OnBtnPageSetup, self.btnSetup)
 287         self.Bind(wx.EVT_BUTTON, self.OnBtnPreview, self.btnPreview)
 288         self.Bind(wx.EVT_BUTTON, self.OnBtnPrint, self.btnPrint)
 289         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 290 
 291         # Bind the close event to an event handler.
 292         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 293 
 294 
 295     def DoLayout(self):
 296         """
 297         Manage widgets Layout.
 298         """
 299 
 300         # MainSizer is the top-level one that manages everything.
 301         mainSizer = wx.BoxSizer(wx.VERTICAL)
 302 
 303         #------------
 304 
 305         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 306         hBox1.Add(self.info, 0, wx.ALL, 15)
 307 
 308         #------------
 309 
 310         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 311         hBox2.Add(self.btnSetup, 0, wx.ALL, 10)
 312         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
 313         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
 314         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 315 
 316         #------------
 317 
 318         # wx.GridBagSizer(vgap=0, hgap=0).
 319         gSizer = wx.GridBagSizer(2, 2)
 320         gSizer.Add(self.stFirstname, (0, 0), span=(wx.DefaultSpan),
 321                    flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
 322         gSizer.Add(self.tcFirstname, (0, 1), span=wx.DefaultSpan)
 323 
 324         gSizer.Add(self.stSurname, (1, 0), span=wx.DefaultSpan,
 325                    flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
 326         gSizer.Add(self.tcSurname, (1, 1), span=wx.DefaultSpan)
 327 
 328         gSizer.Add(self.stAge, (2, 0), span=wx.DefaultSpan,
 329                    flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
 330         gSizer.Add(self.tcAge, (2, 1), span=wx.DefaultSpan)
 331 
 332         #------------
 333 
 334         mainSizer.Add(self.demo, 0, wx.ALL, 10)
 335         mainSizer.Add(wx.StaticLine(self.panel),
 336                       0, wx.EXPAND|wx.TOP, 5)
 337         mainSizer.Add(gSizer, 0, wx.ALL, 20)
 338         mainSizer.Add(hBox1, 0, wx.LEFT|wx.BOTTOM, 5)
 339         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 340 
 341         #------------
 342 
 343         # Finally, tell the panel to use the mainSizer for layout.
 344         self.panel.SetSizer(mainSizer)
 345 
 346 
 347     def OnBtnPageSetup(self, event):
 348         """
 349         Page setup click.
 350         """
 351 
 352         # Page setup dialog.
 353         self.printer.page_setup()
 354 
 355 
 356     def OnBtnPreview(self, event):
 357         """
 358         Print preview click.
 359         """
 360 
 361         # Load template.
 362         self.LoadTemplate(event)
 363 
 364         if self.sample_html is not None:
 365             # Preview html text.
 366             print("Preview result:", self.printer.preview_text(self.sample_html))
 367 
 368 
 369     def OnBtnPrint(self, event):
 370         """
 371         Print click.
 372         """
 373 
 374         # Load template.
 375         self.LoadTemplate(event)
 376 
 377         if self.sample_html is not None:
 378             # Print html text.
 379             print("Print result:", self.printer.print_text(self.sample_html))
 380 
 381 
 382     def OnBtnClose(self, event):
 383         """
 384         Close application.
 385         """
 386 
 387         self.Close(True)
 388 
 389 
 390     def OnCloseWindow(self, event):
 391         """
 392         Destroy application.
 393         """
 394 
 395         self.Destroy()
 396 
 397 #-------------------------------------------------------------------------------
 398 
 399 class MyApp(wx.App):
 400     """
 401     wx.App sub-class that is the example application.
 402     """
 403     def OnInit(self):
 404         """
 405         Init MyApp instance.
 406         """
 407 
 408         #------------
 409 
 410         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 411 
 412         #------------
 413 
 414         frame = MyFrame(None, id=-1)
 415         self.SetTopWindow(frame)
 416         frame.Show(True)
 417 
 418         return True
 419 
 420 #-------------------------------------------------------------------------------
 421 
 422 def main():
 423     app = MyApp(False)
 424     app.MainLoop()
 425 
 426 #-------------------------------------------------------------------------------
 427 
 428 if __name__ == "__main__" :
 429     main()


PDF file reading and printing :

First example

img_sample_nine_a.png

PDF file : wxpython.pdf

   1 # sample_nine_a.py
   2 
   3 import sys
   4 import os
   5 import platform
   6 import wx
   7 
   8 # class My_Frame
   9 # class My_App
  10 
  11 #-------------------------------------------------------------------------------
  12 
  13 if os.name == "posix":
  14     print("\nPlatform : UNIX - Linux")
  15 elif os.name in ['nt', 'dos', 'ce']:
  16     print("\nPlatform : Windows")
  17 else:
  18     print("\nPlatform : ", platform.system())
  19 
  20 #-------------------------------------------------------------------------------
  21 
  22 class My_Frame(wx.Frame):
  23     """
  24     Create a main frame for my application.
  25     """
  26     def __init__(self, parent, id, title=""):
  27         wx.Frame.__init__(self,
  28                           parent,
  29                           id,
  30                           title,
  31                           size=(350, 300),
  32                           style=wx.DEFAULT_FRAME_STYLE)
  33 
  34         #------------
  35 
  36         # Simplified init method.
  37         self.SetProperties()
  38         self.CreateMenu()
  39         self.CreateCtrls()
  40         self.BindEvents()
  41         self.DoLayout()
  42 
  43         #------------
  44 
  45         self.CenterOnScreen()
  46 
  47     #---------------------------------------------------------------------------
  48 
  49     def SetProperties(self):
  50         """
  51         Set the main frame properties (title, icon...).
  52         """
  53 
  54         self.SetTitle("Reading test...")
  55 
  56 
  57     def CreateMenu(self):
  58         """
  59         Make the frame menus.
  60         """
  61 
  62         menub = wx.MenuBar()
  63 
  64         fmenu = wx.Menu()
  65         fmenu.Append(-1, "Sho&w PDF\tCtrl+W")
  66         fmenu.AppendSeparator()
  67         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
  68         menub.Append(fmenu, "&File")
  69 
  70         self.SetMenuBar(menub)
  71 
  72 
  73     def CreateCtrls(self):
  74         """
  75         Make widgets for my application.
  76         """
  77 
  78         boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
  79         boldFont.SetWeight(wx.BOLD)
  80         boldFont.SetPointSize(10)
  81 
  82         #------------
  83 
  84         # First create the controls.
  85         self.panel = wx.Panel(self,
  86                               id=-1,
  87                               style=wx.BORDER_THEME|
  88                               wx.TAB_TRAVERSAL)
  89 
  90         self.text = wx.StaticText(self.panel,
  91                                   id=-1,
  92                                   label="Demonstrating :")
  93         self.text.SetFont(boldFont)
  94 
  95         self.info = wx.StaticText(self.panel,
  96                                   id=-1,
  97                                   label="> Read PDF file with installed default program.")
  98         self.info.SetForegroundColour("red")
  99 
 100         self.btnView = wx.Button(self.panel,
 101                                  id=-1,
 102                                  label="Sho&w PDF")
 103         self.btnView.SetFocus()
 104 
 105         self.btnClose = wx.Button(self.panel,
 106                                   id=wx.ID_CLOSE,
 107                                   label="E&xit")
 108 
 109 
 110     def BindEvents(self):
 111         """
 112         Bind all the events related to my application.
 113         """
 114 
 115         # Bind some menu events to an events handler.
 116         self.Bind(wx.EVT_MENU, self.OnBtnViewPdf, id=-1)
 117         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 118 
 119         # Bind the close event to an event handler.
 120         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 121 
 122         # Bind some buttons events to an events handler.
 123         self.Bind(wx.EVT_BUTTON, self.OnBtnViewPdf, self.btnView)
 124         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 125 
 126 
 127     def DoLayout(self):
 128         """
 129         Manage widgets Layout.
 130         """
 131 
 132         # MainSizer is the top-level one that manages everything.
 133         mainSizer = wx.BoxSizer(wx.VERTICAL)
 134 
 135         #------------
 136 
 137         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 138         hBox1.Add(self.info, 0, wx.ALL, 15)
 139 
 140         #------------
 141 
 142         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 143         hBox2.Add(self.btnView, 0, wx.ALL, 10)
 144         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 145 
 146         #------------
 147 
 148         mainSizer.Add(self.text, 0, wx.ALL, 10)
 149         mainSizer.Add(wx.StaticLine(self.panel),
 150                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 151         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 152         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 153 
 154         #------------
 155 
 156         # Finally, tell the panel to use the mainSizer for layout.
 157         self.panel.SetSizer(mainSizer)
 158 
 159 
 160     def OnBtnViewPdf(self, event):
 161         """
 162         Launch a PDF program to read the file.
 163         """
 164 
 165         wx.BeginBusyCursor()
 166         os.startfile("wxpython.pdf")
 167         wx.CallAfter(wx.EndBusyCursor)
 168 
 169 
 170     def OnBtnClose(self, event):
 171         """
 172         ...
 173         """
 174 
 175         self.Close(True)
 176 
 177 
 178     def OnCloseWindow(self, event):
 179         """
 180         ...
 181         """
 182 
 183         self.Destroy()
 184 
 185 #-------------------------------------------------------------------------------
 186 
 187 class My_App(wx.App):
 188     """
 189     ...
 190     """
 191     def OnInit(self):
 192 
 193         #------------
 194 
 195         frame = My_Frame(None, id=-1)
 196         self.SetTopWindow(frame)
 197         frame.Show(True)
 198 
 199         return True
 200 
 201 #-------------------------------------------------------------------------------
 202 
 203 def main():
 204     app = My_App(False)
 205     app.MainLoop()
 206 
 207 #-------------------------------------------------------------------------------
 208 
 209 if __name__ == "__main__" :
 210     main()


Second example

img_sample_nine_b.png

PDF file : wxpython.pdf

   1 # sample_nine_b.py
   2 
   3 import sys
   4 import os
   5 import platform
   6 import wx
   7 import webbrowser
   8 
   9 # class My_Frame
  10 # class My_App
  11 
  12 #-------------------------------------------------------------------------------
  13 
  14 if os.name == "posix":
  15     print("\nPlatform : UNIX - Linux")
  16 elif os.name in ['nt', 'dos', 'ce']:
  17     print("\nPlatform : Windows")
  18 else:
  19     print("\nPlatform : ", platform.system())
  20 
  21 #-------------------------------------------------------------------------------
  22 
  23 class My_Frame(wx.Frame):
  24     """
  25     Create a main frame for my application.
  26     """
  27     def __init__(self, parent, id, title=""):
  28         wx.Frame.__init__(self,
  29                           parent,
  30                           id,
  31                           title,
  32                           size=(350, 300),
  33                           style=wx.DEFAULT_FRAME_STYLE)
  34 
  35         #------------
  36 
  37         # Simplified init method.
  38         self.SetProperties()
  39         self.CreateMenu()
  40         self.CreateCtrls()
  41         self.BindEvents()
  42         self.DoLayout()
  43 
  44         #------------
  45 
  46         self.CenterOnScreen()
  47 
  48     #---------------------------------------------------------------------------
  49 
  50     def SetProperties(self):
  51         """
  52         Set the main frame properties (title, icon...).
  53         """
  54 
  55         self.SetTitle("Reading test...")
  56 
  57 
  58     def CreateMenu(self):
  59         """
  60         Make the frame menus.
  61         """
  62 
  63         menub = wx.MenuBar()
  64 
  65         fmenu = wx.Menu()
  66         fmenu.Append(-1, "Sho&w PDF\tCtrl+W")
  67         fmenu.AppendSeparator()
  68         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
  69         menub.Append(fmenu, "&File")
  70 
  71         self.SetMenuBar(menub)
  72 
  73 
  74     def CreateCtrls(self):
  75         """
  76         Make widgets for my application.
  77         """
  78 
  79         boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
  80         boldFont.SetWeight(wx.BOLD)
  81         boldFont.SetPointSize(10)
  82 
  83         #------------
  84 
  85         # First create the controls.
  86         self.panel = wx.Panel(self,
  87                               id=-1,
  88                               style=wx.BORDER_THEME|
  89                               wx.TAB_TRAVERSAL)
  90 
  91         self.text = wx.StaticText(self.panel,
  92                                   id=-1,
  93                                   label="Demonstrating :")
  94         self.text.SetFont(boldFont)
  95 
  96         self.info = wx.StaticText(self.panel,
  97                                   id=-1,
  98                                   label="> Read PDF file with default web browser.")
  99         self.info.SetForegroundColour("red")
 100 
 101         self.btnView = wx.Button(self.panel,
 102                                  id=-1,
 103                                  label="Sho&w PDF")
 104         self.btnView.SetFocus()
 105 
 106         self.btnClose = wx.Button(self.panel,
 107                                   id=wx.ID_CLOSE,
 108                                   label="E&xit")
 109 
 110 
 111     def BindEvents(self):
 112         """
 113         Bind all the events related to my application.
 114         """
 115 
 116         # Bind some menu events to an events handler.
 117         self.Bind(wx.EVT_MENU, self.OnBtnViewPdf, id=-1)
 118         self.Bind(wx.EVT_MENU, self.OnBtnClose, id=wx.ID_EXIT)
 119 
 120         # Bind the close event to an event handler.
 121         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 122 
 123         # Bind some buttons events to an events handler.
 124         self.Bind(wx.EVT_BUTTON, self.OnBtnViewPdf, self.btnView)
 125         self.Bind(wx.EVT_BUTTON, self.OnBtnClose, self.btnClose)
 126 
 127 
 128     def DoLayout(self):
 129         """
 130         Manage widgets Layout.
 131         """
 132 
 133         # MainSizer is the top-level one that manages everything.
 134         mainSizer = wx.BoxSizer(wx.VERTICAL)
 135 
 136         #------------
 137 
 138         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
 139         hBox1.Add(self.info, 0, wx.ALL, 15)
 140 
 141         #------------
 142 
 143         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
 144         hBox2.Add(self.btnView, 0, wx.ALL, 10)
 145         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
 146 
 147         #------------
 148 
 149         mainSizer.Add(self.text, 0, wx.ALL, 10)
 150         mainSizer.Add(wx.StaticLine(self.panel),
 151                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
 152         mainSizer.Add(hBox1, 0, wx.ALL, 5)
 153         mainSizer.Add(hBox2, 0, wx.ALL, 5)
 154 
 155         #------------
 156 
 157         # Finally, tell the panel to use the mainSizer for layout.
 158         self.panel.SetSizer(mainSizer)
 159 
 160 
 161     def OnBtnViewPdf(self, event):
 162         """
 163         Launch a PDF program to read the file.
 164         """
 165 
 166         wx.BeginBusyCursor()
 167         webbrowser.open_new("wxpython.pdf")
 168         wx.CallAfter(wx.EndBusyCursor)
 169 
 170 
 171     def OnBtnClose(self, event):
 172         """
 173         ...
 174         """
 175 
 176         self.Close(True)
 177 
 178 
 179     def OnCloseWindow(self, event):
 180         """
 181         ...
 182         """
 183 
 184         self.Destroy()
 185 
 186 #-------------------------------------------------------------------------------
 187 
 188 class My_App(wx.App):
 189     """
 190     ...
 191     """
 192     def OnInit(self):
 193 
 194         #------------
 195 
 196         frame = My_Frame(None, id=-1)
 197         self.SetTopWindow(frame)
 198         frame.Show(True)
 199 
 200         return True
 201 
 202 #-------------------------------------------------------------------------------
 203 
 204 def main():
 205     app = My_App(False)
 206     app.MainLoop()
 207 
 208 #-------------------------------------------------------------------------------
 209 
 210 if __name__ == "__main__" :
 211     main()


ReportLab (PDF Toolkit)

An Open Source Python library for generating PDFs and graphics.

You must install this package for use it :

pip install reportlab

Link :

https://pypi.org/project/reportlab/

https://www.reportlab.com/opensource/

https://www.blog.pythonlibrary.org/2012/06/27/reportlab-mixing-fixed-content-and-flowables/

http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/

http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/


PDFViewer (David Hughes)

The wx.lib.pdfviewer.pdfViewer class can display and print PDF files.

You must install Python bindings for the PDF rendering library MuPDF before use it :

pip install PyMuPDF

img_sample_ten.png

   1 # sample_ten.py
   2 
   3 import os
   4 import sys
   5 import wx
   6 
   7 try:
   8     from wx.lib.pdfviewer import pdfViewer, pdfButtonPanel
   9     havePyPdf = True
  10 except ImportError:
  11     havePyPdf = False
  12 
  13 # class My_Panel
  14 # class My_Frame
  15 # class My_App
  16 
  17 #-------------------------------------------------------------------------------
  18 
  19 class My_Panel(wx.Panel):
  20     """
  21     Create a panel for my frame.
  22     """
  23     def __init__(self, parent):
  24         wx.Panel.__init__(self, parent, -1)
  25 
  26         hsizer = wx.BoxSizer(wx.HORIZONTAL)
  27         vsizer = wx.BoxSizer(wx.VERTICAL)
  28 
  29         self.buttonpanel = pdfButtonPanel(self,
  30                                           wx.ID_ANY,
  31                                           wx.DefaultPosition,
  32                                           wx.DefaultSize,
  33                                           0)
  34 
  35         vsizer.Add(self.buttonpanel, 0,
  36                    wx.GROW|wx.ALIGN_CENTER_VERTICAL|
  37                    wx.LEFT|wx.RIGHT|wx.TOP, 5)
  38 
  39         self.viewer = pdfViewer(self,
  40                                 wx.ID_ANY,
  41                                 wx.DefaultPosition,
  42                                 wx.DefaultSize,
  43                                 wx.HSCROLL|wx.VSCROLL|
  44                                 wx.SUNKEN_BORDER)
  45 
  46         vsizer.Add(self.viewer, 1,
  47                    wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5)
  48 
  49         loadbutton = wx.Button(self,
  50                                wx.ID_ANY,
  51                                "Load PDF file",
  52                                wx.DefaultPosition,
  53                                wx.DefaultSize,
  54                                0)
  55 
  56         vsizer.Add(loadbutton, 0,
  57                    wx.ALIGN_CENTER|wx.ALL, 5)
  58 
  59         hsizer.Add(vsizer, 1,
  60                    wx.GROW|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5)
  61 
  62         self.SetSizer(hsizer)
  63         self.SetAutoLayout(True)
  64 
  65         # Introduce buttonpanel and viewer to each other.
  66         self.buttonpanel.viewer = self.viewer
  67         self.viewer.buttonpanel = self.buttonpanel
  68 
  69         self.Bind(wx.EVT_BUTTON, self.OnLoadButton, loadbutton)
  70 
  71     #---------------------------------------------------------------------------
  72 
  73     def OnLoadButton(self, event):
  74         """
  75         ...
  76         """
  77 
  78         dlg = wx.FileDialog(self, wildcard="*.pdf")
  79 
  80         if dlg.ShowModal() == wx.ID_OK:
  81             wx.BeginBusyCursor()
  82             self.viewer.LoadFile(dlg.GetPath())
  83             wx.EndBusyCursor()
  84 
  85         dlg.Destroy()
  86 
  87 #-------------------------------------------------------------------------------
  88 
  89 class My_Frame(wx.Frame):
  90     """
  91     Create a main frame for my application.
  92     """
  93     def __init__(self):
  94         style = (wx.DEFAULT_FRAME_STYLE)
  95         wx.Frame.__init__(self, None, -1,
  96                           title="PDFViewer (PyMuPDF)",
  97                           size=(700, 500),
  98                           style=style)
  99 
 100         #------------
 101 
 102         pnl = My_Panel(self)
 103 
 104         #------------
 105 
 106         self.CenterOnScreen(wx.BOTH)
 107 
 108         #------------
 109 
 110         self.Show(True)
 111 
 112 #-------------------------------------------------------------------------------
 113 
 114 class My_App(wx.App):
 115     """
 116     ...
 117     """
 118     def OnInit(self):
 119 
 120         #------------
 121 
 122         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 123 
 124         #------------
 125 
 126         frame = My_Frame()
 127         self.SetTopWindow(frame)
 128         frame.Show(True)
 129 
 130         return True
 131 
 132 #-------------------------------------------------------------------------------
 133 
 134 def main():
 135     app = My_App(False)
 136     app.MainLoop()
 137 
 138 #-------------------------------------------------------------------------------
 139 
 140 if __name__ == "__main__" :
 141     main()

Available with wxPython demo (Miscellaneous/PDFViewer).

Link :

https://pypi.org/project/PyMuPDF/

https://wxpython.org/Phoenix/docs/html/wx.lib.pdfviewer.html

https://github.com/pymupdf/PyMuPDF/wiki/GUI-scripts-to-display-a-PDF-using-wxPython-or-Tkinter


PDFWindow (only Win32)

Read PDF files (.pdf) with wxPython using wx.lib.pdfwin.PDFWindow class ActiveX control.

You must install this package for use it :

pip install comtypes

img_sample_eleven.png

PDF file : document.pdf

   1 # sample_eleven.py
   2 
   3 """
   4 
   5 Read PDF files (.pdf) with wxPython
   6 using wx.lib.pdfwin.PDFWindow class ActiveX control
   7 from wxPython's new wx.activex module, this allows one
   8 to use an ActiveX control, as if it would be wx.Window.
   9 it embeds the Adobe Acrobat Reader.
  10 This works only with Windows.
  11 
  12 """
  13 
  14 import os
  15 import sys
  16 import wx
  17 
  18 if wx.Platform == "__WXMSW__":
  19     from wx.lib.pdfwin import PDFWindow
  20 else:
  21     dlg = wx.MessageDialog(self,
  22                            message="This demo only works on Microsoft Windows.",
  23                            caption="Sorry",
  24                            style=wx.OK|
  25                                  wx.ICON_WARNING)
  26     dlg.ShowModal()
  27     dlg.Destroy()
  28 
  29 appDir = os.path.split(os.path.abspath(sys.argv[0]))[0]
  30 doc = os.path.join(appDir, "document.pdf")
  31 
  32 # class My_Frame
  33 # class My_App
  34 
  35 #-------------------------------------------------------------------------------
  36 
  37 class My_Frame(wx.Frame):
  38     def __init__(self, parent, id, title):
  39         wx.Frame.__init__(self, parent, -1,
  40                           title, size=(720, 600),
  41                           style=wx.DEFAULT_FRAME_STYLE |
  42                                 wx.NO_FULL_REPAINT_ON_RESIZE)
  43 
  44         #------------
  45 
  46         # Simplified init method.
  47         self.CreateCtrls()
  48         self.LoadPdf()
  49         self.BindEvents()
  50         self.DoLayout()
  51 
  52         #---------------------------------------------------------------
  53 
  54         self.CenterOnScreen()
  55 
  56     #-------------------------------------------------------------------
  57 
  58     def CreateCtrls(self):
  59         """
  60         ...
  61         """
  62 
  63         fontSize = self.GetFont().GetPointSize()
  64         boldFont = wx.Font(fontSize, wx.SWISS, wx.NORMAL, wx.BOLD)
  65 
  66         #------------
  67 
  68         self.panel = wx.Panel(self, -1)
  69 
  70         #------------
  71 
  72         # Add PDFWindow
  73         self.pdf = PDFWindow(self.panel, style=wx.SUNKEN_BORDER)
  74         self.pdf.setView("FitV")
  75         self.pdf.setPageMode("Bookmarks")
  76         self.pdf.setLayoutMode("SinglePage")
  77         self.pdf.setShowScrollbars(True)
  78 
  79         #------------
  80 
  81         # Add controls
  82         self.btn1 = wx.Button(self.panel, -1, "&Open")
  83         self.btn1.SetToolTip("Open PDF file.")
  84 
  85         self.btn2 = wx.Button(self.panel,  -1, "<<", size=(30, -1))
  86         self.btn2.SetToolTip("First page.")
  87         self.btn2.SetFont(boldFont)
  88 
  89         self.btn3 = wx.Button(self.panel, -1, "<", size=(30, -1))
  90         self.btn3.SetToolTip("Previous page.")
  91         self.btn3.SetFont(boldFont)
  92 
  93         self.btn4 = wx.Button(self.panel, -1, ">", size=(30, -1))
  94         self.btn4.SetToolTip("Next page.")
  95         self.btn4.SetFont(boldFont)
  96 
  97         self.btn5 = wx.Button(self.panel,  -1, ">>", size=(30, -1))
  98         self.btn5.SetToolTip("Last page.")
  99         self.btn5.SetFont(boldFont)
 100 
 101         self.txt1 = wx.StaticText(self.panel, -1, "   Go to page" )
 102         self.txtCtrl = wx.TextCtrl(self.panel, -1, "0", size=[30, -1])
 103 
 104         self.txt2 = wx.StaticText(self.panel, -1, "     Zoom")
 105         self.zoom = wx.Choice(self.panel, -1,
 106                               choices=["Default",
 107                                        "Fit",
 108                                        "FitH",
 109                                        "FitV",
 110                                        "25%",
 111                                        "50%",
 112                                        "75%",
 113                                        "100%",
 114                                        "125%",
 115                                        "200%",
 116                                        "400%"])
 117         self.zoom.SetSelection(0)
 118         self.zoom.SetToolTip("Zoom.")
 119 
 120         self.btn6 = wx.Button(self.panel, -1, "&Pr&int")
 121         self.btn6.SetToolTip("Print PDF file.")
 122 
 123         self.btn7 = wx.Button(self.panel, -1, "&Quit")
 124         self.btn7.SetToolTip("Quit application.")
 125 
 126 
 127     def BindEvents(self):
 128         """
 129         Bind all the events related to my frame.
 130         """
 131 
 132         self.Bind(wx.EVT_BUTTON, self.OnOpenBtn, self.btn1)
 133         self.Bind(wx.EVT_BUTTON, self.OnFirstPageBtn, self.btn2)
 134         self.Bind(wx.EVT_BUTTON, self.OnPrevPageBtn, self.btn3)
 135         self.Bind(wx.EVT_BUTTON, self.OnNextPageBtn, self.btn4)
 136         self.Bind(wx.EVT_BUTTON, self.OnLastPageBtn, self.btn5)
 137         self.Bind(wx.EVT_BUTTON, self.OnPrintBtn, self.btn6)
 138         self.Bind(wx.EVT_BUTTON, self.OnCloseBtn, self.btn7)
 139 
 140         self.Bind(wx.EVT_TEXT, self.OnGotoPage, self.txtCtrl)
 141         self.Bind(wx.EVT_CHOICE, self.OnZoom, self.zoom)
 142 
 143         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 144         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
 145 
 146 
 147     def DoLayout(self):
 148         """
 149         Manage widgets Layout.
 150         """
 151 
 152         # MainSizer is the top-level one that manages everything.
 153         sizer = wx.BoxSizer(wx.VERTICAL)
 154         sizer.Add(self.pdf, proportion=1, flag=wx.EXPAND)
 155 
 156         #------------
 157 
 158         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
 159         btnSizer.Add(self.btn1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 160         btnSizer.Add(self.btn2, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=2)
 161         btnSizer.Add(self.btn3, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=2)
 162         btnSizer.Add(self.btn4, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=2)
 163         btnSizer.Add(self.btn5, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=2)
 164         btnSizer.Add(self.txt1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 165         btnSizer.Add(self.txtCtrl, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 166         btnSizer.Add(self.txt2, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 167         btnSizer.Add(self.zoom, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 168         btnSizer.Add(self.btn6, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 169         btnSizer.Add(self.btn7, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
 170         btnSizer.Add((50,-1), proportion=2, flag=wx.EXPAND)
 171 
 172         #------------
 173 
 174         sizer.Add(btnSizer, proportion=0, flag=wx.EXPAND)
 175 
 176         #------------
 177 
 178         # Finally, tell the panel to use the mainSizer for layout.
 179         self.panel.SetSizer(sizer)
 180         self.panel.SetAutoLayout(True)
 181 
 182 
 183     def LoadPdf(self):
 184         """
 185         ...
 186         """
 187 
 188         self.pdf.LoadFile(doc)
 189 
 190 
 191     def OnOpenBtn(self, event):
 192         """
 193         ...
 194         """
 195 
 196         dlg = wx.FileDialog(self, wildcard="*.pdf")
 197 
 198         if dlg.ShowModal() == wx.ID_OK:
 199             wx.BeginBusyCursor()
 200             self.pdf.LoadFile(dlg.GetPath())
 201             wx.EndBusyCursor()
 202 
 203         dlg.Destroy()
 204 
 205 
 206     def OnFirstPageBtn(self, event):
 207         """
 208         ...
 209         """
 210 
 211         self.pdf.gotoFirstPage()
 212 
 213 
 214     def OnPrevPageBtn(self, event):
 215         """
 216         ...
 217         """
 218 
 219         self.pdf.gotoPreviousPage()
 220 
 221 
 222     def OnNextPageBtn(self, event):
 223         """
 224         ...
 225         """
 226 
 227         self.pdf.gotoNextPage()
 228 
 229 
 230     def OnLastPageBtn(self, event):
 231         """
 232         ...
 233         """
 234 
 235         self.pdf.gotoLastPage()
 236 
 237 
 238     def OnGotoPage(self, event):
 239         """
 240         ...
 241         """
 242 
 243         npage = event.GetEventObject().GetValue()
 244 
 245         try:
 246             self.pdf.setCurrentPage(int(npage))
 247         except ValueError:
 248             pass
 249 
 250 
 251     def OnZoom(self, event):
 252         """
 253         ...
 254         """
 255 
 256         astring = event.GetEventObject().GetStringSelection()
 257 
 258         if astring.startswith('Fit'):
 259             self.pdf.setView(astring)
 260         else:
 261             try:
 262                 percent = float(astring.replace('%',''))
 263                 self.pdf.setZoom(percent)
 264             except ValueError:
 265                 pass
 266 
 267 
 268     def OnPrintBtn(self, event):
 269         """
 270         ...
 271         """
 272 
 273         self.pdf.Print()
 274 
 275 
 276     def OnCloseBtn(self, event):
 277         """
 278         ...
 279         """
 280 
 281         self.Close(True)
 282 
 283 
 284     def OnEraseBackground(self, event):
 285         """
 286         ...
 287         """
 288 
 289         dc = event.GetDC()
 290 
 291         if not dc:
 292             dc = wx.ClientDC(self)
 293             rect = self.GetUpdateRegion().GetBox()
 294             dc.SetClippingRect(rect)
 295 
 296 
 297     def OnCloseWindow(self, event):
 298         """
 299         ...
 300         """
 301 
 302         self.Destroy()
 303 
 304 #-------------------------------------------------------------------------------
 305 
 306 class My_App(wx.App):
 307     """
 308     ...
 309     """
 310     def OnInit(self):
 311 
 312         #------------
 313 
 314         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
 315 
 316         #------------
 317 
 318         frame = My_Frame(None, -1, "PDFWindow (ActiveX)")
 319         self.SetTopWindow(frame)
 320         frame.Show(True)
 321 
 322         return True
 323 
 324 #-------------------------------------------------------------------------------
 325 
 326 def main():
 327     app = My_App(False)
 328     app.MainLoop()
 329 
 330 #-------------------------------------------------------------------------------
 331 
 332 if __name__ == "__main__" :
 333     main()

Available with wxPython demo (More Windows/Controls/ActiveX_PDFWindow).


PyMuPDF(Ruikai Liu / Jorj X. McKie)

MuPDF can access files in PDF, XPS, OpenXPS, epub, comic and fiction book formats, and it is known for both, its top performance and high rendering quality.

With PyMuPDF you therefore can access files with extensions *.pdf, *.xps, *.oxps, *.epub, *.cbz or *.fb2 from your Python scripts. A number of popular image formats is supported as well, including multi-page TIFF images.

PyMuPDF should run on all platforms that are supported by both, MuPDF and Python. These include, but are not limited to, Windows (XP/SP2 and up), Mac OSX and Linux, 32-bit or 64-bit. If you can generate MuPDF on a Python supported platform, then also PyMuPDF can be used there.

You must install Python bindings for the PDF rendering library MuPDF before use it :

pip install PyMuPDF

img_sample_twelve.png

   1 # sample_twelve.py
   2 
   3 """
   4 @created: 2015-10-23 13:40:00
   5 
   6 @author: Jorj X. McKie
   7 
   8 Let the user select a PyMuPDF-supported file and then scroll through it.
   9 
  10 Dependencies:
  11 PyMuPDF, wxPython 3.x
  12 
  13 License:
  14 GNU GPL 3.x, GNU AFFERO GPL 3
  15 
  16 Changes in PyMuPDF 1.9.2
  17 ------------------------
  18 - supporting Python 3 as wxPython now supports it
  19 - optionally show links in displayed pages
  20 - when clicking on a link, attempt to follow it
  21 - remove inline code for dialog icon and import from a library
  22 
  23 Changes in PyMuPDF 1.8.0
  24 ------------------------
  25 - display a fancy icon on the dialogs, defined as inline code in base64 format
  26 - display pages with a zoom factor of 120%
  27 - dynamically resize dialog to reflect each page's image size / orientation
  28 - minor cosmetic changes
  29 """
  30 from __future__ import print_function
  31 import sys
  32 print("Python:", sys.version)
  33 
  34 try:
  35     import wx
  36     print("wxPython:", wx.version())
  37 except:
  38     raise SystemExit(__file__ + " needs wxPython.")
  39 
  40 try:
  41     import fitz
  42     print(fitz.__doc__)
  43 except:
  44     raise SystemExit(__file__ + " needs PyMuPDF(fitz).")
  45 
  46 try:
  47     from PageFormat import FindFit
  48 except ImportError:
  49     def FindFit(*args):
  50         return "not implemented"
  51 
  52 try:
  53     from icons import ico_pdf            # PDF icon in upper left screen corner
  54     do_icon = True
  55 except ImportError:
  56     do_icon = False
  57 
  58 app = None
  59 app = wx.App()
  60 assert wx.VERSION[0:3] >= (3,0,2), "need wxPython 3.0.2 or later"
  61 assert tuple(map(int, fitz.VersionBind.split("."))) >= (1,9,2), "need PyMuPDF 1.9.2 or later"
  62 
  63 # make some adjustments for differences between wxPython versions 3.0.2 / 3.0.3
  64 if wx.VERSION[0:3] >= (3,0,3):
  65     cursor_hand  = wx.Cursor(wx.CURSOR_HAND)
  66     cursor_norm  = wx.Cursor(wx.CURSOR_DEFAULT)
  67     bmp_buffer = wx.Bitmap.FromBuffer
  68     phoenix = True
  69 else:
  70     cursor_hand  = wx.StockCursor(wx.CURSOR_HAND)
  71     cursor_norm  = wx.StockCursor(wx.CURSOR_DEFAULT)
  72     bmp_buffer = wx.BitmapFromBuffer
  73     phoenix = False
  74 
  75 if str != bytes:
  76     stringtypes = (str, bytes)
  77 else:
  78     stringtypes = (str, unicode)
  79 
  80 def getint(v):
  81     try:
  82         return int(v)
  83     except:
  84         pass
  85     if type(v) not in stringtypes:
  86         return 0
  87     a = "0"
  88     for d in v:
  89         if d in "0123456789":
  90             a += d
  91     return int(a)
  92 
  93 # abbreviations to get rid of those long pesky names ...
  94 #==============================================================================
  95 # Define our dialog as a subclass of wx.Dialog.
  96 # Only special thing is, that we are being invoked with a filename ...
  97 #==============================================================================
  98 class PDFdisplay(wx.Dialog):
  99     def __init__(self, parent, filename):
 100         defPos = wx.DefaultPosition
 101         defSiz = wx.DefaultSize
 102         zoom   = 1.2                        # zoom factor of display
 103         wx.Dialog.__init__ (self, parent, id = wx.ID_ANY,
 104             title = u"Display with PyMuPDF: ",
 105             pos = defPos, size = defSiz,
 106             style = wx.CAPTION|wx.CLOSE_BOX|
 107                     wx.DEFAULT_DIALOG_STYLE)
 108 
 109         #======================================================================
 110         # display an icon top left of dialog, append filename to title
 111         #======================================================================
 112         if do_icon:
 113             self.SetIcon(ico_pdf.img.GetIcon())      # set a screen icon
 114         self.SetTitle(self.Title + filename)
 115         self.SetBackgroundColour(wx.Colour(240, 230, 140))
 116 
 117         #======================================================================
 118         # open the document with MuPDF when dialog gets created
 119         #======================================================================
 120         self.doc = fitz.open(filename) # create Document object
 121         if self.doc.needsPass:         # check password protection
 122             self.decrypt_doc()
 123         if self.doc.isEncrypted:       # quit if we cannot decrpt
 124             self.Destroy()
 125             return
 126         self.dl_array = [0] * len(self.doc)
 127         self.last_page = -1            # memorize last page displayed
 128         self.link_rects = []           # store link rectangles here
 129         self.link_texts = []           # store link texts here
 130         self.current_idx = -1          # store entry of found rectangle
 131         self.current_lnks = []         # store entry of found rectangle
 132 
 133         #======================================================================
 134         # define zooming matrix for displaying PDF page images
 135         # we increase images by 20%, so take 1.2 as scale factors
 136         #======================================================================
 137         self.matrix = fitz.Matrix(zoom, zoom)    # will use a constant zoom
 138 
 139         '''
 140         =======================================================================
 141         Overall Dialog Structure:
 142         -------------------------
 143         szr10 (main sizer for the whole dialog - vertical orientation)
 144         +-> szr20 (sizer for buttons etc. - horizontal orientation)
 145           +-> button forward
 146           +-> button backward
 147           +-> field for page number to jump to
 148           +-> field displaying total pages
 149         +-> PDF image area
 150         =======================================================================
 151         '''
 152 
 153         # forward button
 154         self.ButtonNext = wx.Button(self, wx.ID_ANY, u"forw",
 155                            defPos, defSiz, wx.BU_EXACTFIT)
 156         # backward button
 157         self.ButtonPrevious = wx.Button(self, wx.ID_ANY, u"back",
 158                            defPos, defSiz, wx.BU_EXACTFIT)
 159         #======================================================================
 160         # text field for entering a target page. wx.TE_PROCESS_ENTER is
 161         # required to get data entry fired as events.
 162         #======================================================================
 163         self.TextToPage = wx.TextCtrl(self, wx.ID_ANY, u"1", defPos, wx.Size(40, -1),
 164                              wx.TE_RIGHT|wx.TE_PROCESS_ENTER)
 165         # displays total pages and page paper format
 166         self.statPageMax = wx.StaticText(self, wx.ID_ANY,
 167                               "of " + str(len(self.doc)) + " pages.",
 168                               defPos, defSiz, 0)
 169         self.links = wx.CheckBox( self, wx.ID_ANY, u"show links",
 170                            defPos, defSiz, wx.ALIGN_LEFT)
 171         self.links.Value = True
 172         self.paperform = wx.StaticText(self, wx.ID_ANY, "", defPos, defSiz, 0)
 173         # define the area for page images and load page 1 for primary display
 174         self.PDFimage = wx.StaticBitmap(self, wx.ID_ANY, self.pdf_show(1),
 175                            defPos, defSiz, style = 0)
 176         #======================================================================
 177         # the main sizer of the dialog
 178         #======================================================================
 179         self.szr10 = wx.BoxSizer(wx.VERTICAL)
 180         szr20 = wx.BoxSizer(wx.HORIZONTAL)
 181         szr20.Add(self.ButtonNext, 0, wx.ALL, 5)
 182         szr20.Add(self.ButtonPrevious, 0, wx.ALL, 5)
 183         szr20.Add(self.TextToPage, 0, wx.ALL, 5)
 184         szr20.Add(self.statPageMax, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
 185         szr20.Add( self.links, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
 186         szr20.Add(self.paperform, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
 187         # sizer ready, represents top dialog line
 188         self.szr10.Add(szr20, 0, wx.EXPAND, 5)
 189         self.szr10.Add(self.PDFimage, 0, wx.ALL, 5)
 190         # main sizer now ready - request final size & layout adjustments
 191         self.szr10.Fit(self)
 192         self.SetSizer(self.szr10)
 193         self.Layout()
 194         # center dialog on screen
 195         self.Centre(wx.BOTH)
 196 
 197         # Bind buttons and fields to event handlers
 198         self.ButtonNext.Bind(wx.EVT_BUTTON, self.NextPage)
 199         self.ButtonPrevious.Bind(wx.EVT_BUTTON, self.PreviousPage)
 200         self.TextToPage.Bind(wx.EVT_TEXT_ENTER, self.GotoPage)
 201         self.PDFimage.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
 202         self.PDFimage.Bind(wx.EVT_MOTION, self.move_mouse)
 203         self.PDFimage.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
 204 
 205 #==============================================================================
 206 # Button handlers and other functions
 207 #==============================================================================
 208     def OnLeftDown(self, evt):
 209         if self.current_idx < 0 or not self.links.Value:
 210             evt.Skip()
 211             return
 212         lnk = self.current_lnks[self.current_idx]
 213         if lnk["kind"] == fitz.LINK_GOTO:
 214             self.TextToPage.Value = str(lnk["page"] + 1)
 215             self.GotoPage(evt)
 216         elif lnk["kind"] == fitz.LINK_URI:
 217             import webbrowser
 218             try:
 219                 webbrowser.open_new(self.link_texts[self.current_idx])
 220             except:
 221                 pass
 222         elif lnk["kind"] == fitz.LINK_GOTOR:
 223             import subprocess
 224             try:
 225                 subprocess.Popen(self.link_texts[self.current_idx])
 226             except:
 227                 pass
 228         elif lnk["kind"] == fitz.LINK_NAMED:
 229             if lnk["name"] == "FirstPage":
 230                 self.TextToPage.Value = "1"
 231             elif lnk["name"] == "LastPage":
 232                 self.TextToPage.Value = str(len(self.doc))
 233             elif lnk["name"] == "NextPage":
 234                 self.TextToPage.Value = str(int(self.TextToPage.Value) + 1)
 235             elif lnk["name"] == "PrevPage":
 236                 self.TextToPage.Value = str(int(self.TextToPage.Value) - 1)
 237             self.GotoPage(evt)
 238         evt.Skip()
 239         return
 240 
 241     def move_mouse(self, evt):                   # show hand if in a rectangle
 242         if not self.links.Value:                 # do not process links
 243             evt.Skip()
 244             return
 245         if len(self.link_rects) == 0:
 246             evt.Skip()
 247             return
 248         pos = evt.GetPosition()
 249         self.current_idx = self.cursor_in_link(pos)   # get cursor link rect
 250 
 251         if self.current_idx >= 0:                     # if in a hot area
 252             self.PDFimage.SetCursor(cursor_hand)
 253             if phoenix:
 254                 self.PDFimage.SetToolTip(self.link_texts[self.current_idx])
 255             else:
 256                 self.PDFimage.SetToolTipString(self.link_texts[self.current_idx])
 257         else:
 258             self.PDFimage.SetCursor(cursor_norm)
 259             self.PDFimage.UnsetToolTip()
 260 
 261         evt.Skip()
 262         return
 263 
 264     def OnMouseWheel(self, evt):
 265         # process wheel as paging operations
 266         d = evt.GetWheelRotation()               # int indicating direction
 267         if d < 0:
 268             self.NextPage(evt)
 269         elif d > 0:
 270             self.PreviousPage(evt)
 271         return
 272 
 273     def NextPage(self, event):                   # means: page forward
 274         page = getint(self.TextToPage.Value) + 1 # current page + 1
 275         page = min(page, self.doc.pageCount)     # cannot go beyond last page
 276         self.TextToPage.Value = str(page)        # put target page# in screen
 277         self.NeuesImage(page)                    # refresh the layout
 278         event.Skip()
 279 
 280     def PreviousPage(self, event):               # means: page back
 281         page = getint(self.TextToPage.Value) - 1 # current page - 1
 282         page = max(page, 1)                      # cannot go before page 1
 283         self.TextToPage.Value = str(page)        # put target page# in screen
 284         self.NeuesImage(page)
 285         event.Skip()
 286 
 287     def GotoPage(self, event):                   # means: go to page number
 288         page = getint(self.TextToPage.Value)     # get page# from screen
 289         page = min(page, len(self.doc))          # cannot go beyond last page
 290         page = max(page, 1)                      # cannot go before page 1
 291         self.TextToPage.Value = str(page)        # make sure it's on the screen
 292         self.NeuesImage(page)
 293         event.Skip()
 294 
 295 #==============================================================================
 296 # Read / render a PDF page. Parameters are: pdf = document, page = page#
 297 #==============================================================================
 298     def NeuesImage(self, page):
 299         if page == self.last_page:
 300             return
 301         self.PDFimage.SetCursor(cursor_norm)
 302         self.PDFimage.UnsetToolTip()
 303         self.last_page = page
 304         self.link_rects = []
 305         self.link_texts = []
 306         bitmap = self.pdf_show(page)        # read page image
 307         if self.links.Value and len(self.current_lnks) > 0:     # show links?
 308             self.draw_links(bitmap, page)   # modify the bitmap
 309         self.PDFimage.SetBitmap(bitmap)     # put it in screen
 310         self.szr10.Fit(self)
 311         self.Layout()
 312         # image may be truncated, so we need to recalculate hot areas
 313         if len(self.current_lnks) > 0:
 314             isize = self.PDFimage.Size
 315             bsize = self.PDFimage.Bitmap.Size
 316             dis_x = (bsize[0] - isize[0]) / 2.
 317             dis_y = (bsize[1] - isize[1]) / 2.
 318             zoom_w = float(bsize[0]) / float(self.pg_ir.width)
 319             zoom_h = float(bsize[1]) / float(self.pg_ir.height)
 320             for l in self.current_lnks:
 321                 r = l["from"]
 322                 wx_r = wx.Rect(int(r.x0 * zoom_w - dis_x),
 323                            int(r.y0 * zoom_h) - dis_y,
 324                            int(r.width * zoom_w),
 325                            int(r.height * zoom_h))
 326                 self.link_rects.append(wx_r)
 327 
 328         return
 329 
 330     def cursor_in_link(self, pos):
 331         for i, r in enumerate(self.link_rects):
 332             if r.Contains(pos):
 333                 return i
 334         return -1
 335 
 336     def draw_links(self, bmp, pno):
 337         dc = wx.MemoryDC()
 338         dc.SelectObject(bmp)
 339         dc.SetPen(wx.Pen("BLUE", width=1))
 340         dc.SetBrush(wx.Brush("BLUE", style=wx.BRUSHSTYLE_TRANSPARENT))
 341         pg_w = self.pg_ir.x1 - self.pg_ir.x0
 342         pg_h = self.pg_ir.y1 - self.pg_ir.y0
 343         zoom_w = float(bmp.Size[0]) / float(pg_w)
 344         zoom_h = float(bmp.Size[1]) / float(pg_h)
 345         for lnk in self.current_lnks:
 346             r = lnk["from"].irect
 347             wx_r = wx.Rect(int(r.x0 * zoom_w),
 348                            int(r.y0 * zoom_h),
 349                            int(r.width * zoom_w),
 350                            int(r.height * zoom_h))
 351             dc.DrawRectangle(wx_r[0], wx_r[1], wx_r[2]+1, wx_r[3]+1)
 352             if lnk["kind"] == fitz.LINK_GOTO:
 353                 txt = "page " + str(lnk["page"] + 1)
 354             elif lnk["kind"] == fitz.LINK_GOTOR:
 355                 txt = lnk["file"]
 356             elif lnk["kind"] == fitz.LINK_URI:
 357                 txt = lnk["uri"]
 358             else:
 359                 txt = "unkown destination"
 360             self.link_texts.append(txt)
 361         dc.SelectObject(wx.NullBitmap)
 362         dc = None
 363         return
 364 
 365     def pdf_show(self, pg_nr):
 366         pno = int(pg_nr) - 1
 367         if self.dl_array[pno] == 0:
 368             self.dl_array[pno] = self.doc[pno].getDisplayList()
 369         dl = self.dl_array[pno]
 370         pix = dl.getPixmap(matrix = self.matrix, alpha = False)
 371         bmp = bmp_buffer(pix.w, pix.h, pix.samples)
 372         r = dl.rect
 373         paper = FindFit(r.x1, r.y1)
 374         self.paperform.Label = "Page format: " + paper
 375         if self.links.Value:
 376             self.current_lnks = self.doc[pno].getLinks()
 377             self.pg_ir = dl.rect.irect
 378         pix = None
 379         return bmp
 380 
 381     def decrypt_doc(self):
 382         # let user enter document password
 383         pw = None
 384         dlg = wx.TextEntryDialog(self, 'Please enter password below:',
 385                  'Document needs password to open', '',
 386                  style = wx.TextEntryDialogStyle|wx.TE_PASSWORD)
 387         while pw is None:
 388             rc = dlg.ShowModal()
 389             if rc == wx.ID_OK:
 390                 pw = str(dlg.GetValue().encode("utf-8"))
 391                 self.doc.authenticate(pw)
 392             else:
 393                 return
 394             if self.doc.isEncrypted:
 395                 pw = None
 396                 dlg.SetTitle("Wrong password. Enter correct one or cancel.")
 397         return
 398 
 399 #==============================================================================
 400 # main program
 401 #------------------------------------------------------------------------------
 402 # Show a standard FileSelect dialog to choose a file for display
 403 #==============================================================================
 404 # Wildcard: offer all supported filetypes for display
 405 wild = "*.pdf;*.xps;*.oxps;*.epub;*.cbz;*.fb2"
 406 
 407 #==============================================================================
 408 # define the file selection dialog
 409 #==============================================================================
 410 dlg = wx.FileDialog(None, message = "Choose a file to display",
 411                     wildcard = wild, style=wx.FD_OPEN|wx.FD_CHANGE_DIR)
 412 
 413 # We got a file only when one was selected and OK pressed
 414 if dlg.ShowModal() == wx.ID_OK:
 415     # This returns a Python list of selected files (we only have one though)
 416     filename = dlg.GetPath()
 417 else:
 418     filename = None
 419 
 420 # destroy this dialog
 421 dlg.Destroy()
 422 
 423 # only continue if we have a filename
 424 if filename:
 425     # create the dialog
 426     dlg = PDFdisplay(None, filename)
 427     # show it - this will only return for final housekeeping
 428     rc = dlg.ShowModal()
 429 
 430 app = None


Download source

source.zip


Additional Information

Link :

https://wiki.wxpython.org/MoreCommentsOnPrinting

https://wiki.wxpython.org/PrintingWithReportGenerators

http://www.blog.pythonlibrary.org/2012/06/17/an-intro-to-rst2pdf-changing-restructured-text-into-pdfs-with-python/

http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/

https://www.blog.pythonlibrary.org/2010/02/14/python-windows-and-printers/

- - - - -

https://wiki.wxpython.org/TitleIndex

https://docs.wxpython.org/


Thanks to

Lorne White, Jeff Grimmett, Vernon Cole, Robin Dunn, Andy Robinson / Robin Becker / The ReportLab team, David Hughe (PDFViewer), Ruikai Liu / Jorj X. McKie (PyMuPDF), Cody Precord, Mike Driscoll, Pascal Faut., Dietmar Schwertberger, Chris Barker and the wxPython community...

Thanks also to all known contributors or anonymous that I forgot.

And finally, congratulations to the many forums and blog for all the available examples and the help that is the strength of wxPython. ;)


About this page

Date (d/m/y) Person (bot) Comments :

00/00/00 - Sean McKay (originally Created).

10/10/18 - Ecco (Updated page and published examples for wxPython Phoenix).


Comments

- blah, blah, blah....

Printing framework (Phoenix) (last edited 2020-06-13 13:04:27 by Ecco)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.