VBA rapport openen, printen en opslaan als PDF

Status
Niet open voor verdere reacties.

Bospeen

Gebruiker
Lid geworden
23 aug 2005
Berichten
150
Beste forumleden,

Graag hulp bij de volgende VBA code die een specifiek rapport (brief) opent, print en opslaat als PDF op een netwerklocatie.
De bijgevoegde code werkt op zich wel, maar is abnormaal traag: printen en opslaan van één brief + bijlage kan soms wel 10 minuten duren! (en dit is geen netwerkprobleem)
Het lijkt me dat deze code aangepast kan worden ten gunste van de snelheid, maar hoe... graag hulp hierbij!

Met vriendelijke groet,
Bospeen

Code:
Private Sub Knop1_Click()

On Error GoTo Err_Click

Const OverwriteExisting = True
Dim objFSO
Set objFSO = CreateObject("Scripting.Filesystemobject")

'--------------------------------------maakt een lege map op C voor tijdelijke opslag van brieven, dit werkt sneller dan direct opslaan op het tragere netwerk

If objFSO.FolderExists("c:\Temp\brieven") Then
objFSO.DeleteFolder "c:\Temp\brieven", True
objFSO.CreateFolder "c:\Temp\brieven"
Else
    objFSO.CreateFolder ("c:\Temp\brieven")
End If


'--------------------------------------voorwaarden voor het mogen printen en opslaan van de brieven

    If Me.BRIEF = False Then
    MsgBox "De aktie kan niet worden voltooid (brief is niet aangevinkt)."
    Exit Sub
    End If
    
    If IsNull(Me.DATUM_BRIEF) Then
    MsgBox "De aktie kan niet worden voltooid (datum brief is niet gevuld)."
    Exit Sub
    End If
    
    Else:
    GoTo Printbrief:
    End If


Printbrief:
    
    If MsgBox("Kies in het printer-dialoogvenster hierna de juiste papierlade. Wacht daarna tot de melding dat printen en opslaan is voltooid.", vbOKCancel, "Brief printen en opslaan") = vbCancel Then
    Exit Sub
    End If

'--------------------------------------voorwaarde, printen, opslaan en melding brief_1
 
    If Me.BEDRAG > 10000 Then
    stlinkcriteria = "[zoekveld] = '" & Me![zoekveld] & "'"
    
    DoCmd.OpenReport "brief_1", acViewReport, , stlinkcriteria
    DoCmd.RunCommand acCmdPrint
    DoCmd.OutputTo acOutputReport, "BRIEF_1", acFormatPDF, "C:\TEMP\brieven\" & Me.NAAM & "_brief_1.PDF", False
    DoCmd.Close acReport, "brief_1", acSaveNo
    
    MsgBox "Brief_1 is geprint en opgeslagen."
    End If

'--------------------------------------voorwaarde, printen, opslaan en melding brief_2 en bijlage
   
    If Me.BEDRAG > 5000 Then
    stlinkcriteria = "[zoekveld] = '" & Me![zoekveld] & "'"
    
    DoCmd.OpenReport "brief_2", acViewReport, , stlinkcriteria
    DoCmd.RunCommand acCmdPrint
    DoCmd.OutputTo acOutputReport, "brief_2", acFormatPDF, "C:\TEMP\brieven\" & Me.NAAM & "_brief_2.PDF", False
    DoCmd.Close acReport, "brief_2", acSaveNo
    
    DoCmd.OpenReport "brief_2_bijlage", acViewReport, , stlinkcriteria
    DoCmd.RunCommand acCmdPrint
    DoCmd.OutputTo acOutputReport, "brief_2_bijlage", acFormatPDF, "C:\TEMP\brieven\" & Me.NAAM & "_brief_2_bijlage.PDF", False
    DoCmd.Close acReport, "brief_2_bijlage", acSaveNo

    MsgBox "Brief_2 en bijlage is geprint en opgeslagen."
    End If

'--------------------------------------definitief opslaan van de aangemaakte brieven in de archiefmap op het netwerk

objFSO.CopyFolder "c:\temp\brieven", "Q:\SERVERNAAM\ARCHIEF\BRIEVEN\" & Me.NAAM, OverwriteExisting
objFSO.DeleteFolder "c:\Temp\brieven", True
objFSO.CreateFolder "c:\Temp\brieven"

Me.Refresh

Exit Sub

Err_Click:
    MsgBox "DE PRINT EN SAVE AKTIE IS AFGEBROKEN!"

End Sub
 
Ik zie in je procedure dat je oa; een aantal keren (dezelfde) temp folder maakt en terug verwijderd via scripting techniek of zo, terwijl dat allemaal niet nodig is.
Verder kan je het bestaan van een directory ook zo checken en als ie niet bestaat direct aanmaken:
Code:
Dim dirname As String

