2013-01-23 542 views
2

我正在將數據庫從pfaf.org(未來的工廠)轉換爲pdf書籍。 我在pageTemplates方面遇到了一些絆腳石。ReportLab變量nextPageTemplate的

每種植物都可以從左或右對齊的頁面開始;並可能有兩個或更多頁面。 我有兩個用於第一個工廠頁面的模板(左側和右側)以及另外兩個用於潛在後續頁面的模板。

目前這一處理(例如)如下:

for i, plant in enumerate(plants): 
    #the first plant is printed on a right-hand page 
    if i % 2 == 0: 
    template = 'left' 
    second = 'right' 
    else: 
    template = 'right' 
    second = 'left' 

    Story.append(nextPageTemplate(template,'*', 'secondary_'+template, 'secondary_'+second)) 
    Story.append(PageBreak()) 
    #append various paragraphs, jumping between frames, etc... 

代碼(如你可能知道)工作正常,單頁的植物。 它也適用於多頁面工廠(半)。

但是,正如您也可能看到的,兩個(或四個等)頁面工廠將打破模板排列,因爲上面的代碼假定頁面位置基於工廠編號而不是頁碼。

我在上面的代碼的位置(即在Story.append循環期間)中看不到解決方案 - 因爲在那一點上我無法分辨工廠是否使用了多個頁面,因此我目前正在瀏覽哪個頁面,如此。

我希望我可以調整我的自定義docTemplate中的nextPageTemplate結構,但我無法弄清楚這是否可能。

是嗎?還是有另一種解決方案?非常感謝任何幫助。一直在閱讀,但我能找到的最好的例子並不完全涵蓋這種情況。

有任何問題,請詢問。 謝謝


謝謝Nitzle:
麻煩的是,我不知道每個工廠將有多少頁佔用。例如,一個新的工廠開始在一個奇怪的頁面上,所以我給它一個模板循環('right','*','secondaryLeft','secondaryRight')。 [輔助頁面只是一個具有適當邊距的單個框架。]

如果該工廠只有一頁,沒問題,則下一個工廠的模板循環與上述相反。然而,如果工廠有兩頁,它會導致下面的工廠再次在一個奇怪的頁面上掉落,因此模板循環不應該改變......我希望這是有道理的。

這是我遇到了麻煩的情況...如果我像你說的那樣做,它不允許多個頁面工廠。我的大部分代碼如下所示;儘管我已經嘗試將它縮小一點,但希望它仍然包含所有相關的東西,不要太多。

import os 
import sys 
import MySQLdb 

from reportlab.platypus import Spacer, Image, Table, TableStyle, PageBreak, FrameBreak, paraparser 
from reportlab.platypus.doctemplate import BaseDocTemplate, PageTemplate, NextPageTemplate, _doNothing 
from reportlab.platypus.tableofcontents import TableOfContents 
from reportlab.platypus.frames import Frame 
from reportlab.platypus.flowables import KeepInFrame 
from reportlab.platypus.paragraph import Paragraph 

from reportlab.lib.units import mm, cm 
from reportlab.lib.pagesizes import A4, A5 
from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER, TA_RIGHT 
from reportlab.lib.styles import StyleSheet1, ParagraphStyle as PS 
from reportlab.lib import colors 

from reportlab.graphics.shapes import Drawing, Rect, String 

from reportlab.pdfbase.pdfmetrics import registerFont, stringWidth 
from reportlab.pdfbase.ttfonts import TTFont 
from reportlab.rl_config import warnOnMissingFontGlyphs 
warnOnMissingFontGlyphs = 0 

registerFont(TTFont('Museo_', '/home/wuwei/.fonts/Museo300-Regular.ttf')) 
registerFont(TTFont('Museo_M', '/home/wuwei/.fonts/Museo500-Regular.ttf')) 
registerFont(TTFont('Trebuchet', '/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS.ttf')) 
registerFont(TTFont('Trebuchet_I', '/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Italic.ttf')) 

## SOME VARIABLE DEFINITIONS ## 

titleFont = "Museo_M" 
subtitleFont = "Museo_" 
stdFont = "Trebuchet" 
stdItalic = "Trebuchet_I" 
#stdSize = 14 

