Printing framework - Part 3 (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 ! (!)


Grid Printing :

First example

img_sample_one_a.png

   1 # sample_one_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         frameicon = wx.Icon("Icons/wxWidgets.ico")
1352         self.SetIcon(frameicon)
1353 
1354         #------------
1355 
1356         self.SetTitle("Dummy wx frame for testing printout.py")
1357 
1358 
1359     def CreateMenu(self):
1360         """
1361         ...
1362         """
1363 
1364         menub = wx.MenuBar()
1365 
1366         fmenu = wx.Menu()
1367         fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
1368         fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
1369         fmenu.AppendSeparator()
1370         fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
1371         menub.Append(fmenu, "&File")
1372 
1373         self.SetMenuBar(menub)
1374 
1375 
1376     def CreateCtrls(self):
1377         """
1378         ...
1379         """
1380 
1381         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1382         font.SetWeight(wx.BOLD)
1383         font.SetPointSize(10)
1384 
1385         #------------
1386 
1387         # First create the controls.
1388         self.panel = wx.Panel(self, -1,
1389                               style=wx.BORDER_THEME|
1390                               wx.TAB_TRAVERSAL)
1391 
1392         #------------
1393 
1394         self.demo = wx.StaticText(self.panel,
1395                                   id=-1,
1396                                   label="Demonstrating :")
1397         self.demo.SetFont(font)
1398 
1399         self.info = wx.StaticText(self.panel,
1400                                   id=-1,
1401                                   label="1) Direct printing,\n"
1402                                         "2) Printout class,\n"
1403                                         "3) PrintTable class,\n"
1404                                         "4) Preview,\n"
1405                                         "5) Menu")
1406         self.info.SetForegroundColour("red")
1407         font.SetWeight(wx.NORMAL)
1408         self.info.SetFont(font)
1409 
1410         #------------
1411 
1412         self.testgrid = grid.Grid(self.panel, -1,
1413                                   style=wx.BORDER_THEME)
1414         self.testgrid.CreateGrid(5, 5)
1415         for i in range(5):
1416             d = i + 1
1417             self.testgrid.SetColLabelValue(i, 'Column %d' % d)
1418             self.testgrid.SetRowLabelValue(i, 'Row %d' % d)
1419             for j in range(5):
1420                 e = j + 1
1421                 self.testgrid.SetCellValue(i, j, 'Cell %02d.%02d' % (d, e))
1422         self.testgrid.SetCellBackgroundColour(0, 0, wx.RED)
1423         self.testgrid.SetCellBackgroundColour(4, 4, wx.GREEN)
1424         self.testgrid.SetCellBackgroundColour(3, 4, wx.BLUE)
1425         self.testgrid.SetCellBackgroundColour(4, 3, wx.YELLOW)
1426         self.testgrid.SetColSize(0, 71)
1427         self.testgrid.SetColSize(1, 71)
1428         self.testgrid.SetColSize(2, 107)
1429         self.testgrid.SetColSize(3, 130)
1430         self.testgrid.SetColSize(4, 130)
1431 
1432         #------------
1433 
1434         self.btnPreview = wx.Button(self.panel,
1435                                     id=wx.ID_PREVIEW,
1436                                     label="Print pre&view")
1437         self.btnPreview.SetFocus()
1438 
1439         self.btnPrint = wx.Button(self.panel,
1440                                   id=wx.ID_PRINT,
1441                                   label="&Print")
1442 
1443         self.btnClose = wx.Button(self.panel,
1444                                   id=wx.ID_CLOSE,
1445                                   label="E&xit")
1446 
1447 
1448     def CreatePrintData(self):
1449         """
1450         Create printing data.
1451         """
1452 
1453         testgrid = self.testgrid
1454 
1455         #------------
1456 
1457         self.grdprt = PrintGrid(self, testgrid, rowLabels=False, colLabels=False)
1458         self.grdprt.SetAttributes()
1459 
1460         #------------
1461 
1462         self.table = self.grdprt.GetTable()
1463         self.table.SetPortrait()
1464         self.table.SetHeader('This is the test HEADER')
1465         self.table.SetFooter()
1466 
1467 
1468     def BindEvents(self):
1469         """
1470         Bind all the events related to my application.
1471         """
1472 
1473         # Bind some menu events to an events handler.
1474         self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
1475         self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
1476         self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
1477 
1478         # Bind the close event to an event handler.
1479         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1480 
1481         # Bind some buttons events to an events handler.
1482         self.Bind(wx.EVT_BUTTON, self.OnPrintPreview, self.btnPreview)
1483         self.Bind(wx.EVT_BUTTON, self.OnPrint, self.btnPrint)
1484         self.Bind(wx.EVT_BUTTON, self.OnClose, self.btnClose)
1485 
1486 
1487     def DoLayout(self):
1488         """
1489         Manage widgets Layout.
1490         """
1491 
1492         # MainSizer is the top-level one that manages everything.
1493         mainSizer = wx.BoxSizer(wx.VERTICAL)
1494 
1495         #------------
1496 
1497         hBox1 = wx.BoxSizer(wx.HORIZONTAL)
1498         hBox1.Add(self.info, 0, wx.ALL, 15)
1499 
1500         #------------
1501 
1502         hBox2 = wx.BoxSizer(wx.HORIZONTAL)
1503         hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
1504         hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
1505         hBox2.Add(self.btnClose, 0, wx.ALL, 10)
1506 
1507         #------------
1508 
1509         mainSizer.Add(self.demo, 0, wx.ALL, 10)
1510         mainSizer.Add(wx.StaticLine(self.panel),
1511                       0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
1512         mainSizer.Add(self.testgrid, 0, wx.ALL, 15)
1513         mainSizer.Add(hBox1, 0, wx.ALL, 5)
1514         mainSizer.Add(hBox2, 0, wx.ALL, 5)
1515 
1516         #------------
1517 
1518         # Finally, tell the panel to use the mainSizer for layout.
1519         self.panel.SetSizer(mainSizer)
1520 
1521 
1522     def OnPrintPreview(self, event):
1523         self.CreatePrintData()
1524         self.grdprt.Preview()
1525 
1526 
1527     def OnPrint(self, event):
1528         self.CreatePrintData()
1529         self.grdprt.Print()
1530 
1531 
1532     def OnClose(self, evt):
1533         self.Close()
1534 
1535 
1536     def OnCloseWindow(self, event):
1537         """
1538         ...
1539         """
1540 
1541         self.Destroy()
1542 
1543 #-------------------------------------------------------------------------------
1544 
1545 class App(wx.App):
1546     """
1547     ...
1548     """
1549     def OnInit(self):
1550 
1551         #------------
1552 
1553         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
1554 
1555         #------------
1556 
1557         frame = Frame(None, id=-1)
1558         self.SetTopWindow(frame)
1559         frame.Show(True)
1560 
1561         return True
1562 
1563 #-------------------------------------------------------------------------------
1564 
1565 def main():
1566     app = App(False)
1567     app.MainLoop()
1568 
1569 #-------------------------------------------------------------------------------
1570 
1571 if __name__ == "__main__" :
1572     main()


Second example

img_sample_one_b.png

   1 # sample_one_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