dirname = "c:\Temp\brieven"
'
If Dir(dirname, vbDirectory) = "" Then MkDir dirname

Tevens staat onze DB al op de server zelf ipv lokaal en hoe meer plaatjes of andere verzwarende zaken in je document zitten hoe meer MB er over het netwerk zullen moeten gaan.
Ik doe iets gelijkaardigs als jij voor ons personeelsdossier maar daar maak ik in een aparte map op de server automatisch per naam en voornaam een aparte submap voor ieder personeelslid zodat iedere PDF betreffende die persoon daar in terecht komt samen met in de naam van die PDF bv de contract begin en einddatum zodat je een beetje historiek hebt.
Als je wilt post ik die code 's integraal.
 
De werkwijze is an sich al traag omdat je elk rapport, opent, afdrukt en sluit. Dat kan per rapport met één opdracht waarbij het rapport gelijk geëxporteerd wordt. Een rapport opbouwen voor schermweergave kost nu eenmaal tijd.
Verder ben ik het met Johan eens dat je de tijdelijke map maar één keer aan moet maken, en dan kan laten staan.
 
Bedankt voor jullie reactie!

Ik zie inderdaad dat het niet nodig is om aan het eind van het script nog eens de map te deleten en aan te maken.
Nu denk ik dat hiermee niet zoveel tijd gemoeid gaat, want bij het printen van de eenvoudige brief_1 verschijnt de melding dat deze is geprint en opgeslagen nog redelijk snel.

Bij brief_2 en de bijlage is dit anders, dan lijkt 't script minutenlang te 'hangen' (geen idee wat er dan op de achtergrond gebeurt)
Daarom denk ik dat de suggestie van OctaFish om de code te vereenvoudigen de meeste winst behaalt, ik weet alleen niet hoe ik dan de code moet aanpassen,
ik heb al van alles geprobeerd (bijv. acViewReport vervangen door acNormal), maar ik kom er niet uit... hoe print en exporteer/save ik het rapport in één opdracht???

En zou het misschien verschil maken als ik na if en then ook een else ga gebruiken?

NB. de backend van mijn DB staat op een SQL server, de frontend op het netwerk en het digitale brievenarchief ook op dit netwerk. De mappen worden daar al automatisch aangemaakt. Wat dat betreft lijkt onze werkwijze wel veel hetzelfde, JohanRVT. Ik had de code voor posten iets uitgekleed.
 
En zou het misschien verschil maken als ik na if en then ook een else ga gebruiken?
Dat heeft alleen zin als de sturing dat vraagt. Dus als je twee kanten (of meer) op wilt gaan met je code. Qua snelheid win je er niks mee.
Wat wél helpt: een voorbeeldje meeposten met de rapporten. Uiteraard met wat dummy data, want het gaat ons alleen om de werking. Ik kan de netwerk werking uiteraard alleen op het werk testen, ik heb thuis geen netwerk dat daarvoor geschikt is. Maar ik kan wel kijken of er snelheid te halen is of niet.
 
Door beveiligingsissues kan ik niets van ons netwerk halen, om een voorbeeld mee te posten moet ik dus een nieuwe (dummy) DB aanmaken. Ik had gehoopt dat je iemand het volgende stukje code zonder voorbeeld wist te vereenvoudigen

Code:
DoCmd.OpenReport "brief_2", acViewReport, , stlinkcriteria
    DoCmd.RunCommand acCmdPrint
    DoCmd.OutputTo acOutputReport, "brief_2", acFormatPDF, "C:\TEMP\brieven\" & Me.NAAM & "_brief_2.PDF", False
    DoCmd.Close acReport, "brief_2", acSaveNo

Ik hoop dat dit iemand lukt.
 
