def test0(self): "This makes one long multi-page paragraph." # Build story. story = [] styleSheet = getSampleStyleSheet() bt = styleSheet['BodyText'] text = '''If you imagine that the box of X's tothe left is an image, what I want to be able to do is flow a series of paragraphs around the image so that once the bottom of the image is reached, then text will flow back to the left margin. I know that it would be possible to something like this using tables, but I can't see how to have a generic solution. There are two examples of this in the demonstration section of the reportlab site. If you look at the "minimal" euro python conference brochure, at the end of the timetable section (page 8), there are adverts for "AdSu" and "O'Reilly". I can see how the AdSu one might be done generically, but the O'Reilly, unsure... I guess I'm hoping that I've missed something, and that it's actually easy to do using platypus. ''' from reportlab.platypus.flowables import ParagraphAndImage, Image from reportlab.lib.testutils import testsFolder gif = os.path.join(testsFolder,'pythonpowered.gif') story.append(ParagraphAndImage(Paragraph(text,bt),Image(gif))) phrase = 'This should be a paragraph spanning at least three pages. ' description = ''.join([('%d: '%i)+phrase for i in xrange(250)]) story.append(ParagraphAndImage(Paragraph(description, bt),Image(gif),side='left')) doc = MyDocTemplate(outputfile('test_platypus_paragraphandimage.pdf')) doc.multiBuild(story)
def wrap(self, availWidth, availHeight): # print "# wrap", id(self), self.canv # availHeight = self.setMaxHeight(availHeight) self.I.canv = self.canv result = ParagraphAndImage.wrap(self, availWidth, availHeight) del self.I.canv return result
def myFirstPage(canvas, doc): canvas.saveState() canvas.setFont('Times-Bold', 16) canvas.drawCentredString(PAGE_WIDTH / 2.0, PAGE_HEIGHT - 108, title) canvas.setFont('Times-Roman', 9) canvas.drawString(inch, 0.75 * inch, "Page %d - %s" % (doc.page, title)) frame_width = PAGE_WIDTH - 200 hr = HRFlowable() space = Spacer(frame_width, 20) style = styles["Normal"] qr_info = """<para rightIndent=10 leftIndent=20 alignment=right>This document is signed with the QR code shown on the right. Validate it using a Barcode Scanner.""" par = Paragraph(qr_info, style) im = Image("qrcode.png", 101, 101) pandi = ParagraphAndImage(par, im, xpad=3, ypad=30, side='right') frame = Frame(100, 0, frame_width, 200, showBoundary=1) frame.add(hr, canvas) frame.add(space, canvas) frame.add(pandi, canvas) canvas.restoreState()
def Imprimer(self, event=None): listeDates = self.dictImpression["dates"] if len(listeDates) > 26 : dlg = wx.MessageDialog(self, _(u"Désolé mais vous ne pouvez pas imprimer plus de 26 jours sur une feuille !"), _(u"Information"), wx.OK | wx.ICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy() return False # Création du PDF from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak from reportlab.platypus.flowables import ParagraphAndImage, Image from reportlab.rl_config import defaultPageSize from reportlab.lib.units import inch, cm from reportlab.lib.utils import ImageReader from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle self.hauteur_page = defaultPageSize[1] self.largeur_page = defaultPageSize[0] # Recherche le format de la page à appliquer largeurPremiereColonne = 140 largeurColonnesDates = 24 largeurMax = largeurPremiereColonne + (largeurColonnesDates*len(listeDates)) if largeurMax <= 520 : # Format Portrait largeurPage, hauteurPage = defaultPageSize largeurContenu = 520 else : # Format Paysage hauteurPage, largeurPage = defaultPageSize largeurContenu = 770 # Initialisation du PDF nomDoc = FonctionsPerso.GenerationNomDoc("LISTE_TRANSPORTS", "pdf") if sys.platform.startswith("win") : nomDoc = nomDoc.replace("/", "\\") doc = SimpleDocTemplate(nomDoc, pagesize=(largeurPage, hauteurPage), topMargin=30, bottomMargin=30) story = [] # Création du titre du document def Header(): dataTableau = [] largeursColonnes = ( (largeurContenu-100, 100) ) dateDuJour = DateEngFr(str(datetime.date.today())) dataTableau.append( (_(u"Liste des transports"), _(u"%s\nEdité le %s") % (UTILS_Organisateur.GetNom(), dateDuJour)) ) style = TableStyle([ ('BOX', (0,0), (-1,-1), 0.25, colors.black), ('VALIGN', (0,0), (-1,-1), 'TOP'), ('ALIGN', (0,0), (0,0), 'LEFT'), ('FONT',(0,0),(0,0), "Helvetica-Bold", 16), ('ALIGN', (1,0), (1,0), 'RIGHT'), ('FONT',(1,0),(1,0), "Helvetica", 6), ]) tableau = Table(dataTableau, largeursColonnes) tableau.setStyle(style) story.append(tableau) story.append(Spacer(0,20)) # Insère un header Header() # Contenu for dictCategorie in self.dictImpression["donnees"] : label = dictCategorie["texte"] img = dictCategorie["img"] elements = dictCategorie["elements"] dataTableau = [] largeursColonnes = [largeurPremiereColonne,] # Création de la ligne de date paraStyle = ParagraphStyle(name="categorie", fontName="Helvetica-Bold", fontSize=9, leading=8, spaceAfter=2,) ligne = [ParagraphAndImage(Paragraph(label, paraStyle), Image(Chemins.GetStaticPath("Images/32x32/%s.png" % img), width=8, height=8), xpad=1, ypad=0, side="left"),] for date in listeDates : ligne.append(u"%02d/%02d\n%04d" % (date.day, date.month, date.year)) largeursColonnes.append(largeurColonnesDates) dataTableau.append(ligne) # Création des lignes listeExtraStyles = [] index = 1 for element in elements : # Décoration de la ligne if element["type"] in ("lieux", "lignes", "localisations") : listeExtraStyles.append(('BACKGROUND', (0, index), (-1, index), (0.8, 0.8, 1) )) if element["type"] == "arrets" : listeExtraStyles.append(('BACKGROUND', (0, index), (-1, index), (0.9, 0.9, 1) )) if element["type"] == "heures" : listeExtraStyles.append(('FONT',(0, index), (0, index), "Helvetica-Bold", 6),) listeExtraStyles.append(('FONT',(1, index), (-1, index), "Helvetica", 5),) listeExtraStyles.append(('TEXTCOLOR',(1, index), (-1, index), (0.6, 0.6, 0.6)),) if element["type"] == "individus" : listeExtraStyles.append(('ALIGN', (0, index), (0, index), 'RIGHT')) listeExtraStyles.append(('GRID', (1, index), (-1, index), 0.25, colors.black)) listeExtraStyles.append(('FONT',(1, index), (-1, index), "Helvetica", 6),) # Ajout d'une marge label = element["texte"] if "marge" in element : label = u"%s%s" % ((element["marge"]-1) * " ", label) ligne = [label,] # Ajout des colonnes for indexColonne in range(1, len(largeursColonnes)) : label = u"" if "colonnes" in element: if indexColonne in element["colonnes"] : label = element["colonnes"][indexColonne] ligne.append(label) dataTableau.append(ligne) index += 1 # Style du tableau listeStyles = [ ('VALIGN', (0, 0), (-1,-1), 'MIDDLE'), ('ALIGN', (1, 0), (-1, -1), 'CENTRE'), ('FONT',(0, 0), (-1,-1), "Helvetica", 7), ('FONT',(0, 0), (0, 0), "Helvetica-Bold", 8), ('BOX', (0, 1), (-1, -1), 0.25, colors.black), ('GRID', (1, 0), (-1, 0), 0.25, colors.black), ] for extraStyle in listeExtraStyles : listeStyles.append(extraStyle) # Création du tableau tableau = Table(dataTableau, largeursColonnes) tableau.setStyle(TableStyle(listeStyles)) story.append(tableau) story.append(Spacer(0, 15)) ## # TOTAUX ## dataTableau = [] ## largeursColonnes = [220, 220, 40, 40] ## ## for ligne in self.listeImpression["totaux"] : ## dataTableau.append(ligne) ## ## couleurFond = (0.8, 0.8, 0.8) ## listeStyles = [ ## ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), # Centre verticalement toutes les cases ## ('FONT',(0,0),(-1,-1), "Helvetica", 7), # Donne la police de caract. + taille de police ## ('BOX', (0, 1), (-1,-1), 0.25, colors.black), # Crée la bordure noire pour tout le tableau ## ('ALIGN', (2, 0), (-1, -1), 'CENTRE'), # Ligne de labels colonne alignée au centre ## ('BOX', (0, 0), (-1,0), 0.25, colors.black), # Crée la bordure noire du nom de famille ## ('FONT',(0,0),(0,0), "Helvetica-Bold", 8), # Donne la police de caract. + taille de police du titre de groupe ## ('BACKGROUND', (0,0), (-1,0), couleurFond), # Donne la couleur de fond du titre de groupe ## ('TOPPADDING',(0,0),(-1,-1), 1), ## ('BOTTOMPADDING',(0,0),(-1,-1), 1), ## ] ## ## # Création du tableau ## tableau = Table(dataTableau, largeursColonnes) ## tableau.setStyle(TableStyle(listeStyles)) ## story.append(tableau) # Enregistrement du PDF doc.build(story) # Affichage du PDF FonctionsPerso.LanceFichierExterne(nomDoc)
def split(self, availWidth, availHeight): # print "# split", id(self) if not hasattr(self, "wI"): self.wI, self.hI = self.I.wrap(availWidth, availHeight) # drawWidth, self.I.drawHeight return ParagraphAndImage.split(self, availWidth, availHeight)
def wrap(self, availWidth, availHeight): self.I.canv = self.canv result = ParagraphAndImage.wrap(self, availWidth, availHeight) del self.I.canv return result
def OnBoutonOk(self, event): # Récupération et vérification des données listePeriodes = self.ctrl_calendrier.GetDatesSelections() listeActivites = self.ctrl_activites.GetListeActivites() if len(listeActivites) == 0: dlg = wx.MessageDialog( self, _(u"Vous devez obligatoirement cocher au moins une activité !" ), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy() return False listeGroupes = self.ctrl_groupes.GetListeGroupes() if len(listeGroupes) == 0: dlg = wx.MessageDialog( self, _(u"Vous devez obligatoirement cocher au moins un groupe !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy() return False # Création du PDF from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak from reportlab.platypus.flowables import ParagraphAndImage, Image from reportlab.rl_config import defaultPageSize from reportlab.lib.pagesizes import A4 from reportlab.lib.units import inch, cm from reportlab.lib.utils import ImageReader from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle self.taille_page = A4 self.orientation = "PAYSAGE" if self.orientation == "PORTRAIT": self.hauteur_page = self.taille_page[1] self.largeur_page = self.taille_page[0] else: self.hauteur_page = self.taille_page[0] self.largeur_page = self.taille_page[1] # Création des conditions pour les requêtes SQL conditionsPeriodes = GetSQLdates(listePeriodes) if len(listeActivites) == 0: conditionActivites = "()" elif len(listeActivites) == 1: conditionActivites = "(%d)" % listeActivites[0] else: conditionActivites = str(tuple(listeActivites)) if len(listeGroupes) == 0: conditionGroupes = "()" elif len(listeGroupes) == 1: conditionGroupes = "(%d)" % listeGroupes[0] else: conditionGroupes = str(tuple(listeGroupes)) # Récupération des noms des groupes dictGroupes = self.ctrl_groupes.GetDictGroupes() # Récupération des noms d'activités dictActivites = self.ctrl_activites.GetDictActivites() # Récupération de la liste des groupes ouverts sur cette période DB = GestionDB.DB() req = """SELECT IDouverture, IDactivite, IDunite, IDgroupe FROM ouvertures WHERE ouvertures.IDactivite IN %s AND %s AND IDgroupe IN %s ; """ % (conditionActivites, conditionsPeriodes, conditionGroupes) DB.ExecuterReq(req) listeOuvertures = DB.ResultatReq() dictOuvertures = {} for IDouverture, IDactivite, IDunite, IDgroupe in listeOuvertures: if dictOuvertures.has_key(IDactivite) == False: dictOuvertures[IDactivite] = [] if IDgroupe not in dictOuvertures[IDactivite]: dictOuvertures[IDactivite].append(IDgroupe) # Récupération des individus grâce à leurs consommations DB = GestionDB.DB() req = """SELECT individus.IDindividu, IDactivite, IDgroupe, etat, IDcivilite, nom, prenom, date_naiss FROM consommations LEFT JOIN individus ON individus.IDindividu = consommations.IDindividu WHERE etat IN ("reservation", "present") AND IDactivite IN %s AND %s GROUP BY individus.IDindividu ORDER BY nom, prenom ;""" % (conditionActivites, conditionsPeriodes) DB.ExecuterReq(req) listeIndividus = DB.ResultatReq() dictIndividus = {} listeIDindividus = [] for IDindividu, IDactivite, IDgroupe, etat, IDcivilite, nom, prenom, date_naiss in listeIndividus: if date_naiss != None: date_naiss = DateEngEnDateDD(date_naiss) age = self.GetAge(date_naiss) # Mémorisation de l'individu dictIndividus[IDindividu] = { "IDcivilite": IDcivilite, "nom": nom, "prenom": prenom, "age": age, "date_naiss": date_naiss, "IDgroupe": IDgroupe, "IDactivite": IDactivite, } # Mémorisation du IDindividu if IDindividu not in listeIDindividus: listeIDindividus.append(IDindividu) # Dict Informations médicales req = """SELECT IDprobleme, IDindividu, IDtype, intitule, date_debut, date_fin, description, traitement_medical, description_traitement, date_debut_traitement, date_fin_traitement, eviction, date_debut_eviction, date_fin_eviction FROM problemes_sante WHERE diffusion_listing_enfants=1 ;""" DB.ExecuterReq(req) listeInformations = DB.ResultatReq() DB.Close() dictInfosMedicales = {} for IDprobleme, IDindividu, IDtype, intitule, date_debut, date_fin, description, traitement_medical, description_traitement, date_debut_traitement, date_fin_traitement, eviction, date_debut_eviction, date_fin_eviction in listeInformations: if dictInfosMedicales.has_key(IDindividu) == False: dictInfosMedicales[IDindividu] = [] dictTemp = { "IDprobleme": IDprobleme, "IDtype": IDtype, "intitule": intitule, "date_debut": date_debut, "date_fin": date_fin, "description": description, "traitement_medical": traitement_medical, "description_traitement": description_traitement, "date_debut_traitement": date_debut_traitement, "date_fin_traitement": date_fin_traitement, "eviction": eviction, "date_debut_eviction": date_debut_eviction, "date_fin_eviction": date_fin_eviction, } dictInfosMedicales[IDindividu].append(dictTemp) # Récupération des photos individuelles dictPhotos = {} taillePhoto = 128 if self.ctrl_taille_photos.GetSelection() == 0: tailleImageFinal = 16 if self.ctrl_taille_photos.GetSelection() == 1: tailleImageFinal = 32 if self.ctrl_taille_photos.GetSelection() == 2: tailleImageFinal = 64 if self.checkbox_photos.GetValue() == True: for IDindividu in listeIDindividus: IDcivilite = dictIndividus[IDindividu]["IDcivilite"] nomFichier = Chemins.GetStaticPath( "Images/128x128/%s" % DICT_CIVILITES[IDcivilite]["nomImage"]) IDphoto, bmp = CTRL_Photo.GetPhoto(IDindividu=IDindividu, nomFichier=nomFichier, taillePhoto=(taillePhoto, taillePhoto), qualite=100) # Création de la photo dans le répertoire Temp nomFichier = UTILS_Fichiers.GetRepTemp( fichier="photoTmp%d.jpg" % IDindividu) bmp.SaveFile(nomFichier, type=wx.BITMAP_TYPE_JPEG) img = Image(nomFichier, width=tailleImageFinal, height=tailleImageFinal) dictPhotos[IDindividu] = img # ---------------- Création du PDF ------------------- # Initialisation du PDF nomDoc = FonctionsPerso.GenerationNomDoc( "LISTE_INFORMATIONS_MEDICALES", "pdf") if sys.platform.startswith("win"): nomDoc = nomDoc.replace("/", "\\") doc = SimpleDocTemplate(nomDoc, pagesize=(self.largeur_page, self.hauteur_page), topMargin=30, bottomMargin=30) story = [] largeurContenu = self.largeur_page - 75 #520 # Création du titre du document def Header(): dataTableau = [] largeursColonnes = ((largeurContenu - 100, 100)) dateDuJour = DateEngFr(str(datetime.date.today())) dataTableau.append( (_(u"Informations médicales"), _(u"%s\nEdité le %s") % (UTILS_Organisateur.GetNom(), dateDuJour))) style = TableStyle([ ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'TOP'), ('ALIGN', (0, 0), (0, 0), 'LEFT'), ('FONT', (0, 0), (0, 0), "Helvetica-Bold", 16), ('ALIGN', (1, 0), (1, 0), 'RIGHT'), ('FONT', (1, 0), (1, 0), "Helvetica", 6), ]) tableau = Table(dataTableau, largeursColonnes) tableau.setStyle(style) story.append(tableau) story.append(Spacer(0, 20)) # Insère un header Header() # Activités for IDactivite in listeActivites: nomActivite = dictActivites[IDactivite]["nom"] # Groupes if dictOuvertures.has_key(IDactivite): nbreGroupes = len(dictOuvertures[IDactivite]) indexGroupe = 1 for IDgroupe in dictOuvertures[IDactivite]: nomGroupe = dictGroupes[IDgroupe]["nom"] # Initialisation du tableau dataTableau = [] largeursColonnes = [] labelsColonnes = [] # Recherche des entêtes de colonnes : if self.checkbox_photos.GetValue() == True: labelsColonnes.append(_(u"Photo")) largeursColonnes.append(tailleImageFinal + 6) labelsColonnes.append(_(u"Nom - prénom")) largeursColonnes.append(120) if self.checkbox_age.GetValue() == True: labelsColonnes.append(_(u"Âge")) largeursColonnes.append(20) # Calcule la largeur restante largeurRestante = largeurContenu - sum(largeursColonnes) labelsColonnes.append(_(u"Informations alimentaires")) largeursColonnes.append(largeurRestante / 2.0) labelsColonnes.append(_(u"Informations diverses")) largeursColonnes.append(largeurRestante / 2.0) # Création de l'entete de groupe ligne = [ nomGroupe, ] for x in range(0, len(labelsColonnes) - 1): ligne.append("") dataTableau.append(ligne) # Création des entêtes ligne = [] for label in labelsColonnes: ligne.append(label) dataTableau.append(ligne) # --------- Création des lignes ----------- # Création d'une liste temporaire pour le tri listeIndividus = [] if dictOuvertures.has_key(IDactivite): if IDgroupe in dictOuvertures[IDactivite]: for IDindividu in listeIDindividus: dictIndividu = dictIndividus[IDindividu] if dictIndividu["IDgroupe"] == IDgroupe: valeursTri = (IDindividu, dictIndividu["nom"], dictIndividu["prenom"], dictIndividu["age"]) # + Sélection uniquement des individus avec infos if self.checkbox_nonvides.GetValue( ) == False or ( self.checkbox_nonvides.GetValue() == True and dictInfosMedicales. has_key(IDindividu)): listeIndividus.append(valeursTri) if self.ctrl_tri.GetSelection() == 0: paramTri = 1 # Nom if self.ctrl_tri.GetSelection() == 1: paramTri = 2 # Prénom if self.ctrl_tri.GetSelection() == 2: paramTri = 3 # Age if self.ctrl_ordre.GetSelection() == 0: ordreDecroissant = False else: ordreDecroissant = True listeIndividus = sorted(listeIndividus, key=operator.itemgetter(paramTri), reverse=ordreDecroissant) # Récupération des lignes individus for IDindividu, nom, prenom, age in listeIndividus: dictIndividu = dictIndividus[IDindividu] ligne = [] # Photo if self.checkbox_photos.GetValue( ) == True and IDindividu in dictPhotos: img = dictPhotos[IDindividu] ligne.append(img) # Nom ligne.append(u"%s %s" % (nom, prenom)) # Age if self.checkbox_age.GetValue() == True: if age != None: ligne.append(age) else: ligne.append("") # Informations médicales paraStyle = ParagraphStyle( name="infos", fontName="Helvetica", fontSize=7, leading=8, spaceAfter=2, ) listeInfosAlim = [] listeInfosDivers = [] if dictInfosMedicales.has_key(IDindividu): for infoMedicale in dictInfosMedicales[IDindividu]: intitule = infoMedicale["intitule"] description = infoMedicale["description"] traitement = infoMedicale["traitement_medical"] description_traitement = infoMedicale[ "description_traitement"] date_debut_traitement = infoMedicale[ "date_debut_traitement"] date_fin_traitement = infoMedicale[ "date_fin_traitement"] IDtype = infoMedicale["IDtype"] # Intitulé et description if description != None and description != "": texteInfos = u"<b>%s</b> : %s" % ( intitule, description) else: texteInfos = u"%s" % intitule if len(texteInfos ) > 0 and texteInfos[-1] != ".": texteInfos += u"." # Traitement médical if traitement == 1 and description_traitement != None and description_traitement != "": texteDatesTraitement = u"" if date_debut_traitement != None and date_fin_traitement != None: texteDatesTraitement = _( u" du %s au %s" ) % (DateEngFr(date_debut_traitement), DateEngFr(date_fin_traitement)) if date_debut_traitement != None and date_fin_traitement == None: texteDatesTraitement = _( u" à partir du %s") % DateEngFr( date_debut_traitement) if date_debut_traitement == None and date_fin_traitement != None: texteDatesTraitement = _( u" jusqu'au %s") % DateEngFr( date_fin_traitement) texteInfos += _(u"Traitement%s : %s.") % ( texteDatesTraitement, description_traitement) # Création du paragraphe img = DICT_TYPES_INFOS[IDtype]["img"] p = ParagraphAndImage( Paragraph(texteInfos, paraStyle), Image(Chemins.GetStaticPath( "Images/16x16/%s" % img), width=8, height=8), xpad=1, ypad=0, side="left") if infoMedicale["IDtype"] == 2: listeInfosAlim.append(p) else: listeInfosDivers.append(p) ligne.append(listeInfosAlim) ligne.append(listeInfosDivers) # Ajout de la ligne individuelle dans le tableau dataTableau.append(ligne) # Création des lignes vierges if self.checkbox_lignes_vierges.GetValue() == True: for x in range( 0, self.ctrl_nbre_lignes.GetSelection() + 1): ligne = [] for col in labelsColonnes: ligne.append("") dataTableau.append(ligne) # Style du tableau colPremiere = 1 if self.checkbox_photos.GetValue() == True: colPremiere += 1 if self.checkbox_age.GetValue() == True: colPremiere += 1 couleurFond = (0.8, 0.8, 1) # Vert -> (0.5, 1, 0.2) style = TableStyle([ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), # Centre verticalement toutes les cases ('FONT', (0, 0), (-1, -1), "Helvetica", 7), # Donne la police de caract. + taille de police ('GRID', (0, 0), (-1, -1), 0.25, colors.black ), # Crée la bordure noire pour tout le tableau ('ALIGN', (0, 1), (-2, -1), 'CENTRE'), # Centre les cases ('ALIGN', (0, 1), (-1, 1), 'CENTRE' ), # Ligne de labels colonne alignée au centre ( 'FONT', (0, 1), (-1, 1), "Helvetica", 6 ), # Donne la police de caract. + taille de police des labels ( 'SPAN', (0, 0), (-1, 0) ), # Fusionne les lignes du haut pour faire le titre du groupe ( 'FONT', (0, 0), (0, 0), "Helvetica-Bold", 10 ), # Donne la police de caract. + taille de police du titre de groupe ('BACKGROUND', (0, 0), (-1, 0), couleurFond ), # Donne la couleur de fond du titre de groupe ]) # Création du tableau tableau = Table(dataTableau, largeursColonnes) tableau.setStyle(style) story.append(tableau) story.append(Spacer(0, 20)) # Saut de page après un groupe if self.checkbox_page_groupe.GetValue() == True: story.append(PageBreak()) # Insère un header if indexGroupe < nbreGroupes: Header() indexGroupe += 1 # Enregistrement du PDF doc.build(story) # Affichage du PDF FonctionsPerso.LanceFichierExterne(nomDoc) self.MemoriserParametres()