"""CREATE GLOBALS""" 
_w, _h = A4 
_head_w = 17.5*cm 
_head_pad = 0.2*cm 
_main_w = 17.2*cm 
_budge = 0.3*cm 

_left_margin = 1.5*cm 
_right_margin = 2.0*cm 
_top_margin = 1.5*cm 
_bottom_margin = 2.0*cm 

_latinFontS = 18 

#reset superFraction to style 'common name' placement 
paraparser.superFraction = 0.15 
paraparser.sizeDelta = 0 


########################################################################################################### 
#########################################     ############################################### 
########################################  DB FUNCTIONS  ############################################# 
#########################################     ############################################### 
########################################################################################################### 

def connectToDB(): 
    try: 
     connection = MySQLdb.connect (host = "localhost", 
           user = "root", 
           passwd = "****************", 
           db = "pfaf") 
    except MySQLdb.Error, e: 
     print "I guess, either you don't have a local copy of the pfaf db" 
     print "or something is wrong with your connection details." 
     print "Error %d: %s" % (e.args[0], e.args[1]) 
     sys.exit (1) 

    return connection 

def close(item, exit=0): 
    #used to close both database cursors and connections 
    item.close() 
    if exit == 1: 
     sys.exit (0) 

def runQuery(q, conn): 
    results = conn.cursor(MySQLdb.cursors.DictCursor) 
    results.execute (q) 
    return results 

def Fetch(results, fetchAll=0): 
    if fetchAll: 
     print "fetchAll" 
     # FETCHALL option: 
     rows = results.fetchall() 
     #cursor.close() 
     #conn.close() 
     '''for row in rows: 
      print "%s, %s" % (row["Latin Name"], row["Hardyness"]) 
     print "%d rows were returned" % results.rowcount''' 
     return rows 
    else: 
     # FETCHONE option: 
     ##--- Print some debug info to command line ---## 
     print "Latin Name - Common Name - Hardyness"  
     while (1): 
      row = results.fetchone() 
      if row == None: 
       break 

      latin_name = row["Latin Name"] 
      common_name = row["Common name"] 
      hardyness = row["Hardyness"] 
      family = row["Family"] 
      synonyms = row["Synonyms"] 

     ##--- Print some more useful debug info to command line ---## 
      print "%s - %s - %s" % (latin_name, common_name, hardyness) 
     print row 

     if results.rowcount != 1: 
      print "%d rows were returned" % results.rowcount 
     else: 
      print "%d row was returned" % results.rowcount 

     return row 


########################################################################################################### 
#########################################     ############################################### 
######################################## STORY PROCESSING ############################################# 
#########################################     ############################################### 
########################################################################################################### 

def drawBorders(canv, side): 
    canv.saveState() 
    d = Drawing(0,0) 

    #header border# 
    r = Rect(side-_budge, _h-(2.4*cm), _head_w+(_budge*2), 1.2*cm, rx=5, ry=5) 
    r.strokeColor = colors.black 
    r.fillColor = colors.white 
    r.strokeWidth = 1.5 
    d.add(r) 

    #hardyness border# 
    rad = 5 
    hWidth = 1.4*cm 
    if side == _left_margin: 
     hPos = -rad 
    else: 
     hPos = _w - hWidth + rad 
    r = Rect(hPos, _h-(3.8*cm), hWidth, 1.2*cm, rx=rad, ry=rad) 
    r.strokeColor = colors.black 
    r.fillColor = colors.white 
    r.strokeWidth = 1.5 
    d.add(r) 

    d.drawOn(canv, 0, 0) 
    canv.restoreState() 

def drawFooter(canv, doc): 
    canv.saveState() 
    canv.setFont(stdFont,10) 
    canv.drawCentredString((_w/2.0), 1.5*cm, "%d - %s" % (doc.page, doc.latinName))   
    canv.restoreState() 


