author | robin <robin@reportlab.com> |
Tue, 07 Mar 2017 10:00:34 +0000 | |
changeset 4330 | 617ffa6bbdc8 |
parent 4252 | fe660f227cac |
child 4370 | 823a8c33ce43 |
permissions | -rw-r--r-- |
3228 | 1 |
#!/usr/bin/env python |
4330 | 2 |
#Copyright ReportLab Europe Ltd. 2000-2017 |
3228 | 3 |
#see license.txt for license details |
4 |
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/grids.py |
|
4252 | 5 |
__version__='3.3.0' |
3228 | 6 |
|
7 |
from reportlab.graphics.widgetbase import Widget |
|
8 |
from reportlab.graphics.charts.textlabels import Label |
|
9 |
from reportlab.graphics import shapes |
|
10 |
from reportlab.lib import colors |
|
11 |
from reportlab.lib.validators import * |
|
12 |
from reportlab.lib.attrmap import * |
|
13 |
||
14 |
from reportlab.graphics.shapes import Drawing |
|
15 |
||
16 |
class TableWidget(Widget): |
|
17 |
"""A two dimensions table of labels |
|
18 |
""" |
|
19 |
||
20 |
_attrMap = AttrMap( |
|
21 |
x = AttrMapValue(isNumber, desc="x position of left edge of table"), |
|
22 |
y = AttrMapValue(isNumber, desc="y position of bottom edge of table"), |
|
23 |
width = AttrMapValue(isNumber, desc="table width"), |
|
24 |
height = AttrMapValue(isNumber, desc="table height"), |
|
25 |
borderStrokeColor = AttrMapValue(isColorOrNone, desc="table border color"), |
|
26 |
fillColor = AttrMapValue(isColorOrNone, desc="table fill color"), |
|
27 |
borderStrokeWidth = AttrMapValue(isNumber, desc="border line width"), |
|
28 |
horizontalDividerStrokeColor = AttrMapValue(isColorOrNone, desc="table inner horizontal lines color"), |
|
29 |
verticalDividerStrokeColor = AttrMapValue(isColorOrNone, desc="table inner vertical lines color"), |
|
30 |
horizontalDividerStrokeWidth = AttrMapValue(isNumber, desc="table inner horizontal lines width"), |
|
31 |
verticalDividerStrokeWidth = AttrMapValue(isNumber, desc="table inner vertical lines width"), |
|
32 |
dividerDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array for dividerLines.'), |
|
33 |
data = AttrMapValue(None, desc="a list of list of strings to be displayed in the cells"), |
|
34 |
boxAnchor = AttrMapValue(isBoxAnchor, desc="location of the table anchoring point"), |
|
35 |
fontName = AttrMapValue(isString, desc="text font in the table"), |
|
36 |
fontSize = AttrMapValue(isNumber, desc="font size of the table"), |
|
37 |
fontColor = AttrMapValue(isColorOrNone, desc="font color"), |
|
38 |
alignment = AttrMapValue(OneOf("left", "right"), desc="Alignment of text within cells"), |
|
39 |
textAnchor = AttrMapValue(OneOf('start','middle','end','numeric'), desc="Alignment of text within cells"), |
|
40 |
) |
|
41 |
||
42 |
def __init__(self, x=10, y=10, **kw): |
|
43 |
||
44 |
self.x = x |
|
45 |
self.y = y |
|
46 |
self.width = 200 |
|
47 |
self.height = 100 |
|
48 |
self.borderStrokeColor = colors.black |
|
49 |
self.fillColor = None |
|
50 |
self.borderStrokeWidth = 0.5 |
|
51 |
self.horizontalDividerStrokeColor = colors.black |
|
52 |
self.verticalDividerStrokeColor = colors.black |
|
53 |
self.horizontalDividerStrokeWidth = 0.5 |
|
54 |
self.verticalDividerStrokeWidth = 0.25 |
|
55 |
self.dividerDashArray = None |
|
56 |
self.data = [['North','South','East','West'],[100,110,120,130],['A','B','C','D']] # list of rows each row is a list of columns |
|
57 |
self.boxAnchor = 'nw' |
|
58 |
#self.fontName = None |
|
59 |
self.fontSize = 8 |
|
60 |
self.fontColor = colors.black |
|
61 |
self.alignment = 'right' |
|
62 |
self.textAnchor = 'start' |
|
63 |
||
64 |
||
3723
99aa837b6703
second stage of port to Python 3.3; working hello world
rptlab
parents:
3721
diff
changeset
|
65 |
for k, v in kw.items(): |
3721 | 66 |
if k in list(self.__class__._attrMap.keys()): |
3228 | 67 |
setattr(self, k, v) |
68 |
else: |
|
69 |
raise ValueError('invalid argument supplied for class %s'%self.__class__) |
|
70 |
||
71 |
def demo(self): |
|
72 |
""" returns a sample of this widget with data |
|
73 |
""" |
|
74 |
d = Drawing(400, 200) |
|
75 |
t = TableWidget() |
|
76 |
d.add(t, name='table') |
|
77 |
d.table.dividerDashArray = (1, 3, 2) |
|
78 |
d.table.verticalDividerStrokeColor = None |
|
79 |
d.table.borderStrokeWidth = 0 |
|
80 |
d.table.borderStrokeColor = colors.red |
|
81 |
return d |
|
82 |
||
83 |
def draw(self): |
|
84 |
""" returns a group of shapes |
|
85 |
""" |
|
86 |
g = shapes.Group() |
|
87 |
||
88 |
#overall border and fill |
|
89 |
if self.borderStrokeColor or self.fillColor: # adds border and filling color |
|
90 |
rect = shapes.Rect(self.x, self.y, self.width, self.height) |
|
91 |
rect.fillColor = self.fillColor |
|
92 |
rect.strokeColor = self.borderStrokeColor |
|
93 |
rect.strokeWidth = self.borderStrokeWidth |
|
94 |
g.add(rect) |
|
95 |
||
96 |
#special case - for an empty table we want to avoid divide-by-zero |
|
97 |
data = self.preProcessData(self.data) |
|
98 |
rows = len(self.data) |
|
99 |
cols = len(self.data[0]) |
|
100 |
#print "(rows,cols)=(%s, %s)"%(rows,cols) |
|
101 |
row_step = self.height / float(rows) |
|
102 |
col_step = self.width / float(cols) |
|
103 |
#print "(row_step,col_step)=(%s, %s)"%(row_step,col_step) |
|
104 |
# draw the grid |
|
105 |
if self.horizontalDividerStrokeColor: |
|
3721 | 106 |
for i in range(rows): # make horizontal lines |
3228 | 107 |
x1 = self.x |
108 |
x2 = self.x + self.width |
|
109 |
y = self.y + row_step*i |
|
110 |
#print 'line (%s, %s), (%s, %s)'%(x1, y, x2, y) |
|
111 |
line = shapes.Line(x1, y, x2, y) |
|
112 |
line.strokeDashArray = self.dividerDashArray |
|
113 |
line.strokeWidth = self.horizontalDividerStrokeWidth |
|
114 |
line.strokeColor = self.horizontalDividerStrokeColor |
|
115 |
g.add(line) |
|
116 |
if self.verticalDividerStrokeColor: |
|
3721 | 117 |
for i in range(cols): # make vertical lines |
3228 | 118 |
x = self.x+col_step*i |
119 |
y1 = self.y |
|
120 |
y2 = self.y + self.height |
|
121 |
#print 'line (%s, %s), (%s, %s)'%(x, y1, x, y2) |
|
122 |
line = shapes.Line(x, y1, x, y2) |
|
123 |
line.strokeDashArray = self.dividerDashArray |
|
124 |
line.strokeWidth = self.verticalDividerStrokeWidth |
|
125 |
line.strokeColor = self.verticalDividerStrokeColor |
|
126 |
g.add(line) |
|
127 |
||
128 |
# since we plot data from down up, we reverse the list |
|
129 |
self.data.reverse() |
|
130 |
for (j, row) in enumerate(self.data): |
|
131 |
y = self.y + j*row_step + 0.5*row_step - 0.5 * self.fontSize |
|
132 |
for (i, datum) in enumerate(row): |
|
133 |
if datum: |
|
134 |
x = self.x + i*col_step + 0.5*col_step |
|
135 |
s = shapes.String(x, y, str(datum), textAnchor=self.textAnchor) |
|
136 |
s.fontName = self.fontName |
|
137 |
s.fontSize = self.fontSize |
|
138 |
s.fillColor = self.fontColor |
|
139 |
g.add(s) |
|
140 |
return g |
|
141 |
||
142 |
def preProcessData(self, data): |
|
143 |
"""preprocess and return a new array with at least one row |
|
144 |
and column (use a None) if needed, and all rows the same |
|
145 |
length (adding Nones if needed) |
|
146 |
||
147 |
""" |
|
148 |
if not data: |
|
149 |
return [[None]] |
|
150 |
#make all rows have similar number of cells, append None when needed |
|
151 |
max_row = max( [len(x) for x in data] ) |
|
152 |
for rowNo, row in enumerate(data): |
|
153 |
if len(row) < max_row: |
|
154 |
row.extend([None]*(max_row-len(row))) |
|
155 |
return data |
|
156 |
||
157 |
#test |
|
158 |
if __name__ == '__main__': |
|
159 |
d = TableWidget().demo() |
|
160 |
import os |
|
161 |
d.save(formats=['pdf'],outDir=os.getcwd(),fnRoot=None) |