Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Articles
Search: 

How do I know if report is printed
Lutz Scheffler, May 8, 2009
When printing, sometimes there is a need to know if a report is printed or not. Since we have no simple way to see if something is realy printed we can at least check if the user send a complete report to the spooler. This article deals with the way to solve this problem with and without object as...
Summary
When printing, sometimes there is a need to know if a report is printed or not. Since we have no simple way to see if something is realy printed we can at least check if the user send a complete report to the spooler. This article deals with the way to solve this problem with and without object assisted reports (aka listeners).
Description
Update: add up code to catch cancel in the printer prompt of
REPORT FORM xxx TO PRINTER PROMPT
/Update For a report without object assistance this is a simple problem. We need to see if the last part of the report is printed while the print window exists. The main trick is to place some code into an On.. Expression of a bar that runs at the very end of the report. (Doubleclick the grey bar in the report designer to reach the expressions). One way would be to add a summary expression to each report and use its OnExit. The problem with summary is, that this (if empty) will create extra pages on multi column reports The more reliable way is to add an otherwise useless outer group that will never change, for example with expression .F.. The expression will be added to the OnExit of the groups footer. The expression may be as simple as a variable assignment using _VFP.SetVar. I try to give a more general solution so I refer to a method of a object what will do the reporting The code in on Exit looks like:
poPrint.ReportEnd
The report call looks like
PRIVATE;
 poPrint

THIS.glPrinted = .F.

poPrint = THIS && Assuming THIS is the printhandler with the method!

REPORT FORM ....

IF THIS.glPrinted THEN
 ?'Report send to spooler'
ELSE &&THIS.glPrinted
 ?'Report not (completely) printed'
ENDIF &&THIS.glPrinted
The method ReportEnd will be discussed below since I simply use it for the Listener too The object assisted reporting is a bit more tricky We have a problem with Reportbehavior 90. The new rendering system makes small differences if we use preview or not. For non preview reports we need simply to check if te report is not canceled via ESC. In preview the report is completely rendered on the point we decide to print, so no report band or the like is activated. What I do is a small trick with eventbinding I refer again to a method called "ReportEnd". (Generic for all versions of VFP)
LPARAMETERS;
 tlPrint

*FYI:
#DEFINE dcPrintWindow_uk	'Printing...'
#DEFINE dcPrintWindow_deu	'Drucken...'

LOCAL;
 llEvent  AS BOOLEAN

#IF VERSION(5)>=900 THEN
*not much use before VFP9, much trouble before VFP8
 LOCAL;
  lnEvents AS INTEGER,;
  lnEvent  AS INTEGER

 LOCAL ARRAY;
  laAvents(1,4)

 lnEvents = AEVENTS(laEvents,THIS)

 FOR lnEvent = 1 TO lnEvents
  IF laEvents(lnEvent,1) AND laEvents(lnEvent,4)=('REPORTEND') THEN 
   llEvent = .T.
   EXIT
  ENDIF &&laEvents(lnEvent,1) AND laEvents(lnEvent,4)=('REPORTEND')
 ENDFOR &&lnEvent

 IF llEvent THEN
  IF !EMPTY(AEVENTS(laEvents,0)) THEN
*supress VFP 8 style call from frx, if the summary band still holds the call
   DO CASE
    CASE !laEvents(1,1).BASECLASS='Reportlistener'
    CASE laEvents(1,2)=('BEFOREREPORT')
     THIS.glPrinted = .T.
    CASE laEvents(1,2)=('CANCELREPORT')
     THIS.glPrinted = .F.
    CASE laEvents(1,2)=('ONPREVIEWCLOSE') AND !tlPrint
     THIS.glPrinted = .F.
   ENDCASE
  ENDIF &&!EMPTY(AEVENTS(laEvents,0))
 ENDIF &&llEvent
#ENDIF &&VERSION(5)>=900 THEN

IF !llEvent THEN
*this is for REPORTBEHAVIOR 80 and needs a call to this method in summary band
 #IF VERSION(5)<800 THEN
*before Version 8
*if you use other language add up
  THIS.glPrinted = ;
   WEXIST(dcPrintWindow_Deu) OR;
   WEXIST(dcPrintWindow_Uk)
 #ELSE &&VERSION(5)<800
*Version 8 and beyond. We have a problem with NODIALOG clause
*so we use new sys function:
  THIS.glPrinted = SYS(2040)="2"
 #ENDIF &&VERSION(5)<800
ENDIF &&llEvent
I call the report from a form like:
toListener = .NULL.
DO (_REPORTOUTPUT) WITH tnListenerType,toListener

THIS.glPrinted = .F.
BINDEVENT(toListener,'BeforeReport'  ,THIS,'ReportEnd',1)
BINDEVENT(toListener,'CancelReport'  ,THIS,'ReportEnd',1)
BINDEVENT(toListener,'OnPreviewClose',THIS,'ReportEnd',1)

REPORT FORM myReport OBJECT toListener

UNBINDEVENTS(toListener,'OnPreviewClose',THIS,'ReportEnd')
UNBINDEVENTS(toListener,'CancelReport'  ,THIS,'ReportEnd')
UNBINDEVENTS(toListener,'BeforeReport'  ,THIS,'ReportEnd')

*If THIS.glPrinted is .F., the report was not send to any spooler
The contents of this FAQ are composed from articles out of UT from different authors. It's accumulated over the years. Thank you all. Update: Note the inverse init value of THIS.glPrinted for the both Version (REPORTBEHAVIOR 80/90)
Lutz Scheffler, Lutz Scheffler Software Ingenieurbüro
More articles from this author
Lutz Scheffler, June 4, 2004
Custom scripts are different from scripts that are invoked via a command or function. The big plus to command or function is that custom scripts may invoke everywhere in a line, while command can be invoked only as first word and functions need a "(". There are some problems to write a custom scr...
Lutz Scheffler, June 2, 2009
A commonly problem seems to be to run an app with the VFP Version / SP it is compiled. VFP itself gives not much help on this. But some little compiler commands like #IF and #DEFINES will do the trick.