class LeftPageTemplate(PageTemplate): 
    def __init__(self): 
     #allow a bigger margin on the right for binding 
     latinF = Frame(_left_margin, 27.5*cm, _head_w, 0.8*cm,  id='latinL', showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     hardyF = Frame(0.1*cm, 26.05*cm, cm, cm, id='hardL',  showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     synF =  Frame(_left_margin, 26.65*cm, _main_w, 0.55*cm, id='synL',  showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     otherF = Frame(_left_margin, 22.1*cm, 12.4*cm, 4.5*cm, id='otherL',  showBoundary=1) 
     calF =  Frame(14.2*cm, 22.1*cm, 4.5*cm, 4.5*cm, id='calL',  showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     flowF =  Frame(_left_margin, 2.0*cm, _main_w, 19.85*cm, id='flowL',  showBoundary=1) 

     PageTemplate.__init__(self, 
           id='left', 
           frames=[latinF, hardyF, synF, otherF, calF, flowF], 
           pagesize=A4) 

    def beforeDrawPage(self, canv, doc): 
     drawBorders(canv, _left_margin) 

    def afterDrawPage(self, canv, doc): 
     drawFooter(canv, doc) 


class RightPageTemplate(PageTemplate): 
    def __init__(self): 
     #allow a bigger margin on the left for binding 
     latinF = Frame(_right_margin, 27.5*cm, _head_w, 0.8*cm,  id='latinR', showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     hardyF = Frame(_w-1.1*cm, 26.05*cm, cm, cm, id='hardR',  showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     synF =  Frame(_right_margin+_budge, 26.65*cm, _main_w, 0.55*cm, id='synR',  showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     calF =  Frame(_right_margin+_budge, 22.1*cm, 4.5*cm, 4.5*cm, id='calR',  showBoundary=0, 
          rightPadding=0, leftPadding=0, topPadding=0, bottomPadding=0) 
     otherF = Frame(_right_margin+5.1*cm, 22.1*cm, 12.4*cm, 4.5*cm, id='otherR',  showBoundary=1) 
     flowF =  Frame(_right_margin+_budge, 2.0*cm, _main_w, 19.85*cm, id='flowR',  showBoundary=1) 

     PageTemplate.__init__(self, 
           id='right', 
           frames=[latinF, hardyF, synF, otherF, calF, flowF], 
           pagesize=A4) 

    def beforeDrawPage(self, canv, doc): 
     drawBorders(canv, _right_margin) 

    def afterDrawPage(self, canv, doc): 
     drawFooter(canv, doc) 


class MyDocTemplate(BaseDocTemplate): 
    _invalidInitArgs = ('pageTemplates',) 

    def __init__(self, filename, **kw): 
     self.allowSplitting = 0 
     BaseDocTemplate.__init__(self, filename, **kw) 

     self.latinName = "(none initially)" 
     self.latinWidth = 0 #(none initially) 

    def afterInit(self): 
     self._calc() #in case we have changed margin sizes etc 

     self.leftMargin = _left_margin 
     self.rightMargin = _right_margin 
     self.topMargin = _top_margin 
     self.bottomMargin = _bottom_margin 
     self.width = _w - self.leftMargin - self.rightMargin 
     self.height = _h - self.topMargin - self.bottomMargin 

     frameStd = Frame(cm, self.bottomMargin, (_w - 2*cm), (_h - 3*cm), id='cvr', showBoundary=0) 
     frameToC = Frame(self.rightMargin, self.bottomMargin, self.width, self.height, id='tocFrame', showBoundary=0) 
     frameL = Frame(self.leftMargin, self.bottomMargin, self.width, self.height, id='secLeftFrame', showBoundary=1) 
     frameR = Frame(self.leftMargin, self.bottomMargin, self.width, self.height, id='secRightFrame', showBoundary=1) 

     self.addPageTemplates([PageTemplate(id='Cover', frames=frameStd, onPage=coverPage, pagesize=self.pagesize), 
           PageTemplate(id='ToC', frames=frameToC, onPage=tocPage, pagesize=self.pagesize), 
           PageTemplate(id='blank', frames=frameStd, onPage=_doNothing, pagesize=self.pagesize), 
           LeftPageTemplate(), 
           RightPageTemplate(), 
           PageTemplate(id='secondary_left', frames=frameL, onPage=_doNothing, pagesize=self.pagesize), 
           PageTemplate(id='secondary_right', frames=frameR, onPage=_doNothing, pagesize=self.pagesize) 
           ]) 

    def afterFlowable(self, flowable): 
     """Registers ToC entries - and captures latin name for footer""" 
     if isinstance(flowable, Paragraph): 
      style = flowable.style.name 
      key = None 
      firstWord = style.split('_',1)[0] 
      if (style == 'LatinName') or (style == 'LatinNameR') or (firstWord == 'LatinName'): 
       level = 0 
       key = 'latin-%s' % self.seq.nextf('LatinName') 
       self.canv.bookmarkPage(key) 

       wholeStr = flowable.getPlainText() 
       if self.page % 2 == 0: #even numbers are on left pages 
        latinOnly = wholeStr.split('\xc2\xa0\xc2\xa0')[0] #looks for '&nbsp&nbsp' as divider 
       else: 
        latinOnly = wholeStr.split('\xc2\xa0\xc2\xa0')[1] 
       self.latinName = latinOnly 
       E = [level, latinOnly, self.page] 
       if key is not None: E.append(key) 
       self.notify('TOCEntry', tuple(E)) 
       '''elif (style == 'CommonName'): 
       self.commonName = flowable.getPlainText() 
       self.commonWidth = stringWidth(self.commonName, styles['common'].fontName, styles['common'].fontSize)''' 
      else: 
       return 


""" coverPage and otherPages are intended for non-flowing (i.e standard) parts of the pages """ 
def coverPage(canvas, doc): 
    Title = "Plants for a Future" 
    pageinfo = "The full database collected as a printable book" 
    canvas.setTitle(Title + " : " + pageinfo) 

    print "creating cover page..." 
    canvas.saveState() 
    d = Drawing(0,0) 

    r = Rect(0, 0, 12*cm, 4*cm, rx=5, ry=5) 
    r.strokeColor = colors.black 
    r.fillColor = colors.white 
    r.strokeWidth = 3 
    d.add(r) 
    d.drawOn(canvas, (_w/2.0)-6*cm, _h-(6.2*cm)) 

    canvas.setFont(stdFont, 30) 
    canvas.drawCentredString(_w/2.0, _h-108, Title) 
    canvas.setFont(stdItalic, 14) 
    canvas.drawCentredString(_w/2.0, _h-150, pageinfo) 
    canvas.restoreState() 

def tocPage(canvas, doc): 
    canvas.saveState() 
    canvas.setFont(stdFont,10) 
    canvas.drawCentredString((_w/2.0), 1.5*cm, "Table of Contents") 
    canvas.restoreState() 


def getMedicinal(plant): 
    p = plant 
    initial = p["Medicinal"] 
    return initial 


""" Run after 'Story' has been fully populated """ 
def go(): 
    doc = MyDocTemplate('result01.pdf') 
    passes = doc.multiBuild(Story) 

######################################################################## 

"""Build StyleSheet""" 
styles = buildStyle() 

h1 = PS(name = 'HeadingOne', 
     fontName = stdFont, 
     fontSize = 14, 
     leading = 16) 

h2 = PS(name = 'HeadingTwo', 
     fontName = stdFont, 
     fontSize = 12, 
     leading = 14, 
     leftIndent = 1*cm) 

Story=[] 

a = Story.append 
a(NextPageTemplate('blank')) 
a(PageBreak()) 
a(NextPageTemplate('ToC')) 
a(PageBreak()) 

toc = TableOfContents() 
toc.levelStyles = [ h1, h2 ] 
a(toc) 

a(NextPageTemplate('blank')) 
a(PageBreak()) 


"""###LEFT PAGES SHOULD BE STYLED RIGHT-ALIGNED, AND RIGHT PAGES LEFT-ALIGNED###""" 
#print type(plants) 
for i, plant in enumerate(plants): 
    ### THIS INITIAL CHECK BREAKS AS IT NEEDS TO BE BASED ON PAGE NUMBER, NOT PLANT NUMBER!!! ### 
    if i %2 == 0: #IF FIRST PLANT APPEARS ON A RIGHTSIDE PAGE, ELSE REVERSE THE R and L 
     page='R' 
     template = 'right' 
     second = 'left' 
    else: 
     page='L' 
     template ='left' 
     second = 'right' 

    #FIRST THINGS FIRST: 
    #Make sure the page templates flow nicely for each plant "chapter" 
    a(NextPageTemplate([template, '*', ('secondary_'+template), ('secondary_'+second) ])) 
    a(PageBreak()) 

    '''CAPTURE PLANT INFO IN OBJECTS''' 
    p = plant 

    '''for info in plant: 
     print info, p[info]''' 


    '''Header''' 
    latin = p["Latin Name"] 
    common = p["Common name"] 
    family = p["Family"] 
    syn = p["Synonyms"] 
    """X. congestum. (Lour.)Merrill. X. racemosum. Miq. Apactis japonica. Croton congestum. 
       Flacourtia japonica. Walp. Hisingera japonica. H. racemosa.""" 
    hardy = str(p["Hardyness"]) 

    '''Basic Info''' 
    author = p["Author"] 
    botanicalrefs = p["Botanical references"] 
    width = p["Width"] 
    height = p["Height"] 
    habit = p["Habit"] 

    planttype = clean("Deciduous/Evergreen", p) 

    plantrange = p["Range"] 
    habitat = p["Habitat"] 
    soil = clean("Soil", plant) 
    shade = p["Shade"] 
    moisture = p["Moisture"] 
    drained = p["Well-drained"] 
    nf = p["Nitrogen fixer"] 
    pH = p["pH"] 
    acid = p["Acid"] 
    alkaline = p["Alkaline"] 
    saline = p["Saline"] 
    wind = p["Wind"] 

    rate = clean("Growth rate", plant) 
    pollution = p["Pollution"] 
    poorsoil = p["Poor soil"] 
    drought = p["Drought"] 
    heavyclay = p["Heavy clay"] 
    tender = clean("FrostTender", plant) 

    inleaf = p["In leaf"] 
    flowering = p["Flowering time"] 
    seedripens = p["Seed ripens"] 
    flowertype = p["Flower Type"] 
    pollinators = p["Pollinators"] 
    selffertile = clean("Self-fertile", plant) 

    hazards = p["Known hazards"] 

    rating_edible = p["Rating"] 
    rating_med = p["Medicinal Rating"] 
    edibleuses = p["Edible uses"] 
    medicinaluses = getMedicinal(plant) 
    otheruses = p["Uses notes"] 
    #the following encoding allows for special characters such as degree symbol 
    cultivation = unicode(p["Cultivation details"], 'latin-1')#'ISO-8859-1') 
    propagation = p["Propagation 1"] 

    scented = p["Scented"] #boolean - requires further lookup in `ScentedPlants` table 

    string = '''%s is %s %s growing to %gm by %gm at a %s rate.<br/> 
       It's habitats are %s <br/><br/> Range: %s 
        <br/><br/> 
       Suitable for %s soils. <br/><br/> 
       Shade: %s, Moisture: %s <br/> 
       Well-drained: %d, Nitrogen fixer: %d <br/> ph: %s <br/> 
       Acid: %d, Alkaline: %d, Saline: %d <br/> 
       Wind: %s 
        <br/><br/> 
       Author: %s <br/> Botanical References: %s''' % (
        latin, planttype, habit.lower(), width, height, rate, 
        habitat[0].lower()+habitat[1:], plantrange, 
        soil, shade, moisture, drained, 
        nf, pH, acid, alkaline, saline, wind, author, botanicalrefs) 
    string = unicode(string, 'latin-1') 

    latinW = stringWidth(latin, styles['latin'].fontName, styles['latin'].fontSize) 
    commonW = stringWidth(common, styles['common'].fontName, styles['common'].fontSize) 

    if (latinW + commonW + (_head_pad*3)) > _head_w: 
     styleName = "LatinName_" + str(i) 
     latinStyle = PS(name=styleName, 
         parent=styles['Normal'], 
         fontName=titleFont, 
         fontSize=_latinFontS, 
         leading=22, 
         spaceAfter=0) 
     j = 1 
     #should the latin string be too long, attempt to shrink until it fits 
     while (latinW + commonW + (_head_pad*3)) > _head_w: 
      #change the font size until ok... 
      latinStyle.fontSize = _latinFontS -j 
      latinW = stringWidth(latin, latinStyle.fontName, latinStyle.fontSize) 
      j += 0.2 
    else: 
     latinStyle = styles['LatinName'] 

    if page == 'L': 
     headerText = '''<para align="left"> 
          %s 
          <font face="%s" size="%d">&nbsp;&nbsp;<super>%s</super></font> 
         </para>''' % (latin, subtitleFont, 12, common) 
    else: 
     headerText = '''<para align="right"> 
          <font face="%s" size="%d"><super>%s</super>&nbsp;&nbsp;</font> 
          %s 
         </para>''' % (subtitleFont, 12, common, latin) 
    latinPara = Paragraph(headerText, latinStyle) 

    a(FrameBreak('latin'+page)) 
    a(latinPara) 

    a(FrameBreak('syn'+page)) 
    a(KeepInFrame(_main_w, 1.5*cm, 
        [Paragraph(syn, styles['syn'+page])], 
        mode="shrink")) #can be shrink, truncate or overflow 

    a(FrameBreak('hard'+page)) 
    a(Paragraph(hardy, styles['hardy'])) 

    a(FrameBreak('cal'+page)) 
    #SHALL BE ULTIMATELY POPULATED VIA DATABASE# 
    greyOut = [ [0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,1,1,1,0] ] 

    cal = drawCalendar(greyOut) 
    a(cal) 

    a(FrameBreak('flow'+page)) 
    a(Paragraph(string, styles['Normal'])) 
    a(Paragraph("Edible Uses", styles['title'])) 
    a(Paragraph("Medicinal Uses", styles['title'])) 
    a(Paragraph("Other Uses", styles['title'])) 

    a(Paragraph("Cultivation", styles['title'])) 
    a(Paragraph(cultivation, styles['Normal'])) 

    a(Paragraph("Propagation", styles['title'])) 
    a(Paragraph(propagation, styles['Normal'])) 


##ASSEMBLE PDF### 
go() 
+0

簡而言之,您需要修改決定下一個頁面模板的函數,以根據當前頁碼執行自定義行爲,因爲它將在構建過程中調用,因此您將能夠獲得該行爲。這已經有一段時間了,所以我不記得你正在尋找的確切功能,但是如果你創建了一個自定義文檔類,那麼你可以很容易地完成它。 –

+0

謝謝你,戈登 - 我將探索更進一步 – berilac

+0

謝謝,威爾,將我的「自我回答」放入我原來的帖子 - 將來,我應該編輯這個帖子來做出這樣的修正嗎? (我之所以這麼做,是因爲它對評論顯然太長) – berilac

回答

2

如果你只是一個「左」和「右」模板之間進行切換,你可以嘗試使用BaseDocTemplate類的_handle_nextPageTemplate方法。跟蹤頁碼的一種方法是使用afterPage掛鉤來增加頁碼。

from reportlab.platypus import BaseDocTemplate 

class MyDocTemplate(BaseDocTemplate): 
    def __init__(self, *args, **kwargs): 
     BaseDocTemplate.__init__(self, *args, **kwargs) 
     self.__pageNum = 1 

    def afterPage(self): 
     """Called after all flowables have been drawn on a page""" 

     # Increment pageNum since the page has been completed 
     self.__pageNum += 1 

     # If the page number is even, force "left-side" template 
     if self.__pageNum % 2 == 0: 
      self._handle_nextPageTemplate('left_template') 
     else: 
      self._handle_nextPageTemplate('right_template') 

我沒有測試上面的代碼,但您可能需要使用beforePage而是取決於它如何檢查頁面模板順序。

+0

謝謝Gordon和Nitzle。 – berilac

+0

我已經漫步了一下,並附加了更多的代碼。然而,我現在正在考慮如果我跟蹤正在渲染的流程(並說有一個布爾值讓我知道我是否啓動一個新工廠),那麼可能最好的解決方案是使用_handle_nextPageTemplate()來追加循環:) – berilac

+0

@berilac如果您需要跟蹤正在渲染的流程,您可以使用'BaseDocTemplate'的'afterFlowable'方法,然後使用'_handle_nextPageTemplate'。 – Nitzle