How to use printing framework - Part 3 (Phoenix)
Keywords : Printing, Printout, Preview, Printer, PrintData, PrintDialogData, PageSetupDialogData, PageSetupDialog, PrintPreview, PreviewFrame, Canvas, Grid, HtmlEasyPrinting, PDFViewer, PDFWindow, ReportLab.
Contents
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 :
wx.HtmlEasyPrinting -- The simple way to print
wx.Printout -- Base printing class that will be inherited from. Various control functions handling printing events are defined here.
wx.PrintData -- Printer / page configuration data
wx.PrintDialogData -- (same as (wx.PrintData) except what is used by Page Setup window ??)
wx.Printer -- Software interface to the printer
wx.MessageBox -- Used for alerting the user to any problems
wx.PrintPreview -- Used for print preview
wx.PrintDialog -- Window that pops up, asking how many pages to print, etc..
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
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
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 set = self.set_cell_text[row] # test if row already exists
909 try:
910 set[col] = colour # test if column already exists
911 except:
912 set = { col: colour } # create the column value
913 except:
914 set = { col: colour } # create the column value
915
916 self.set_cell_text[row] = set # create dictionary item for colour settings
917
918
919 def SetColumnLineSize(self, col, size): # column line size
920 self.column_line_size[col] = size # create dictionary item for column line settings
921
922
923 def SetColumnLineColour(self, col, colour):
924 self.column_line_colour[col] = colour
925
926
927 def SetRowLineSize(self, row, size):
928 self.row_line_size[row] = size
929
930
931 def SetRowLineColour(self, row, colour):
932 self.row_line_colour[row] = colour
933
934
935 def GetColour(self, colour): # returns colours based from wxColour value
936 red = colour.Red()
937 blue = colour.Blue()
938 green = colour.Green()
939 return [red, green, blue ]
940
941
942 def SetHeader(self, text = "", type = "Text", font=None, align = None, indent = None, colour = None, size = None):
943 set = { "Text": text }
944
945 if font is None:
946 set["Font"] = copy.copy(self.default_font)
947 else:
948 set["Font"] = font
949
950 if colour is not None:
951 setfont = set["Font"]
952 setfont["Colour"] = self.GetColour(colour)
953
954 if size is not None:
955 setfont = set["Font"]
956 setfont["Size"] = size
957
958 if align is None:
959 set["Align"] = self.header_align
960 else:
961 set["Align"] = align
962
963 if indent is None:
964 set["Indent"] = self.header_indent
965 else:
966 set["Indent"] = indent
967
968 if type is None:
969 set["Type"] = self.header_type
970 else:
971 set["Type"] = type
972
973 self.header.append(set)
974
975
976 def SetFooter(self, text = "", type = None, font=None, align = None, indent = None, colour = None, size = None):
977 set = { "Text": text }
978
979 if font is None:
980 set["Font"] = copy.copy(self.default_font)
981 else:
982 set["Font"] = font
983
984 if colour is not None:
985 setfont = set["Font"]
986 setfont["Colour"] = self.GetColour(colour)
987
988 if size is not None:
989 setfont = set["Font"]
990 setfont["Size"] = size
991
992 if align is None:
993 set["Align"] = self.footer_align
994 else:
995 set["Align"] = align
996
997 if indent is None:
998 set["Indent"] = self.footer_indent
999 else:
1000 set["Indent"] = indent
1001
1002 if type is None:
1003 set["Type"] = self.footer_type
1004 else:
1005 set["Type"] = type
1006
1007 self.footer.append(set)
1008
1009
1010 def Preview(self):
1011 data = wx.PrintDialogData(self.printData)
1012
1013 text = self.parentFrame.tc.GetValue()
1014
1015 printout = SetPrintout(self, text)
1016 printout2 = SetPrintout(self, text)
1017 self.preview = wx.PrintPreview(printout, printout2, data)
1018 if not self.preview.IsOk():
1019 wx.MessageBox("There was a problem printing!", "Printing", wx.OK)
1020 return
1021
1022 self.preview.SetZoom(60) # initial zoom value
1023 frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview")
1024
1025 frame.Initialize()
1026 if self.parentFrame:
1027 frame.SetPosition(self.preview_frame_pos)
1028 frame.SetSize(self.preview_frame_size)
1029 frame.Show(True)
1030
1031
1032 def Print(self):
1033 pdd = wx.PrintDialogData(self.printData)
1034 printer = wx.Printer(pdd)
1035
1036 text = self.parentFrame.tc.GetValue()
1037
1038 printout = SetPrintout(self, text)
1039 if not printer.Print(self.parentFrame, printout):
1040 if wx.Printer.GetLastError() == wx.PRINTER_ERROR:
1041 wx.MessageBox("There was a problem printing.\n"
1042 "Perhaps your current printer is not set correctly?",
1043 "Printing", wx.OK)
1044 else:
1045 self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
1046 printout.Destroy()
1047
1048
1049 def DoDrawing(self, DC):
1050 size = DC.GetSize()
1051
1052 table = PrintTableDraw(self, DC, size)
1053 table.data = self.data
1054 table.set_column = self.set_column
1055 table.label = self.label
1056 table.SetPage(self.page)
1057
1058 if self.preview is None:
1059 table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1060 table.SetPTSize(size[0], size[1])
1061 table.SetPreview(False)
1062 else:
1063 if self.preview == 1:
1064 table.scale = self.scale
1065 table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
1066 else:
1067 table.SetPSize(self.pwidth, self.pheight)
1068
1069 table.SetPTSize(self.ptwidth, self.ptheight)
1070 table.SetPreview(self.preview)
1071
1072 table.OutCanvas()
1073 self.page_total = table.total_pages # total display pages
1074
1075 self.ymax = DC.MaxY()
1076 self.xmax = DC.MaxX()
1077
1078 self.sizeh = size[0]
1079 self.sizew = size[1]
1080
1081
1082 def GetTotalPages(self):
1083 self.page_total = 100
1084 return self.page_total
1085
1086
1087 def HasPage(self, page):
1088 if page <= self.page_total:
1089 return True
1090 else:
1091 return False
1092
1093
1094 def SetPage(self, page):
1095 self.page = page
1096
1097
1098 def SetPageSize(self, width, height):
1099 self.pwidth, self.pheight = width, height
1100
1101
1102 def SetTotalSize(self, width, height):
1103 self.ptwidth, self.ptheight = width, height
1104
1105
1106 def SetPreview(self, preview, scale):
1107 self.preview = preview
1108 self.scale = scale
1109
1110
1111 def SetTotalSize(self, width, height):
1112 self.ptwidth = width
1113 self.ptheight = height
1114
1115 #-------------------------------------------------------------------------------
1116
1117 class PrintGrid(object):
1118 """
1119 ...
1120 """
1121 def __init__(self, parent, grid, format = [], total_col = None, total_row = None):
1122 if total_row is None:
1123 total_row = grid.GetNumberRows()
1124 if total_col is None:
1125 total_col = grid.GetNumberCols()
1126
1127 self.total_row = total_row
1128 self.total_col = total_col
1129 self.grid = grid
1130
1131 data = []
1132 for row in range(total_row):
1133 row_val = []
1134 value = grid.GetRowLabelValue(row)
1135 row_val.append(value)
1136
1137 for col in range(total_col):
1138 value = grid.GetCellValue(row, col)
1139 row_val.append(value)
1140 data.append(row_val)
1141
1142 label = [""]
1143 for col in range(total_col):
1144 value = grid.GetColLabelValue(col)
1145 label.append(value)
1146
1147 self.table = PrintTable(parent)
1148 self.table.cell_left_margin = 0.0
1149 self.table.cell_right_margin = 0.0
1150
1151 self.table.label = label
1152 self.table.set_column = format
1153 self.table.data = data
1154
1155 #---------------------------------------------------------------------------
1156
1157 def GetTable(self):
1158 return self.table
1159
1160
1161 def SetAttributes(self):
1162 for row in range(self.total_row):
1163 for col in range(self.total_col):
1164 colour = self.grid.GetCellTextColour(row, col-1)
1165 self.table.SetCellText(row, col, colour)
1166
1167 colour = self.grid.GetCellBackgroundColour(row, col-1)
1168 self.table.SetCellColour(row, col, colour)
1169
1170
1171 def Preview(self):
1172 self.table.Preview()
1173
1174
1175 def Print(self):
1176 self.table.Print()
1177
1178 #-------------------------------------------------------------------------------
1179
1180 class SetPrintout(wx.Printout):
1181 """
1182 ...
1183 """
1184 def __init__(self, canvas, text):
1185 wx.Printout.__init__(self)
1186
1187 self.canvas = canvas
1188 self.end_pg = 1000
1189 self.lines = text
1190
1191 #---------------------------------------------------------------------------
1192
1193 def OnBeginDocument(self, start, end):
1194 return super(SetPrintout, self).OnBeginDocument(start, end)
1195
1196
1197 def OnEndDocument(self):
1198 super(SetPrintout, self).OnEndDocument()
1199
1200
1201 def HasPage(self, page):
1202 try:
1203 end = self.canvas.HasPage(page)
1204 return end
1205 except:
1206 return True
1207
1208
1209 def GetPageInfo(self):
1210 try:
1211 self.end_pg = self.canvas.GetTotalPages()
1212 except:
1213 pass
1214
1215 end_pg = self.end_pg
1216 str_pg = 1
1217 return (str_pg, end_pg, str_pg, end_pg)
1218
1219
1220 def OnPreparePrinting(self):
1221 super(SetPrintout, self).OnPreparePrinting()
1222
1223
1224 def OnBeginPrinting(self):
1225 dc = self.GetDC()
1226
1227 self.preview = self.IsPreview()
1228 if (self.preview):
1229 self.pixelsPerInch = self.GetPPIScreen()
1230 else:
1231 self.pixelsPerInch = self.GetPPIPrinter()
1232
1233 (w, h) = dc.GetSize()
1234 scaleX = float(w) / 1000
1235 scaleY = float(h) / 1000
1236 self.printUserScale = min(scaleX, scaleY)
1237
1238 super(SetPrintout, self).OnBeginPrinting()
1239
1240
1241 def GetSize(self):
1242 self.psizew, self.psizeh = self.GetPPIPrinter()
1243 return self.psizew, self.psizeh
1244
1245
1246 def GetTotalSize(self):
1247 self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1248 return self.ptsizew, self.ptsizeh
1249
1250
1251 def OnPrintPage(self, page):
1252 dc = self.GetDC()
1253 (w, h) = dc.GetSize()
1254 scaleX = float(w) / 1000
1255 scaleY = float(h) / 1000
1256 self.printUserScale = min(scaleX, scaleY)
1257 dc.SetUserScale(self.printUserScale, self.printUserScale)
1258
1259 self.preview = self.IsPreview()
1260
1261 self.canvas.SetPreview(self.preview, self.printUserScale)
1262 self.canvas.SetPage(page)
1263
1264 self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
1265 self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh)
1266
1267 self.psizew, self.psizeh = self.GetPPIPrinter()
1268 self.canvas.SetPageSize(self.psizew, self.psizeh)
1269
1270 self.canvas.DoDrawing(dc)
1271 return True
1272
1273 #-------------------------------------------------------------------------------
1274
1275 class Frame(wx.Frame):
1276 """
1277 ...
1278 """
1279 def __init__(self, parent, id, title=""):
1280 wx.Frame.__init__(self,
1281 parent,
1282 id,
1283 title,
1284 size=(600, 450),
1285 style=wx.DEFAULT_FRAME_STYLE)
1286
1287 #------------
1288
1289 # Simplified init method.
1290 self.SetProperties()
1291 self.CreateMenu()
1292 self.CreateCtrls()
1293 self.CreatePrintData()
1294 self.BindEvents()
1295 self.DoLayout()
1296
1297 #------------
1298
1299 self.CenterOnScreen()
1300
1301 #---------------------------------------------------------------------------
1302
1303 def SetProperties(self):
1304 """
1305 Set the main frame properties (title, icon...).
1306 """
1307
1308 frameicon = wx.Icon("Icons/wxWidgets.ico")
1309 self.SetIcon(frameicon)
1310
1311 #------------
1312
1313 self.SetTitle("Dummy wx frame for testing printout.py")
1314
1315
1316 def CreateMenu(self):
1317 """
1318 ...
1319 """
1320
1321 menub = wx.MenuBar()
1322
1323 fmenu = wx.Menu()
1324 fmenu.Append(wx.ID_PREVIEW, "Print pre&view\tCtrl+V")
1325 fmenu.Append(wx.ID_PRINT, "&Print\tCtrl+P")
1326 fmenu.AppendSeparator()
1327 fmenu.Append(wx.ID_EXIT, "E&xit\tCtrl+X")
1328 menub.Append(fmenu, "&File")
1329
1330 self.SetMenuBar(menub)
1331
1332
1333 def CreateCtrls(self):
1334 """
1335 ...
1336 """
1337
1338 font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1339 font.SetWeight(wx.BOLD)
1340 font.SetPointSize(10)
1341
1342 #------------
1343
1344 # First create the controls.
1345 self.panel = wx.Panel(self, -1,
1346 style=wx.BORDER_THEME|
1347 wx.TAB_TRAVERSAL)
1348
1349 self.demo = wx.StaticText(self.panel,
1350 id=-1,
1351 label="Demonstrating :")
1352 self.demo.SetFont(font)
1353
1354 self.info = wx.StaticText(self.panel,
1355 id=-1,
1356 label="1) Direct printing,\n"
1357 "2) Printout class,\n"
1358 "3) PrintTable class,\n"
1359 "4) Preview,\n"
1360 "5) Menu")
1361 self.info.SetForegroundColour("red")
1362 font.SetWeight(wx.NORMAL)
1363 self.info.SetFont(font)
1364
1365 text = ('This the first line of text.\n'\
1366 'This is the second line and the third. The fourth will be the number 4.0.\n'\
1367 '4.0\n'\
1368 'This is the fifth line, but by design it is too long to fit in the width of a standard'\
1369 'page, so it will be forced to wrap around in order to fit without having'\
1370 'some of its verbose verbage truncated.\n'
1371 'Here we have the final line.')
1372
1373 self.tc = wx.TextCtrl(self.panel,
1374 id=-1,
1375 size=(200, -1),
1376 value=text,
1377 style=wx.TE_MULTILINE|wx.TE_DONTWRAP)
1378
1379 self.btnPreview = wx.Button(self.panel,
1380 id=wx.ID_PREVIEW,
1381 label="Print pre&view")
1382 self.btnPreview.SetFocus()
1383
1384 self.btnPrint = wx.Button(self.panel,
1385 id=wx.ID_PRINT,
1386 label="&Print")
1387
1388 self.btnClose = wx.Button(self.panel,
1389 id=wx.ID_CLOSE,
1390 label="E&xit")
1391
1392
1393 def CreatePrintData(self):
1394 """
1395 Create printing data.
1396 """
1397
1398 self.ptbl = PrintTable(self)
1399 self.ptbl.SetHeader('This is the test HEADER')
1400 self.ptbl.SetFooter()
1401
1402 #... but, if labels or columns are defined, a single sequence will print out as a single row
1403 self.ptbl.label = ('One','Two','Three','Four','5')
1404
1405
1406 def BindEvents(self):
1407 """
1408 Bind all the events related to my application.
1409 """
1410
1411 # Bind some menu events to an events handler.
1412 self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
1413 self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
1414 self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
1415
1416 # Bind the close event to an event handler.
1417 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1418
1419 # Bind some buttons events to an events handler.
1420 self.Bind(wx.EVT_BUTTON, self.OnPrintPreview, self.btnPreview)
1421 self.Bind(wx.EVT_BUTTON, self.OnPrint, self.btnPrint)
1422 self.Bind(wx.EVT_BUTTON, self.OnClose, self.btnClose)
1423
1424
1425 def DoLayout(self):
1426 """
1427 Manage widgets Layout.
1428 """
1429
1430 # MainSizer is the top-level one that manages everything.
1431 mainSizer = wx.BoxSizer(wx.VERTICAL)
1432
1433 #------------
1434
1435 hBox1 = wx.BoxSizer(wx.HORIZONTAL)
1436 hBox1.Add(self.info, 0, wx.ALL, 15)
1437
1438 #------------
1439
1440 hBox2 = wx.BoxSizer(wx.HORIZONTAL)
1441 hBox2.Add(self.btnPreview, 0, wx.ALL, 10)
1442 hBox2.Add(self.btnPrint, 0, wx.ALL, 10)
1443 hBox2.Add(self.btnClose, 0, wx.ALL, 10)
1444
1445 #------------
1446
1447 mainSizer.Add(self.demo, 0, wx.ALL, 10)
1448 mainSizer.Add(wx.StaticLine(self.panel),
1449 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
1450 mainSizer.Add(self.tc, 1, wx.EXPAND | wx.ALL, 15)
1451 mainSizer.Add(hBox1, 0, wx.ALL, 5)
1452 mainSizer.Add(hBox2, 0, wx.ALL, 5)
1453
1454 #------------
1455
1456 # Finally, tell the panel to use the mainSizer for layout.
1457 self.panel.SetSizer(mainSizer)
1458
1459
1460 def OnPrintPreview(self, event):
1461 text = self.tc.GetValue()
1462 resultat = text.splitlines()
1463 self.ptbl.data = (resultat)
1464 self.ptbl.Preview()
1465
1466
1467 def OnPrint(self, event):
1468 text = self.tc.GetValue()
1469 resultat = text.splitlines()
1470 self.ptbl.data = (resultat)
1471 self.ptbl.Print()
1472
1473
1474 def OnClose(self, evt):
1475 self.Close()
1476
1477
1478 def OnCloseWindow(self, event):
1479 """
1480 ...
1481 """
1482
1483 self.Destroy()
1484
1485 #-------------------------------------------------------------------------------
1486
1487 class App(wx.App):
1488 """
1489 ...
1490 """
1491 def OnInit(self):
1492
1493 #------------
1494
1495 self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
1496
1497 #------------
1498
1499 frame = Frame(None, id=-1)
1500 self.SetTopWindow(frame)
1501 frame.Show(True)
1502
1503 return True
1504
1505 #-------------------------------------------------------------------------------
1506
1507 def main():
1508 app = App(False)
1509 app.MainLoop()
1510
1511 #-------------------------------------------------------------------------------
1512
1513 if __name__ == "__main__" :
1514 main()
Note : you should create the printing data structures only for printing and destroy them after printing again.
There is no point in storing them permanently as self.grdprt.
Thanks to Dietmar Schwertberger for this info.
Download source
Additional Information
Link :
https://wiki.wxpython.org/MoreCommentsOnPrinting
https://wiki.wxpython.org/PrintingWithReportGenerators
http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/
https://www.blog.pythonlibrary.org/2010/02/14/python-windows-and-printers/
- - - - -
https://wiki.wxpython.org/TitleIndex
Thanks to
Lorne White, Jeff Grimmett, Vernon Cole, Robin Dunn, Andy Robinson / Robin Becker / The ReportLab team, David Hughe (PDFViewer), Ruikai Liu / Jorj X. McKie (PyMuPDF), Cody Precord, Mike Driscoll, Pascal Faut., Dietmar Schwertberger, Chris Barker, the wxPython community...
Thanks also to all known contributors or anonymous that I forgot.
And finally, congratulations to the many forums and blogs for all the available examples and the help which is the strength of wxPython.
About this page
Date (d/m/y) Person (bot) Comments :
00/00/00 - Sean McKay (originally Created).
10/10/18 - Ecco (Updated page and published examples for wxPython Phoenix).
Comments
- blah, blah, blah....