Omdat we je db niet hebben is het lastig om precies te zien hoe de rapporten zijn opgemaakt, maar ik zou het in deze situatie zo doen.
Code:
Sub cmdPrinten()
Dim qDef As QueryDef
Dim strSQL As String, Brief As String
Dim i As Integer
    
    If Me.BEDRAG > 10000 Then
        For i = 1 To 3
            Brief = "Brief_" & i
            strSQL = "SELECT * FROM q" & Brief & " WHERE [zoekveld] = """ & Me.zoekveld & """"
            Set qDef = CurrentDb.QueryDefs("qTemp")
            qDef.SQL = strSQL
            With DoCmd
                .OpenReport Brief, acViewNormal
                .OutputTo acOutputReport, Brief, acFormatPDF, _
                    "Q:\SERVERNAAM\ARCHIEF\BRIEVEN\" & Me.Naam & "_" & Brief & ".pfd", False
            End With
        Next i
    End If

End Sub
Hierbij zitten uiteraard wel een paar aannames.
1a. De drie brieven hebben dezelfde bron (query): geen probleem.
1b. De drie brieven hebben verschillende bronnen (queries): Zorg ervoor dat je drie queries hebt die de volledige ongefilterde recordset hebben die je nodig hebt. Noem deze queries qBrief_1, qBrief_2 en qBrief_3.
2. Hang elk rapport aan een query met de naam "qTemp"
3. Gebruik de rapporten alleen vanuit knoppen en code, omdat je de qTemp waarschijnlijk steeds moet aanpassen volgens bovenstaand voorbeeld.

De werking is eigenlijk heel simpel: in een lus (i = 1 to 3) wordt steeds een andere query ingelezen met een ander filter en in een stringvariabele gezet. Vervolgens wordt de query qTemp voorzien van deze query. Omdat het rapport op qTemp staat ingesteld, krijg je dus altijd de juiste filtering op het rapport. Je hoeft het rapport nu dus niet meer te openen, maar kunt het gelijk exporteren. Je wilt het zo te zien ook nog printen, dus die code heb ik er ook bij laten staan.
Er lijkt mij geen noodzaak om de pdf-jes in een tijdelijke map op te slaan; je kunt ze gelijk op de goede map op de Q-schijf wegzetten. Tenzij dat echt niet gaat, dan misschien toch maar eerst lokaal.
Maar sneller (en in ieder geval een stuk korter) als dit zal lastig worden.
 
Je zegt hierboven dat je DB op de server zelf staat; ik nam aan dat die lokaal stond. Waarom dus een temp map lokaal maken? Maak die op de server zelf; je zult toch wel ergens een gedeelde map hebben?
En verder schrijf je de brief en de bijlage. Welke bijlage zit er dan wel nog bij die brief? En dat moet allemaal over het netwerk (internet dus) weg en weer gesluisd worden.
 
Je zegt hierboven dat je DB op de server zelf staat; ik nam aan dat die lokaal stond. Waarom dus een temp map lokaal maken? Maak die op de server zelf; je zult toch wel ergens een gedeelde map hebben?
En verder schrijf je de brief en de bijlage. Welke bijlage zit er dan wel nog bij die brief? En dat moet allemaal over het netwerk (internet dus) weg en weer gesluisd worden.

Testwerk heeft uitgewezen dat het direct exporteren naar de definitieve netwerklocatie veel langer duurt dan exporteren naar C en daarna kopiëren naar het netwerk. Maar wellicht is dit niet meer nodig als de opdrachtregels gecombineerd worden (Octa's voorstel)
De bijlage is niet meer dan een apart rapport. Als aan bepaalde voorwaarden is voldaan, moeten er dus 2 verschillende rapporten geprint en opgeslagen worden.
 
2 aparte rapporten in PDF opslaan is een heel ander gegeven dan zoals U zei een brief openen, printen en een bijlage opslaan.
En Michel zal wel een typo gemaakt hebben als hij Pfd gebruikte ipv pdf.
Wat netwerk beveiliging issues betreft kan je bij ons ook niets rechtstreeks naar je lokale harddisk downen/uppen maar je kan het wel naar een USB stick doen en dan lokaal van de USB stick naar je HDD. je moet het maar uitgelegd krijgen als IT dat dat veiliger is :)
 
En Michel zal wel een typo gemaakt hebben als hij Pfd gebruikte ipv pdf.
Scherp :). Wij gebruiken op het werk een virtuele omgeving, en dat is nog rotter, want dan doe je dus helemaal niks meer op de C-schijf. Wat extra vervelend is, is dat de tijdelijke mappen ook virtueel zijn met steeds andere namen. Wij kunnen dus voor onze sjablonen ook nergens terecht, met als gevolg dat ik elke dag een 'schone' normal.dot krijg en ik weer opnieuw alle macro's kan importeren. Kortom: 'netwerken' is wat anders als 'net werken' :D
 
Excuus, ik heb het steeds over brieven maar ik bedoel rapporten (die in de vorm van brieven zijn opgesteld).
Het zit eigenlijk zo: gebruikers werken een 'behandelscherm' af (=formulier o.b.v. een tabel) en moeten hierbij een brief printen en opslaan, met een klik op een knop.
Welk rapport (brief) hiervoor geselecteerd moet worden hangt af van de invulling van het behandelscherm.
Het rapport hoeft in principe niet aan de gebruiker getoond te worden, wel moet het printer-dialoogvenster getoond worden omdat gebruikers een andere papierlade moeten kunnen kiezen.

Jouw code, Octa, bevat geen printopdracht. En ik heb zoiets al geprobeerd, het geeft geen verbetering qua performance.

Omdat meerdere gebruikers posten in hetzelfde behandelscherm afwerken, worden de queries t.b.v. de rapporten bij dit multi-user gebruik telkens afgevuurd op een door anderen geopende tabel... kan dit gegeven de grote boosdoener zijn?

Ps. ons netwerk is (voor mij) dusdanig streng afgeschermd, dat ik echt geen enkele informatie naar buiten kan brengen (ook geen stick of externe email), alleen een foto van het scherm.
 
Excuus, ik heb het steeds over brieven maar ik bedoel rapporten (die in de vorm van brieven zijn opgesteld).
"A report by any other name is still a report..." Vrij naar Shakespeare natuurlijk. Iedereen hier weet wel dat Access geen brieven kan afdrukken, maar wel rapporten. Gewoon een andere benaming. Dus dat zal geen probleem hebben opgeleverd.

Jouw code, Octa, bevat geen printopdracht. En ik heb zoiets al geprobeerd, het geeft geen verbetering qua performance.
Echt wel; de standaardinstelling acViewNormal drukt het rapport gelijk af. Uit de Helpfunctie:
Met de methode OpenReport kunt u een rapport openen in de ontwerpweergave, de afdrukweergave, of het rapport meteen afdrukken.
In het volgende voorbeeld wordt het rapport Sales Report afgedrukt met gebruik van de bestaande query Report Filter.

DoCmd.OpenReport "Sales Report", acViewNormal, "Report Filter"

Kortom: dat de code bij jou niet werkt, zegt meer over jouw db dan over de report opdracht uit mijn code.

Als je een vraag stelt, is het van belang dat je alle aspecten die de uitvoering kunnen beïnvloeden gelijk benoemt, dat werkt voor ons ook een stuk makkelijker. Met de laatste informatie erbij, zou je eens kunnen kijken of de database eigenschappen wel goed staan. Persoonlijk zou ik, zeker als het netwerk niet geweldig snel is, met een FE-BE werken waarbij alle gebruikers een eigen frontend hebben die aan de backend is gekoppeld. Dan heb je de minste snelheidsproblemen.
 
Kun je een foto nemen van je 'behandelscherm'?
Je spreekt van een tabel onder dat scherm? Onze dames moeten nml bij iedre opname van een nieuwe bewoner een 34-tal rapporten afprinten. Ze kunnen dit doen door eerst in een formulier de juiste documenten aan te vinken (de rapportnamen zitten opgeslagen in een tabel) en dan op de printknop te drukken. Het netwerk kan zo'n printopdracht niet ineens aan en dus doen we dat via een funcite met loop in (met instelbare pauze tussen de verschillende opdrachten). Dan lukt 't de printer om alles in een paar minuten af te drukken.
Er zijn hier ook verschillende DB crashes opgelost indertijd met alles gewoon te splitsen naar een backend met voor de grootste gebruikers een eigen frontend.
 

Bijlagen

  • Direct_print.JPG
    Direct_print.JPG
    205,7 KB · Weergaven: 86
Laatst bewerkt:
Helaas Johan, ook geen foto. Is wel mogelijk natuurlijk, maar niet toegestaan vanwege de wet op privacy.
In jouw db kunnen gebruikers zelf aanvinken welk rapport ze willen hebben, in mijn db wordt dat geautomatiseerd bepaald a.h.v. de ingevulde gegevens op het behandelscherm. Hooguit 2 rapporten (brief + bijlage) kunnen hierbij worden aangemaakt. Ik ga nog verder stoeien met de suggesties+vb code van Octa. Bedankt zover!
 
Je kunt daar op verschillende manieren ver in gaan; Bv In onderstaande screenshots van een andere manier krijgt de gebruiker voor het aanmaken en opslaan op bepaalde directories van een ganse reeks PDF's een paar waarschuwingschermen en keuzemogelijkheden, het aantal PDF's dat gemaakt wordt en dan achteraf een resultaatscherm hoe lang het geduurd heeft.
 

Bijlagen

  • 00.PNG
    00.PNG
    22,2 KB · Weergaven: 63
  • 01.PNG
    01.PNG
    26,5 KB · Weergaven: 89
  • 02.PNG
    02.PNG
    19 KB · Weergaven: 74
  • 03.PNG
    03.PNG
    12,3 KB · Weergaven: 81
Is wel mogelijk natuurlijk, maar niet toegestaan vanwege de wet op privacy.
Ik werk ook met privacy gevoelige documenten (gemeente) maar zo zout als bij jou heb ik het nog niet gegeten :). Je kunt toch wel een afdrukje maken en dan de persoonsgegevens even blurren?
 
Het heeft even geduurd, maar het performance probleem met de vba code is opgelost!
Achteraf lag het helemaal niet aan de code... er ontbrak een index op de SQL tabel!
In ieder geval bedankt voor jullie meedenken.
 
Ach ja, het nut van indexen.... Kan niet genoeg benadrukt worden :).
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan