[reportlab-users] Flexible table layout
Dirk Holtwick
reportlab-users@reportlab.com
Thu, 13 Feb 2003 10:32:50 +0100
Hi,
here is a drop in suggestion for a more flexible table layout. for the
colWidths just pass a list of _width() objects and for totalWidth one
_width() object. Width can be
- an absolute value (_width("1.2cm"))
- a percentage (_width("33%"))
- a space consuming "spanner" (_width(None))
Attention, I added "align" to the init values! Was quite unhandy formerly.
Enjoy,
Dirk
-----
class MyTable(Table):
def __init__(self, data, align, colWidths=None,
totalWidth=None, rowHeights=None, style=None,
repeatRows=0, repeatCols=0, splitByRow=1,
emptyTableAction=None):
self._data = data
self._align = align
self._colwidths = colWidths
self._rowheights = rowHeights
self._style = style
self._repeatrows = repeatRows
self._repeatcols = repeatCols
self._splitbyrow = splitByRow
self._emptytableaction = emptyTableAction
self._notset = 1
self._totalwidth = totalWidth
def wrap(self, aw, ah):
if self._notset:
self._notset = 0
cw = self._colwidths
tw = self._totalwidth.calc(aw)
ws = []
sc = 0
sp = 0
# calculate known
for c in cw:
if c.span():
ws.append(None)
sc = sc + 1
else:
v = c.calc(tw)
sp = sp + v
ws.append(v)
# donate space to the rest
cw = []
if sc:
rest = (tw - sp) / sc
for c in ws:
if c==None:
cw.append(rest)
else:
cw.append(c)
else:
cw = ws
Table.__init__(self,
self._data,
cw,
self._rowheights,
self._style,
self._repeatrows,
self._repeatcols,
self._splitbyrow,
self._emptytableaction)
self.hAlign = self._align
return Table.wrap(self, aw, ah)
def get_length(s):
try:
s = str(s)
# for us germans, we like comma ;-)
s = string.replace(s,",",".")
if s[-2:]=='cm': return float(s[:-2])*cm
if s[-2:]=='in': return float(s[:-2])*inch
if s[-2:]=='pt': return float(s[:-2])
if s[-1:]=='i': return float(s[:-1])*inch
return float(s)
except:
raise ValueError, "Can't convert '%s' to length" % s
class _width:
def __init__(self, value=None):
self.value = None
self.fix = None
if value!=None:
self.set(value)
def set(self, value):
if string.find(value,"%")>=0:
self.value = float(
string.strip(string.replace(value, "%", "")))
self.fix = 0
else:
self.value = get_length(value)
self.fix = 1
def calc(self, avail):
if self.value==None:
return avail
if self.fix:
return self.value
else:
return ((avail/100.0)*self.value)
def span(self):
return not self.value