#---------------------------------------------------------------------------- # Name: printout.py # Purpose: preview and printing class -> table/grid printing # # Author: Lorne White (email: lorne.white@telusplanet.net) # # Created: # Version 0.75 # Date: May 15, 2002 # Licence: wxWindows license #---------------------------------------------------------------------------- # Release Notes # fixed bug for string wider than print region # add index to data list after parsing total pages for paging #---------------------------------------------------------------------------- # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net) # o 2.5 compatability update. #---------------------------------------------------------------------------- # 11/23/2004 - Vernon Cole (wnvcole@peppermillcas.com) # o Generalize for non-2-dimensional sequences and non-text data # (can use as a simple text printer by supplying a list of strings.) # o Add a small _main_ for self test import copy import types import wx class PrintBase: def SetPrintFont(self, font): # set the DC font parameters fattr = font["Attr"] if fattr[0] == 1: weight = wx.BOLD else: weight = wx.NORMAL if fattr[1] == 1: set_style = wx.ITALIC else: set_style = wx.NORMAL underline = fattr[2] fcolour = self.GetFontColour(font) self.DC.SetTextForeground(fcolour) setfont = wx.Font(font["Size"], wx.SWISS, set_style, weight, underline) setfont.SetFaceName(font["Name"]) self.DC.SetFont(setfont) def GetFontColour(self, font): fcolour = font["Colour"] return wx.Colour(fcolour[0], fcolour[1], fcolour[2]) def OutTextRegion(self, textout, txtdraw = True): textlines = textout.split('\n') y = copy.copy(self.y) + self.pt_space_before for text in textlines: remain = 'X' while remain != "": vout, remain = self.SetFlow(text, self.region) if self.draw == True and txtdraw == True: test_out = self.TestFull(vout) if self.align == wx.ALIGN_LEFT: self.DC.DrawText(test_out, self.indent+self.pcell_left_margin, y) elif self.align == wx.ALIGN_CENTRE: diff = self.GetCellDiff(test_out, self.region) self.DC.DrawText(test_out, self.indent+diff/2, y) elif self.align == wx.ALIGN_RIGHT: diff = self.GetCellDiff(test_out, self.region) self.DC.DrawText(test_out, self.indent+diff, y) else: self.DC.DrawText(test_out, self.indent+self.pcell_left_margin, y) text = remain y = y + self.space return y - self.space + self.pt_space_after def GetCellDiff(self, text, width): # get the remaining cell size for adjustment w, h = self.DC.GetTextExtent(text) diff = width - w if diff < 0: diff = 0 return diff def TestFull(self, text_test): w, h = self.DC.GetTextExtent(text_test) if w > self.region: # trouble fitting into cell return self.SetChar(text_test, self.region) # fit the text to the cell size else: return text_test def SetFlow(self, ln_text, width): width = width - self.pcell_right_margin text = "" split = ln_text.split() if len(split) == 1: return ln_text, "" try: w, h = self.DC.GetTextExtent(" " + split[0]) if w >= width: return ln_text, "" except: pass cnt = 0 for word in split: bword = " " + word # blank + word length = len(bword) w, h = self.DC.GetTextExtent(text + bword) if w < width: text = text + bword cnt = cnt + 1 else: remain = ' '.join(split[cnt:]) text = text.strip() return text, remain remain = ' '.join(split[cnt:]) vout = text.strip() return vout, remain def SetChar(self, ln_text, width): # truncate string to fit into width width = width - self.pcell_right_margin - self.pcell_left_margin text = "" for val in ln_text: w, h = self.DC.GetTextExtent(text + val) if w > width: text = text + ".." return text # fitted text value text = text + val return text def OutTextPageWidth(self, textout, y_out, align, indent, txtdraw = True): textlines = textout.split('\n') y = copy.copy(y_out) pagew = self.parent.page_width * self.pwidth # full page width w, h = self.DC.GetTextExtent(textout) y_line = h for text in textlines: remain = 'X' while remain != "": vout, remain = self.SetFlow(text, pagew) if self.draw == True and txtdraw == True: test_out = vout if align == wx.ALIGN_LEFT: self.DC.DrawText(test_out, indent, y) elif align == wx.ALIGN_CENTRE: diff = self.GetCellDiff(test_out, pagew) self.DC.DrawText(test_out, indent+diff/2, y) elif align == wx.ALIGN_RIGHT: diff = self.GetCellDiff(test_out, pagew) self.DC.DrawText(test_out, indent+diff, y) else: self.DC.DrawText(test_out, indent, y_out) text = remain y = y + y_line return y - y_line def GetDate(self): date, time = self.GetNow() return date def GetDateTime(self): date, time = self.GetNow() return date + ' ' + time def GetNow(self): now = wx.DateTime.Now() date = now.FormatDate() time = now.FormatTime() return date, time def SetPreview(self, preview): self.preview = preview def SetPSize(self, width, height): self.pwidth = width/self.scale self.pheight = height/self.scale def SetScale(self, scale): self.scale = scale def SetPTSize(self, width, height): self.ptwidth = width self.ptheight = height def getWidth(self): return self.sizew def getHeight(self): return self.sizeh class PrintTableDraw(wx.ScrolledWindow, PrintBase): def __init__(self, parent, DC, size): self.parent = parent self.DC = DC self.scale = parent.scale self.width = size[0] self.height = size[1] self.SetDefaults() def SetDefaults(self): self.page = 1 self.total_pages = None self.page_width = self.parent.page_width self.page_height = self.parent.page_height self.left_margin = self.parent.left_margin self.right_margin = self.parent.right_margin self.top_margin = self.parent.top_margin self.bottom_margin = self.parent.bottom_margin self.cell_left_margin = self.parent.cell_left_margin self.cell_right_margin = self.parent.cell_right_margin self.label_colour = self.parent.label_colour self.row_line_colour = self.parent.row_line_colour self.row_line_size = self.parent.row_line_size self.row_def_line_colour = self.parent.row_def_line_colour self.row_def_line_size = self.parent.row_def_line_size self.column_line_colour = self.parent.column_line_colour self.column_line_size = self.parent.column_line_size self.column_def_line_size = self.parent.column_def_line_size self.column_def_line_colour = self.parent.column_def_line_colour self.text_font = self.parent.text_font self.label_font = self.parent.label_font def AdjustValues(self): self.vertical_offset = self.pheight * self.parent.vertical_offset self.horizontal_offset = self.pheight * self.parent.horizontal_offset self.pcell_left_margin = self.pwidth * self.cell_left_margin self.pcell_right_margin = self.pwidth * self.cell_right_margin self.ptop_margin = self.pheight * self.top_margin self.pbottom_margin = self.pheight * self.bottom_margin self.pheader_margin = self.pheight * self.parent.header_margin self.pfooter_margin = self.pheight * self.parent.footer_margin self.cell_colour = self.parent.set_cell_colour self.cell_text = self.parent.set_cell_text self.column = [] self.column_align = [] self.column_bgcolour = [] self.column_txtcolour = [] set_column_align = self.parent.set_column_align set_column_bgcolour = self.parent.set_column_bgcolour set_column_txtcolour = self.parent.set_column_txtcolour pos_x = self.left_margin * self.pwidth + self.horizontal_offset # left margin self.column.append(pos_x) #module logic expects two dimensional data -- fix input if needed if isinstance(self.data,types.StringTypes): self.data = [[copy.copy(self.data)]] # a string becomes a single cell try: rows = len(self.data) except TypeError: self.data = [[str(self.data)]] # a non-iterable becomes a single cell rows = 1 first_value = self.data[0] if isinstance(first_value, types.StringTypes): # a sequence of strings if self.label == [] and self.set_column == []: data = [] for x in self.data: #becomes one column data.append([x]) else: data = [self.data] #becames one row self.data = data first_value = data[0] try: column_total = len(first_value) except TypeError: # a sequence of non-iterables if self.label == [] and self.set_column == []: data = [] #becomes one column for x in self.data: data.append([str(x)]) column_total = 1 else: data = [self.data] #becomes one row column_total = len(self.data) self.data = data first_value = data[0] if self.set_column == []: table_width = self.page_width - self.left_margin - self.right_margin if self.label == []: temp = first_value else: temp = self.label width = table_width/(len(temp)) for val in temp: column_width = width * self.pwidth pos_x = pos_x + column_width self.column.append(pos_x) # position of each column else: for val in self.set_column: column_width = val * self.pwidth pos_x = pos_x + column_width self.column.append(pos_x) # position of each column if pos_x > self.page_width * self.pwidth: # check if it fits in page print "Warning, Too Wide for Page" return if self.label != []: if len(self.column) -1 != len(self.label): print "Column Settings Incorrect", "\nColumn Value: " + str(self.column), "\nLabel Value: " + str(self.label) return if column_total != len(self.column) -1: print "Cannot fit", first_value, 'in', len(self.column)-1, 'columns.' return for col in range(column_total): try: align = set_column_align[col] # check if custom column alignment except: align = wx.ALIGN_LEFT self.column_align.append(align) try: colour = set_column_bgcolour[col] # check if custom column background colour except: colour = self.parent.column_colour self.column_bgcolour.append(colour) try: colour = set_column_txtcolour[col] # check if custom column text colour except: colour = self.GetFontColour(self.parent.text_font) self.column_txtcolour.append(colour) def SetPointAdjust(self): f = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL) # setup using 10 point self.DC.SetFont(f) f.SetFaceName(self.text_font["Name"]) x, y = self.DC.GetTextExtent("W") self.label_pt_space_before = self.parent.label_pt_adj_before * y/10 # extra spacing for label per point value self.label_pt_space_after = self.parent.label_pt_adj_after * y/10 self.text_pt_space_before = self.parent.text_pt_adj_before * y/10 # extra spacing for row text per point value self.text_pt_space_after = self.parent.text_pt_adj_after * y/10 def SetPage(self, page): self.page = page def SetColumns(self, col): self.column = col def OutCanvas(self): self.AdjustValues() self.SetPointAdjust() self.y_start = self.ptop_margin + self.vertical_offset self.y_end = self.parent.page_height * self.pheight - self.pbottom_margin + self.vertical_offset self.SetPrintFont(self.label_font) x, y = self.DC.GetTextExtent("W") self.label_space = y self.SetPrintFont(self.text_font) x, y = self.DC.GetTextExtent("W") self.space = y if self.total_pages is None: self.GetTotalPages() # total pages for display/printing self.data_cnt = self.page_index[self.page-1] self.draw = True self.PrintHeader() self.PrintFooter() self.OutPage() def GetTotalPages(self): self.data_cnt = 0 self.draw = False self.page_index = [0] cnt = 0 while 1: test = self.OutPage() self.page_index.append(self.data_cnt) if test == False: break cnt = cnt + 1 self.total_pages = cnt + 1 def OutPage(self): self.y = self.y_start self.end_x = self.column[-1] if self.data_cnt < len(self.data): # if there data for display on the page if self.label != []: # check if header defined self.PrintLabel() else: return False for val in self.data: try: row_val = self.data[self.data_cnt] except: self.FinishDraw() return False max_y = self.PrintRow(row_val, False) # test to see if row will fit in remaining space test = max_y + self.space if test > self.y_end: break self.ColourRowCells(max_y-self.y+self.space) # colour the row/column max_y = self.PrintRow(row_val, True) # row fits - print text self.DrawGridLine() # top line of cell self.y = max_y + self.space if self.y > self.y_end: break self.data_cnt = self.data_cnt + 1 self.FinishDraw() if self.data_cnt == len(self.data): # last value in list return False return True def PrintLabel(self): self.pt_space_before = self.label_pt_space_before # set the point spacing self.pt_space_after = self.label_pt_space_after self.LabelColorRow(self.label_colour) self.SetPrintFont(self.label_font) self.col = 0 max_y = 0 for vtxt in self.label: self.region = self.column[self.col+1] - self.column[self.col] self.indent = self.column[self.col] self.align = wx.ALIGN_LEFT max_out = self.OutTextRegion(vtxt, True) if max_out > max_y: max_y = max_out self.col = self.col + 1 self.DrawGridLine() # top line of label self.y = max_y + self.label_space def PrintHeader(self): # print the header array if self.draw == False: return for val in self.parent.header: self.SetPrintFont(val["Font"]) header_indent = val["Indent"] * self.pwidth text = val["Text"] htype = val["Type"] if htype == "Date": addtext = self.GetDate() elif htype == "Date & Time": addtext = self.GetDateTime() else: addtext = "" self.OutTextPageWidth(text+addtext, self.pheader_margin, val["Align"], header_indent, True) def PrintFooter(self): # print the header array if self.draw == False: return footer_pos = self.parent.page_height * self.pheight - self.pfooter_margin + self.vertical_offset for val in self.parent.footer: self.SetPrintFont(val["Font"]) footer_indent = val["Indent"] * self.pwidth text = val["Text"] ftype = val["Type"] if ftype == "Pageof": addtext = "Page " + str(self.page) + " of " + str(self.total_pages) elif ftype == "Page": addtext = "Page " + str(self.page) elif ftype == "Num": addtext = str(self.page) elif ftype == "Date": addtext = self.GetDate() elif ftype == "Date & Time": addtext = self.GetDateTime() else: addtext = "" self.OutTextPageWidth(text+addtext, footer_pos, val["Align"], footer_indent, True) def LabelColorRow(self, colour): brush = wx.Brush(colour, wx.SOLID) self.DC.SetBrush(brush) height = self.label_space + self.label_pt_space_before + self.label_pt_space_after self.DC.DrawRectangle(self.column[0], self.y, self.end_x-self.column[0]+1, height) def ColourRowCells(self, height): if self.draw == False: return col = 0 for colour in self.column_bgcolour: cellcolour = self.GetCellColour(self.data_cnt, col) if cellcolour is not None: colour = cellcolour brush = wx.Brush(colour, wx.SOLID) self.DC.SetBrush(brush) self.DC.SetPen(wx.Pen(wx.NamedColour('WHITE'), 0)) start_x = self.column[col] width = self.column[col+1] - start_x + 2 self.DC.DrawRectangle(start_x, self.y, width, height) col = col + 1 def PrintRow(self, row_val, draw = True, align = wx.ALIGN_LEFT): self.SetPrintFont(self.text_font) self.pt_space_before = self.text_pt_space_before # set the point spacing self.pt_space_after = self.text_pt_space_after self.col = 0 max_y = 0 for vtxt in row_val: if not isinstance(vtxt,types.StringTypes): vtxt = str(vtxt) self.region = self.column[self.col+1] - self.column[self.col] self.indent = self.column[self.col] self.align = self.column_align[self.col] fcolour = self.column_txtcolour[self.col] # set font colour celltext = self.GetCellTextColour(self.data_cnt, self.col) if celltext is not None: fcolour = celltext # override the column colour self.DC.SetTextForeground(fcolour) max_out = self.OutTextRegion(vtxt, draw) if max_out > max_y: max_y = max_out self.col = self.col + 1 return max_y def GetCellColour(self, row, col): # check if custom colour defined for the cell background try: set = self.cell_colour[row] except: return None try: colour = set[col] return colour except: return None def GetCellTextColour(self, row, col): # check if custom colour defined for the cell text try: set = self.cell_text[row] except: return None try: colour = set[col] return colour except: return None def FinishDraw(self): self.DrawGridLine() # draw last row line self.DrawColumns() # draw all vertical lines def DrawGridLine(self): if self.draw == True \ and len(self.column) > 2: #supress grid lines if only one column try: size = self.row_line_size[self.data_cnt] except: size = self.row_def_line_size if size < 1: return try: colour = self.row_line_colour[self.data_cnt] except: colour = self.row_def_line_colour self.DC.SetPen(wx.Pen(colour, size)) y_out = self.y # y_out = self.y + self.pt_space_before + self.pt_space_after # adjust for extra spacing self.DC.DrawLine(self.column[0], y_out, self.end_x, y_out) def DrawColumns(self): if self.draw == True \ and len(self.column) > 2: #surpress grid line if only one column col = 0 for val in self.column: try: size = self.column_line_size[col] except: size = self.column_def_line_size if size < 1: continue try: colour = self.column_line_colour[col] except: colour = self.column_def_line_colour indent = val self.DC.SetPen(wx.Pen(colour, size)) self.DC.DrawLine(indent, self.y_start, indent, self.y) col = col + 1 def DrawText(self): self.DoRefresh() def DoDrawing(self, DC): size = DC.GetSize() self.DC = DC DC.BeginDrawing() self.DrawText() DC.EndDrawing() self.sizew = DC.MaxY() self.sizeh = DC.MaxX() class PrintTable: def __init__(self, parentFrame=None): self.data = [] self.set_column = [] self.label = [] self.header = [] self.footer = [] self.set_column_align = {} self.set_column_bgcolour = {} self.set_column_txtcolour = {} self.set_cell_colour = {} self.set_cell_text = {} self.column_line_size = {} self.column_line_colour = {} self.row_line_size = {} self.row_line_colour = {} self.parentFrame = parentFrame self.SetPreviewSize() self.printData = wx.PrintData() self.scale = 1.0 self.SetParms() self.SetColors() self.SetFonts() self.TextSpacing() self.SetPrinterOffset() self.SetHeaderValue() self.SetFooterValue() self.SetMargins() self.SetPortrait() def SetPreviewSize(self, position = wx.Point(0, 0), size="Full"): if size == "Full": r = wx.GetClientDisplayRect() self.preview_frame_size = r.GetSize() self.preview_frame_pos = r.GetPosition() else: self.preview_frame_size = size self.preview_frame_pos = position def SetPaperId(self, paper): self.printData.SetPaperId(paper) def SetOrientation(self, orient): self.printData.SetOrientation(orient) def SetColors(self): self.row_def_line_colour = wx.NamedColour('BLACK') self.row_def_line_size = 1 self.column_def_line_colour = wx.NamedColour('BLACK') self.column_def_line_size = 1 self.column_colour = wx.NamedColour('WHITE') self.label_colour = wx.NamedColour('LIGHT GREY') def SetFonts(self): self.label_font = { "Name": self.default_font_name, "Size": 12, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } self.text_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } def TextSpacing(self): self.label_pt_adj_before = 0 # point adjustment before and after the label text self.label_pt_adj_after = 0 self.text_pt_adj_before = 0 # point adjustment before and after the row text self.text_pt_adj_after = 0 def SetLabelSpacing(self, before, after): # method to set the label space adjustment self.label_pt_adj_before = before self.label_pt_adj_after = after def SetRowSpacing(self, before, after): # method to set the row space adjustment self.text_pt_adj_before = before self.text_pt_adj_after = after def SetPrinterOffset(self): # offset to adjust for printer self.vertical_offset = -0.1 self.horizontal_offset = -0.1 def SetHeaderValue(self): self.header_margin = 0.25 self.header_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } self.header_align = wx.ALIGN_CENTRE self.header_indent = 0 self.header_type = "Text" def SetFooterValue(self): self.footer_margin = 0.7 self.footer_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } self.footer_align = wx.ALIGN_CENTRE self.footer_indent = 0 self.footer_type = "Pageof" def SetMargins(self): self.left_margin = 0.5 self.right_margin = 0.5 # only used if no column sizes self.top_margin = 0.8 self.bottom_margin = 1.0 self.cell_left_margin = 0.1 self.cell_right_margin = 0.1 def SetPortrait(self): self.printData.SetPaperId(wx.PAPER_LETTER) self.printData.SetOrientation(wx.PORTRAIT) self.page_width = 8.5 self.page_height = 11.0 def SetLandscape(self): self.printData.SetOrientation(wx.LANDSCAPE) self.page_width = 11.0 self.page_height = 8.5 def SetParms(self): self.ymax = 1 self.xmax = 1 self.page = 1 self.total_pg = 100 self.preview = None self.page = 0 self.default_font_name = "Arial" self.default_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } def SetColAlignment(self, col, align=wx.ALIGN_LEFT): self.set_column_align[col] = align def SetColBackgroundColour(self, col, colour): self.set_column_bgcolour[col] = colour def SetColTextColour(self, col, colour): self.set_column_txtcolour[col] = colour def SetCellColour(self, row, col, colour): # cell background colour try: set = self.set_cell_colour[row] # test if row already exists try: set[col] = colour # test if column already exists except: set = { col: colour } # create the column value except: set = { col: colour } # create the column value self.set_cell_colour[row] = set # create dictionary item for colour settings def SetCellText(self, row, col, colour): # font colour for custom cells try: set = self.set_cell_text[row] # test if row already exists try: set[col] = colour # test if column already exists except: set = { col: colour } # create the column value except: set = { col: colour } # create the column value self.set_cell_text[row] = set # create dictionary item for colour settings def SetColumnLineSize(self, col, size): # column line size self.column_line_size[col] = size # create dictionary item for column line settings def SetColumnLineColour(self, col, colour): self.column_line_colour[col] = colour def SetRowLineSize(self, row, size): self.row_line_size[row] = size def SetRowLineColour(self, row, colour): self.row_line_colour[row] = colour def GetColour(self, colour): # returns colours based from wxColour value red = colour.Red() blue = colour.Blue() green = colour.Green() return [red, green, blue ] def SetHeader(self, text = "", type = "Text", font=None, align = None, indent = None, colour = None, size = None): set = { "Text": text } if font is None: set["Font"] = copy.copy(self.default_font) else: set["Font"] = font if colour is not None: setfont = set["Font"] setfont["Colour"] = self.GetColour(colour) if size is not None: setfont = set["Font"] setfont["Size"] = size if align is None: set["Align"] = self.header_align else: set["Align"] = align if indent is None: set["Indent"] = self.header_indent else: set["Indent"] = indent if type is None: set["Type"] = self.header_type else: set["Type"] = type self.header.append(set) def SetFooter(self, text = "", type = None, font=None, align = None, indent = None, colour = None, size = None): set = { "Text": text } if font is None: set["Font"] = copy.copy(self.default_font) else: set["Font"] = font if colour is not None: setfont = set["Font"] setfont["Colour"] = self.GetColour(colour) if size is not None: setfont = set["Font"] setfont["Size"] = size if align is None: set["Align"] = self.footer_align else: set["Align"] = align if indent is None: set["Indent"] = self.footer_indent else: set["Indent"] = indent if type is None: set["Type"] = self.footer_type else: set["Type"] = type self.footer.append(set) def Preview(self): data = wx.PrintDialogData(self.printData) printout = SetPrintout(self) printout2 = SetPrintout(self) self.preview = wx.PrintPreview(printout, printout2, data) if not self.preview.Ok(): wx.MessageBox("There was a problem printing!", "Printing", wx.OK) return self.preview.SetZoom(60) # initial zoom value frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview") frame.Initialize() if self.parentFrame: frame.SetPosition(self.preview_frame_pos) frame.SetSize(self.preview_frame_size) frame.Show(True) def Print(self): pdd = wx.PrintDialogData(self.printData) printer = wx.Printer(pdd) printout = SetPrintout(self) if not printer.Print(self.parentFrame, printout): wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK) else: self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() ) printout.Destroy() def DoDrawing(self, DC): size = DC.GetSize() DC.BeginDrawing() table = PrintTableDraw(self, DC, size) table.data = self.data table.set_column = self.set_column table.label = self.label table.SetPage(self.page) if self.preview is None: table.SetPSize(size[0]/self.page_width, size[1]/self.page_height) table.SetPTSize(size[0], size[1]) table.SetPreview(False) else: if self.preview == 1: table.scale = self.scale table.SetPSize(size[0]/self.page_width, size[1]/self.page_height) else: table.SetPSize(self.pwidth, self.pheight) table.SetPTSize(self.ptwidth, self.ptheight) table.SetPreview(self.preview) table.OutCanvas() self.page_total = table.total_pages # total display pages DC.EndDrawing() self.ymax = DC.MaxY() self.xmax = DC.MaxX() self.sizeh = size[0] self.sizew = size[1] def GetTotalPages(self): self.page_total = 100 return self.page_total def HasPage(self, page): if page <= self.page_total: return True else: return False def SetPage(self, page): self.page = page def SetPageSize(self, width, height): self.pwidth, self.pheight = width, height def SetTotalSize(self, width, height): self.ptwidth, self.ptheight = width, height def SetPreview(self, preview, scale): self.preview = preview self.scale = scale def SetTotalSize(self, width, height): self.ptwidth = width self.ptheight = height class PrintGrid: def __init__(self, parent, grid, format = [], total_col = None, total_row = None): if total_row is None: total_row = grid.GetNumberRows() if total_col is None: total_col = grid.GetNumberCols() self.total_row = total_row self.total_col = total_col self.grid = grid data = [] for row in range(total_row): row_val = [] value = grid.GetRowLabelValue(row) row_val.append(value) for col in range(total_col): value = grid.GetCellValue(row, col) row_val.append(value) data.append(row_val) label = [""] for col in range(total_col): value = grid.GetColLabelValue(col) label.append(value) self.table = PrintTable(parent) self.table.cell_left_margin = 0.0 self.table.cell_right_margin = 0.0 self.table.label = label self.table.set_column = format self.table.data = data def GetTable(self): return self.table def SetAttributes(self): for row in range(self.total_row): for col in range(self.total_col): colour = self.grid.GetCellTextColour(row, col-1) self.table.SetCellText(row, col, colour) colour = self.grid.GetCellBackgroundColour(row, col-1) self.table.SetCellColour(row, col, colour) def Preview(self): self.table.Preview() def Print(self): self.table.Print() class SetPrintout(wx.Printout): def __init__(self, canvas): wx.Printout.__init__(self) self.canvas = canvas self.end_pg = 1000 def OnBeginDocument(self, start, end): return super(SetPrintout, self).OnBeginDocument(start, end) def OnEndDocument(self): super(SetPrintout, self).OnEndDocument() def HasPage(self, page): try: end = self.canvas.HasPage(page) return end except: return True def GetPageInfo(self): try: self.end_pg = self.canvas.GetTotalPages() except: pass end_pg = self.end_pg str_pg = 1 return (str_pg, end_pg, str_pg, end_pg) def OnPreparePrinting(self): super(SetPrintout, self).OnPreparePrinting() def OnBeginPrinting(self): dc = self.GetDC() self.preview = self.IsPreview() if (self.preview): self.pixelsPerInch = self.GetPPIScreen() else: self.pixelsPerInch = self.GetPPIPrinter() (w, h) = dc.GetSize() scaleX = float(w) / 1000 scaleY = float(h) / 1000 self.printUserScale = min(scaleX, scaleY) super(SetPrintout, self).OnBeginPrinting() def GetSize(self): self.psizew, self.psizeh = self.GetPPIPrinter() return self.psizew, self.psizeh def GetTotalSize(self): self.ptsizew, self.ptsizeh = self.GetPageSizePixels() return self.ptsizew, self.ptsizeh def OnPrintPage(self, page): dc = self.GetDC() (w, h) = dc.GetSize() scaleX = float(w) / 1000 scaleY = float(h) / 1000 self.printUserScale = min(scaleX, scaleY) dc.SetUserScale(self.printUserScale, self.printUserScale) self.preview = self.IsPreview() self.canvas.SetPreview(self.preview, self.printUserScale) self.canvas.SetPage(page) self.ptsizew, self.ptsizeh = self.GetPageSizePixels() self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh) self.psizew, self.psizeh = self.GetPPIPrinter() self.canvas.SetPageSize(self.psizew, self.psizeh) self.canvas.DoDrawing(dc) return True if __name__ == '__main__': app = wx.PySimpleApp() frame = wx.Frame(None, -1, "Dummy wx frame for testing printout.py") frame.Show(True) ptbl = PrintTable(frame) ptbl.SetHeader('This is the test HEADER') # a single sequence will print out as a single column with no borders ... ptbl.data = ( 'This is the first line of text.', 'This is the second line\nand the third. The fourth will be the number "4.0".', 04.00, 'This is the fifth line, but by design it is too long to fit in the width of a standard'\ ' page, so it will be forced to wrap around in order to fit without having '\ 'some of its verbose verbage truncated.', 'Here we have the final line.' ) #... but, if labels or columns are defined, a single sequence will print out as a single row ##ptbl.label = ('One','Two','Three','Four','5') ptbl.Preview() app.MainLoop()