VFP 9 introduces a new reporting system based on listeners (object-assisted output).
Listeners can be customized in a variety of ways and there's a lot of amazing things you can do with it.
If you combine the power of GDI+ with customized listeners you can highly increase the reporting capabilities.
I'll show how you can customize the Report Listener to create a watermark in all report pages and how you can customize Report Preview to change the language of report preview toolbar buttons and display the preview window maximized.
Set Classlib To (Addbs(Home()) + "FFC\_GDIPlus.vcx") Additive
* Create a Report Listener object
Local loReportListener
loReportListener = Newobject("MyReportListener")
With loReportListener
.ListenerType = 1 && Preview
* Set the Watermark properties: text, font and style
.cWatermark = "Watermark demo"
.cFontName = "Verdana"
.nFontStyle = 1 && Bold
Endwith
* Create a cursor that will be the report data source and insert some records
Create Cursor curTest (field1 c(100))
Local i
For i=1 To 640
Insert Into curTest Values (Str(i)+" test, test, test, test, test, test, test, test, test, test, test, test, test")
Endfor
Select curTest
Go Top
* Create a report on the fly
Create Report Test From curTest
* Run the report using the new report engine (object-assisted output)
Report Form Test Object loReportListener
* Close cursor and delete the report file
Use In curTest
Delete File Test.fr?
Return
* Create a class derived from _ReportListener base class and add some features
Define Class MyReportListener As _ReportListener Of Addbs(Home()) + "FFC\_ReportListener.VCX"
* Internal to the class
Hidden nAngle, oBrush, oColor, oFont, oGDIGraphics, oRect, oStringFormat
Hidden ResourceStatus
nAngle = 0
oBrush = Null
oColor = Null
oFont = Null
oGDIGraphics = Null
oRect = Null
oStringFormat = Null
cResourceStatus = Set("Resource")
* Public
cWatermark = ""
cFontName = ""
nFontStyle = 0
*
Procedure Init
Lparameters cWatermark, cFontName, cFontStyle
Set Resource Off
With This
.cWatermark = Evl(cWatermark,"")
.cFontName = Evl(cFontName,"")
.nFontStyle = Evl(cFontStyle,0)
Endwith
DoDefault()
Endproc
*
Procedure Destroy
Local lcResourceStatus
lcResourceStatus = This.cResourceStatus
Set Resource &lcResourceStatus
DoDefault()
Endproc
*
Procedure LoadReport
DoDefault()
With This
If .ListenerType==1 And Not Vartype(.PreviewContainer)=="O"
.ExtendPreviewContainer()
Endif
Endwith
Endproc
*
Procedure BeforeReport
DoDefault()
With This
If Not Empty(.cWatermark)
.oGDIGraphics = Createobject('GPGraphics')
.SetWatermarkFontSize()
Endif
Endwith
Endproc
*
Procedure AfterBand(nBandObjCode, nFRXRecNo)
If nBandObjCode==7 && Page footer
With This
If Not Empty(.cWatermark)
.AddWatermark()
Endif
Endwith
Endif
DoDefault(nBandObjCode, nFRXRecNo)
Endproc
*
Function SetWatermarkFontSize
With This
.SetoGDIGraphicsHandle()
* Create a semi transparent Grey Color
.oColor = Createobject('gpColor',128,128,128,127)
* Create a SolidBrush with Grey Color
.oBrush = Createobject("gpSolidBrush", .oColor)
* Create a StringFormat
#Define StringAlignmentNear 0
#Define StringAlignmentCenter 1
#Define StringAlignmentFar 2
.oStringFormat = Createobject('gpStringFormat')
With .oStringFormat
.Create()
.Alignment = StringAlignmentCenter
.LineAlignment = StringAlignmentCenter
Endwith
* Create a Font object
Local loFont
loFont = Createobject("GpFont")
Local lnFactor, lnMaxWidth
lnFactor = 0.80
lnMaxWidth = (Sqrt((.SharedPageHeight ^ 2) + (.SharedPageWidth ^ 2))) * lnFactor
* To bypass GDI+ MeasureString bug to obtain the correct size
Local loStringFormat As 'GpStringFormat' Of Home() + 'FFC\_gdiplus.vcx'
loStringFormat = Newobject('GpStringFormat',Home() + 'FFC\_gdiplus.vcx')
loStringFormat.Create()
loStringFormat.GetGenericTypographic()
Local loSize, lnSize, lnCharsFitted, lnLinesFilled, lnPerc
lnSize = 1500
loFont.Create(.cFontName,lnSize,.nFontStyle,2)
lnCharsFitted = 0
lnLinesFilled = 0
loSize = .oGDIGraphics.MeasureStringA(.cWatermark,loFont, ,;
loStringFormat, @lnCharsFitted, @lnLinesFilled)
If Vartype(loSize)=="O"
If loSize.W > lnMaxWidth
lnPerc = loSize.W / lnMaxWidth
lnSize = Int(lnSize / lnPerc)
Endif
Endif
loFont.Create(.cFontName,lnSize,.nFontStyle,2)
.oFont = loFont
* Calculate the rotation angle
.nAngle = Rtod(Atan(.SharedPageHeight / .SharedPageWidth ))
* Create a rectangle with special dimensions
.oRect = Createobject("gpRectangle", ;
-.SharedPageWidth/2, -.SharedPageHeight/2, ;
.SharedPageWidth*2, .SharedPageHeight*2)
Endwith
Endfunc
*
Function AddWatermark
With This
.SetoGDIGraphicsHandle()
* Prepare transformation
.oGDIGraphics.TranslateTransform(.SharedPageWidth/2, ;
.SharedPageHeight/2)
.oGDIGraphics.RotateTransform(-.nAngle)
.oGDIGraphics.TranslateTransform(-.SharedPageWidth/2, ;
-.SharedPageHeight/2)
* Draw a string
.oGDIGraphics.DrawStringA(.cWatermark, .oFont, .oRect, .oStringFormat, .oBrush)
* Reset Rotation
.oGDIGraphics.ResetTransform()
Endwith
Endfunc
*
Function SetoGDIGraphicsHandle
With This
If Not .IsSuccessor
.SharedGDIPlusGraphics = .GDIPlusGraphics
Endif
.oGDIGraphics.SetHandle(.SharedGDIPlusGraphics)
.oGDIGraphics.TextRenderingHint = 3 && AntiAlias
Endwith
Endfunc
*
Function ExtendPreviewContainer
Local loPreviewContainer
loPreviewContainer = Null
Do (_ReportPreview) With loPreviewContainer
loPreviewContainer.SetExtensionHandler(Newobject("MyExtensionHandler"))
This.PreviewContainer = loPreviewContainer
Endfunc
Enddefine
* Create a class that will extend Report Preview
Define Class MyExtensionHandler As Custom
*
Procedure Show(iStyle)
With This.PreviewForm
With .Toolbar
* Translate toolbar buttons ToolTips to Brazilian Portugese language
.cboZoom.ToolTipText = "Zoom"
.cmdClose.ToolTipText = "Fechar a visualização"
.cmdGoToPage.ToolTipText = "Ir para a página"
.cmdPrint.ToolTipText = "Imprimir"
With .cntNext
.cmdBottom.ToolTipText = "Última página"
.cmdForward.ToolTipText = "Próxima página"
Endwith
With .cntPrev
.cmdBack.ToolTipText = "Página anterior"
.cmdTop.ToolTipText = "Primeira página"
Endwith
With .opgPageCount
.opt1.ToolTipText = "Uma página"
.opt2.ToolTipText = "Duas páginas"
.opt3.ToolTipText = "Quatro páginas"
Endwith
*
Endwith
.WindowState = 2 && Maximize report preview
Endwith
DoDefault(iStyle)
Endproc
*
Enddefine
To know more about the new VFP 9 reporting system and GDI+, I recomend you to:
- read VFP 9 help topics: Understanding Visual FoxPro Object-Assisted Reporting and Using GDI+ in Reports;
- take a look at VFPX website and search for GDIPlusX class that extends GDI+ capabilities;
- visit César Chalom's blog. He is involved in GDIPlusX project from VFPX team. His blog has great GDI+ samples.
One more time, thanks to César Chalom for develop the code to do the watermark. Congratulations for your great job!