341
|
1 |
#ch6_tables
|
|
2 |
|
|
3 |
from genuserguide import *
|
424
|
4 |
from reportlab.platypus import Image
|
341
|
5 |
|
|
6 |
heading1("Tables and TableStyles")
|
|
7 |
disc("""
|
399
|
8 |
The $Table$ class is derived from the $Flowable$ class and is intended
|
341
|
9 |
as a simple textual gridding mechanism. $Table$ cells can hold anything which can be converted to
|
|
10 |
a <b>Python</b> $string$.
|
|
11 |
""")
|
|
12 |
|
|
13 |
disc("""
|
|
14 |
$Tables$ are created by passing the constructor a sequence of column widths,
|
|
15 |
a sequence of row heights and the data in
|
|
16 |
row order. Drawing of the table can be controlled by using a $TableStyle$ instance. This allows control of the
|
|
17 |
color and weight of the lines (if any), and the font, alignment and padding of the text.
|
|
18 |
A primitive automatic row height and or column width calculation mechanism is provided for.
|
|
19 |
""")
|
|
20 |
|
399
|
21 |
heading2('$Table$ User Methods')
|
|
22 |
disc("""These are the main methods which are of interest to the client programmer.""")
|
341
|
23 |
|
356
|
24 |
heading4("""$Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1,
|
|
25 |
repeatRows=0, repeatCols=0)$""")
|
341
|
26 |
|
|
27 |
disc("""The $data$ argument is a sequence of sequences of cell values each of which
|
424
|
28 |
should be convertible to a string value using the $str$ function or should be a Flowable instance (such as a $Paragraph$) or a list (or tuple) of such instances.
|
|
29 |
If a cell value is a $Flowable$ or list of $Flowables$ these must either have a determined width
|
|
30 |
or the containing column must have a fixed width.
|
|
31 |
The first row of cell values
|
399
|
32 |
is in $data[0]$ i.e. the values are in row order. The $i$, $j$<sup>th.</sup> cell value is in
|
341
|
33 |
$data[i][j]$. Newline characters $'\\n'$ in cell values are treated as line split characters and
|
|
34 |
are used at <i>draw</i> time to format the cell into lines.
|
|
35 |
""")
|
356
|
36 |
disc("""The other arguments are fairly obvious, the $colWidths$ argument is a sequence
|
|
37 |
of numbers or possibly $None$, representing the widths of the columns. The number of elements
|
|
38 |
in $colWidths$ determines the number of columns in the table.
|
|
39 |
A value of $None$ means that the corresponding column width should be calculated automatically.""")
|
341
|
40 |
|
356
|
41 |
disc("""The $rowHeights$ argument is a sequence
|
|
42 |
of numbers or possibly $None$, representing the heights of the rows. The number of elements
|
|
43 |
in $rowHeights$ determines the number of rows in the table.
|
|
44 |
A value of $None$ means that the corresponding row height should be calculated automatically.""")
|
|
45 |
|
|
46 |
disc("""The $style$ argument can be an initial style for the table.""")
|
399
|
47 |
disc("""The $splitByRow$ argument is a Boolean indicating that the $Table$ should split itself
|
|
48 |
by row before attempting to split itself by column when too little space is available in
|
356
|
49 |
the current drawing area and the caller wants the $Table$ to split.""")
|
|
50 |
|
|
51 |
disc("""The $repeatRows$ and $repeatCols$ arguments specify the number of leading rows and columns
|
|
52 |
that should be repeated when the $Table$ is asked to split itself.""")
|
399
|
53 |
heading4('$Table.setStyle(tblStyle)$')
|
341
|
54 |
disc("""
|
399
|
55 |
This method applies a particular instance of class $TableStyle$ (discussed below)
|
341
|
56 |
to the $Table$ instance. This is the only way to get $tables$ to appear
|
|
57 |
in a nicely formatted way.
|
|
58 |
""")
|
|
59 |
disc("""
|
|
60 |
Successive uses of the $setStyle$ method apply the styles in an additive fashion.
|
399
|
61 |
That is, later applications override earlier ones where they overlap.
|
341
|
62 |
""")
|
|
63 |
|
399
|
64 |
heading2('$TableStyle$')
|
341
|
65 |
disc("""
|
399
|
66 |
This class is created by passing it a sequence of <i>commands</i>, each command
|
341
|
67 |
is a tuple identified by its first element which is a string; the remaining
|
399
|
68 |
elements of the command tuple represent the start and stop cell coordinates
|
|
69 |
of the command and possibly thickness and colors, etc.
|
341
|
70 |
""")
|
349
|
71 |
heading2("$TableStyle$ User Methods")
|
|
72 |
heading3("$TableStyle(commandSequence)$")
|
341
|
73 |
disc("""The creation method initializes the $TableStyle$ with the argument
|
|
74 |
command sequence as an example:""")
|
|
75 |
eg("""
|
|
76 |
LIST_STYLE = TableStyle(
|
|
77 |
[('LINEABOVE', (0,0), (-1,0), 2, colors.green),
|
|
78 |
('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black),
|
|
79 |
('LINEBELOW', (0,-1), (-1,-1), 2, colors.green),
|
|
80 |
('ALIGN', (1,1), (-1,-1), 'RIGHT')]
|
|
81 |
)
|
|
82 |
""")
|
349
|
83 |
heading3("$TableStyle.add(commandSequence)$")
|
341
|
84 |
disc("""This method allows you to add commands to an existing
|
399
|
85 |
$TableStyle$, i.e. you can build up $TableStyles$ in multiple statements.
|
341
|
86 |
""")
|
|
87 |
eg("""
|
|
88 |
LIST_STYLE.add([('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7))])
|
|
89 |
""")
|
349
|
90 |
heading3("$TableStyle.getCommands()$")
|
341
|
91 |
disc("""This method returns the sequence of commands of the instance.""")
|
|
92 |
eg("""
|
|
93 |
cmds = LIST_STYLE.getCommands()
|
|
94 |
""")
|
349
|
95 |
heading2("$TableStyle$ Commands")
|
341
|
96 |
disc("""The commands passed to $TableStyles$ come in three main groups
|
|
97 |
which affect the table background, draw lines, or set cell styles.
|
|
98 |
""")
|
|
99 |
disc("""The first element of each command is its identifier,
|
|
100 |
the second and third arguments determine the cell coordinates of
|
|
101 |
the box of cells which are affected with negative coordinates
|
|
102 |
counting backwards from the limit values as in <b>Python</b>
|
|
103 |
indexing. The coordinates are given as
|
399
|
104 |
(column, row) which follows the spreadsheet 'A1' model, but not
|
341
|
105 |
the more natural (for mathematicians) 'RC' ordering.
|
399
|
106 |
The top left cell is (0, 0) the bottom right is (-1, -1). Depending on
|
|
107 |
the command various extra (???) occur at indices beginning at 3 on.
|
341
|
108 |
""")
|
349
|
109 |
heading3("""$TableStyle$ Cell Formatting Commands""")
|
341
|
110 |
disc("""The cell formatting commands all begin with an identifier, followed by
|
|
111 |
the start and stop cell definitions and the perhaps other arguments.
|
|
112 |
the cell formatting commands are:""")
|
|
113 |
eg("""
|
362
|
114 |
FONT - takes fontname, optional fontsize and optional leading.
|
|
115 |
FONTNAME (or FACE) - takes fontname.
|
|
116 |
FONTSIZE (or SIZE) - takes fontsize in points; leading may get out of sync.
|
|
117 |
LEADING - takes leading in points.
|
341
|
118 |
TEXTCOLOR - takes a color name or (R,G,B) tuple.
|
|
119 |
ALIGNMENT (or ALIGN) - takes one of LEFT, RIGHT and CENTRE (or CENTER).
|
|
120 |
LEFTPADDING - takes an integer, defaults to 6.
|
|
121 |
RIGHTPADDING - takes an integer, defaults to 6.
|
|
122 |
BOTTOMPADDING - takes an integer, defaults to 3.
|
|
123 |
TOPPADDING - takes an integer, defaults to 3.
|
|
124 |
BACKGROUND - takes a color.
|
|
125 |
VALIGN - takes one of TOP, MIDDLE or the default BOTTOM
|
|
126 |
""")
|
|
127 |
disc("""This sets the background cell color in the relevant cells.
|
399
|
128 |
The following example shows the $BACKGROUND$, and $TEXTCOLOR$ commands in action:""")
|
341
|
129 |
EmbeddedCode("""
|
|
130 |
data= [['00', '01', '02', '03', '04'],
|
|
131 |
['10', '11', '12', '13', '14'],
|
|
132 |
['20', '21', '22', '23', '24'],
|
|
133 |
['30', '31', '32', '33', '34']]
|
356
|
134 |
t=Table(data)
|
341
|
135 |
t.setStyle(TableStyle([('BACKGROUND',(1,1),(-2,-2),colors.green),
|
|
136 |
('TEXTCOLOR',(0,0),(1,-1),colors.red)]))
|
|
137 |
""")
|
|
138 |
disc("""To see the effects of the alignment styles we need some widths
|
|
139 |
and a grid, but it should be easy to see where the styles come from.""")
|
|
140 |
EmbeddedCode("""
|
|
141 |
data= [['00', '01', '02', '03', '04'],
|
|
142 |
['10', '11', '12', '13', '14'],
|
|
143 |
['20', '21', '22', '23', '24'],
|
|
144 |
['30', '31', '32', '33', '34']]
|
356
|
145 |
t=Table(data,5*[0.4*inch], 4*[0.4*inch])
|
341
|
146 |
t.setStyle(TableStyle([('ALIGN',(1,1),(-2,-2),'RIGHT'),
|
|
147 |
('TEXTCOLOR',(1,1),(-2,-2),colors.red),
|
|
148 |
('VALIGN',(0,0),(0,-1),'TOP'),
|
|
149 |
('TEXTCOLOR',(0,0),(0,-1),colors.blue),
|
|
150 |
('ALIGN',(0,-1),(-1,-1),'CENTER'),
|
|
151 |
('VALIGN',(0,-1),(-1,-1),'MIDDLE'),
|
|
152 |
('TEXTCOLOR',(0,-1),(-1,-1),colors.green),
|
|
153 |
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
|
|
154 |
('BOX', (0,0), (-1,-1), 0.25, colors.black),
|
|
155 |
]))
|
|
156 |
""")
|
349
|
157 |
heading3("""$TableStyle$ Line Commands""")
|
341
|
158 |
disc("""
|
399
|
159 |
Line commands begin with the identifier, the start and stop cell coordinates
|
341
|
160 |
and always follow this with the thickness (in points) and color of the desired lines. Colors can be names,
|
399
|
161 |
or they can be specified as a (R, G, B) tuple, where R, G and B are floats and (0, 0, 0) is black. The line
|
341
|
162 |
command names are: GRID, BOX, OUTLINE, INNERGRID, LINEBELOW, LINEABOVE, LINEBEFORE
|
|
163 |
and LINEAFTER. BOX and OUTLINE are equivalent, and GRID is the equivalent of applying both BOX and
|
|
164 |
INNERGRID.
|
|
165 |
""")
|
363
|
166 |
CPage(4.0)
|
341
|
167 |
disc("""We can see some line commands in action with the following example.
|
|
168 |
""")
|
|
169 |
EmbeddedCode("""
|
|
170 |
data= [['00', '01', '02', '03', '04'],
|
|
171 |
['10', '11', '12', '13', '14'],
|
|
172 |
['20', '21', '22', '23', '24'],
|
|
173 |
['30', '31', '32', '33', '34']]
|
360
|
174 |
t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
|
|
175 |
('BOX',(0,0),(1,-1),2,colors.red),
|
|
176 |
('LINEABOVE',(1,2),(-2,2),1,colors.blue),
|
|
177 |
('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
|
|
178 |
])
|
341
|
179 |
""")
|
424
|
180 |
disc("""Line commands cause problems for tables when they split; the following example
|
|
181 |
shows a table being split in various positions""")
|
|
182 |
EmbeddedCode("""
|
|
183 |
data= [['00', '01', '02', '03', '04'],
|
|
184 |
['10', '11', '12', '13', '14'],
|
|
185 |
['20', '21', '22', '23', '24'],
|
|
186 |
['30', '31', '32', '33', '34']]
|
|
187 |
t=Table(data,style=[
|
|
188 |
('GRID',(0,0),(-1,-1),0.5,colors.grey),
|
|
189 |
('GRID',(1,1),(-2,-2),1,colors.green),
|
|
190 |
('BOX',(0,0),(1,-1),2,colors.red),
|
|
191 |
('BOX',(0,0),(-1,-1),2,colors.black),
|
|
192 |
('LINEABOVE',(1,2),(-2,2),1,colors.blue),
|
|
193 |
('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
|
|
194 |
('BACKGROUND', (0, 0), (0, 1), colors.pink),
|
|
195 |
('BACKGROUND', (1, 1), (1, 2), colors.lavender),
|
|
196 |
('BACKGROUND', (2, 2), (2, 3), colors.orange),
|
|
197 |
])
|
|
198 |
""")
|
|
199 |
t=getStory()[-1]
|
|
200 |
getStory().append(Spacer(0,6))
|
|
201 |
for s in t.split(4*inch,30):
|
|
202 |
getStory().append(s)
|
|
203 |
getStory().append(Spacer(0,6))
|
|
204 |
getStory().append(Spacer(0,6))
|
|
205 |
for s in t.split(4*inch,36):
|
|
206 |
getStory().append(s)
|
|
207 |
getStory().append(Spacer(0,6))
|
|
208 |
|
|
209 |
disc("""When unsplit and split at the first or second row.""")
|
|
210 |
|
|
211 |
CPage(4.0)
|
|
212 |
heading3("""Complex Cell Values""")
|
|
213 |
disc("""
|
|
214 |
As mentioned above we can have complicated cell values including $Paragraphs$, $Images$ and other $Flowables$
|
|
215 |
or lists of the same. To see this in operation consider the following code and the table it produces.
|
|
216 |
Note that the $Image$ has a white background which will obscure any background you choose for the cell.
|
|
217 |
To get better results you should use a transparent background.
|
|
218 |
""")
|
|
219 |
import os, reportlab.platypus
|
|
220 |
I = '../images/replogo.gif'
|
|
221 |
EmbeddedCode("""
|
|
222 |
I = Image('%s')
|
|
223 |
I.drawHeight = 1.25*inch*I.drawHeight / I.drawWidth
|
|
224 |
I.drawWidth = 1.25*inch
|
|
225 |
I.noImageCaching = 1
|
|
226 |
P0 = Paragraph('''
|
|
227 |
<b>A pa<font color=red>r</font>a<i>graph</i></b>
|
|
228 |
<super><font color=yellow>1</font></super>''',
|
|
229 |
styleSheet["BodyText"])
|
|
230 |
P = Paragraph('''
|
|
231 |
<para align=center spaceb=3>The <b>ReportLab Left
|
|
232 |
<font color=red>Logo</font></b>
|
|
233 |
Image</para>''',
|
|
234 |
styleSheet["BodyText"])
|
|
235 |
data= [['A', 'B', 'C', P0, 'D'],
|
|
236 |
['00', '01', '02', [I,P], '04'],
|
|
237 |
['10', '11', '12', [P,I], '14'],
|
|
238 |
['20', '21', '22', '23', '24'],
|
|
239 |
['30', '31', '32', '33', '34']]
|
|
240 |
|
|
241 |
t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
|
|
242 |
('BOX',(0,0),(1,-1),2,colors.red),
|
|
243 |
('LINEABOVE',(1,2),(-2,2),1,colors.blue),
|
|
244 |
('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
|
|
245 |
('BACKGROUND', (0, 0), (0, 1), colors.pink),
|
|
246 |
('BACKGROUND', (1, 1), (1, 2), colors.lavender),
|
|
247 |
('BACKGROUND', (2, 2), (2, 3), colors.orange),
|
|
248 |
('BOX',(0,0),(-1,-1),2,colors.black),
|
|
249 |
('GRID',(0,0),(-1,-1),0.5,colors.black),
|
|
250 |
('VALIGN',(3,0),(3,0),'BOTTOM'),
|
|
251 |
('BACKGROUND',(3,0),(3,0),colors.limegreen),
|
|
252 |
('BACKGROUND',(3,1),(3,1),colors.khaki),
|
|
253 |
('ALIGN',(3,1),(3,1),'CENTER'),
|
|
254 |
('BACKGROUND',(3,2),(3,2),colors.beige),
|
|
255 |
('ALIGN',(3,2),(3,2),'LEFT'),
|
|
256 |
])
|
|
257 |
|
|
258 |
t._argW[3]=1.5*inch
|
|
259 |
"""%I)
|
|
260 |
|
387
|
261 |
heading1("""Other Useful $Flowables$""")
|
441
|
262 |
heading2("""$Preformatted(text, style, bulletText = None, dedent=0)$""")
|
|
263 |
disc("""
|
|
264 |
Creates a preformatted paragraph which does no wrapping, line splitting or other manipulations.
|
|
265 |
No $XML$ style tags are taken account of in the text.
|
|
266 |
If dedent is non zero $dedent$ common leading
|
|
267 |
spaces will be removed from the front of each line.
|
|
268 |
""")
|
|
269 |
heading2("""$XPreformatted(text, style, bulletText = None, dedent=0, frags=None)$""")
|
|
270 |
disc("""
|
|
271 |
This is a non rearranging form of the $Paragraph$ class; $XML$ tags are allowed in
|
|
272 |
$text$ and have the same meanings as for the $Paragraph$ class.
|
|
273 |
As for $Preformatted$, if dedent is non zero $dedent$ common leading
|
|
274 |
spaces will be removed from the front of each line.
|
|
275 |
""")
|
|
276 |
EmbeddedCode("""
|
|
277 |
from reportlab.lib.styles import getSampleStyleSheet
|
|
278 |
stylesheet=getSampleStyleSheet()
|
|
279 |
normalStyle = stylesheet['Normal']
|
|
280 |
text='''
|
|
281 |
This is a non rearranging form of the <b>Paragraph</b> class;
|
|
282 |
<b><font color=red>XML</font></b> tags are allowed in <i>text</i> and have the same
|
|
283 |
meanings as for the <b>Paragraph</b> class.
|
|
284 |
As for <b>Preformatted</b>, if dedent is non zero <font color=red size=+1>dedent</font>
|
|
285 |
common leading spaces will be removed from the
|
|
286 |
front of each line.
|
|
287 |
'''
|
|
288 |
t=XPreformatted(text,normalStyle,dedent=3)
|
|
289 |
""")
|
387
|
290 |
heading2("""$Image(filename, width=None, height=None)$""")
|
|
291 |
disc("""Create a flowable which will contain the image defined by the data in file $filename$.
|
|
292 |
The default <b>PDF</b> image type <i>jpeg</i> is supported and if the <b>PIL</b> extension to <b>Python</b>
|
|
293 |
is installed the other image types can also be handled. If $width$ and or $height$ are specified
|
|
294 |
then they determine the dimension of the displayed image in <i>points</i>. If either dimension is
|
|
295 |
not specified (or specified as $None$) then the corresponding pixel dimension of the image is assumed
|
|
296 |
to be in <i>points</i> and used.
|
|
297 |
""")
|
391
|
298 |
I=os.path.join(os.path.dirname(__file__),'..','images','lj8100.jpg')
|
387
|
299 |
eg("""
|
389
|
300 |
Image("lj8100.jpg")
|
387
|
301 |
""",after=0.1)
|
|
302 |
disc("""will display as""")
|
391
|
303 |
try:
|
|
304 |
getStory().append(Image(I))
|
|
305 |
except:
|
|
306 |
disc("""An image should have appeared here.""")
|
387
|
307 |
disc("""whereas""")
|
|
308 |
eg("""
|
389
|
309 |
Image("lj8100.jpg", width=2*inch, height=2*inch)
|
387
|
310 |
""", after=0.1)
|
|
311 |
disc('produces')
|
391
|
312 |
try:
|
|
313 |
getStory().append(Image(I, width=2*inch, height=2*inch))
|
|
314 |
except:
|
|
315 |
disc("""An image should have appeared here.""")
|
387
|
316 |
heading2("""$Spacer(width, height)$""")
|
|
317 |
disc("""This does exactly as would be expected; it adds a certain amount of space into the story.
|
|
318 |
At present this only works for vertical space.
|
|
319 |
""")
|
|
320 |
CPage(1)
|
|
321 |
heading2("""$PageBreak()$""")
|
|
322 |
disc("""This $Flowable$ represents a page break. It works by effectively consuming all vertical
|
399
|
323 |
space given to it. This is sufficient for a single $Frame$ document, but would only be a
|
387
|
324 |
frame break for multiple frames so the $BaseDocTemplate$ mechanism
|
|
325 |
detects $pageBreaks$ internally and handles them specially.
|
|
326 |
""")
|
|
327 |
CPage(1)
|
|
328 |
heading2("""$CondPageBreak(height)$""")
|
399
|
329 |
disc("""This $Flowable$ attempts to force a $Frame$ break if insufficient vertical space remains
|
|
330 |
in the current $Frame$. It is thus probably wrongly named and should probably be renamed as
|
387
|
331 |
$CondFrameBreak$.
|
|
332 |
""")
|
|
333 |
CPage(1)
|
|
334 |
heading2("""$KeepTogether(flowables)$""")
|
|
335 |
disc("""
|
|
336 |
This compound $Flowable$ takes a list of $Flowables$ and attempts to keep them in the same $Frame$.
|
|
337 |
If the total height of the $Flowables$ in the list $flowables$ exceeds the current frame's available
|
|
338 |
space then all the space is used and a frame break is forced.
|
|
339 |
""")
|