Foxite.COM Community Weblog

Foxite.COM Community Weblog - free weblog service for the Visual FoxPro Community.
Welcome to Foxite.COM Community Weblog Sign in | Join | Help
in
Home Blogs Forum Photos Forum Archives

VFP IMAGING



Full Justified texts in reports with GdiPlusX - REVISITED

As I've shown in a previous post from last year, this is totally possible for us in VFP, using the GdiPlusX library together with ReportListeners, remember?

 

BUT I've been receiving some emails about the Full-Justified ReportListener I published last year.

It did not deal with the possibility of multipage reports. In fact, when a string that had to be printed in FullJustified mode had to be divided in more than one page, in the next page the whole string was redrawn.

To solve this, I needed to make some adjustments in the report listener source, more specifically in the "Render" event, in order to deal with the parameters "nObjectContinuationType" and "cContentsToBeRendered". I had totally missed them. In the first version, I was only using the "Text" property that I retrieved in the "EvaluateContents" method. The first tells us if the text could be totally drawn, or partially. The 2nd, brings the text that is to be drawn, not the whole text.

It's amazing how we can control our output with all these new enhancements from the VFP9 Reporting System. In fact, we can control almost everything !

It's a pity I couldn't explore this tool as much as I would like, the possibilities seem to be infinite.

 

In HELP I found all the info I needed to fix it:

  • nObjectContinuationType
    * Indicates the current continuation state for the rendered element. When layout elements span pages, they are rendered in multiple sections (once for each page).
    * Value  Continuation Type 
    *   0    Complete (no continuation).
    *   1    Start of layout element occurrence, will not finish on the current page.
    *   2    Mid-element, neither started nor finished on the current page.
    *   3    End of element, completed on the current page.

 

  • cContentsToBeRendered
    * Indicates the text to be rendered for Expression (Field) and Label layout elements.
    * If your derived class sends the text value through some additional processing, such as storage in a table, you can use the STRCONV() function, and its optional regional script parameter, to convert the string to DBCS first. For more information, see STRCONV( ) Function.

 

Some important tweaks and fixes were needed in the GdiPlusX library too, more specifically in the xfcGraphics.DrawStringJustified function. I added to it a new parameter, "tlJustifyLast", in order fo force the justifying in the last sentence. This is for the case of reports, when an unfinished sentence needs to be justified as well.

 

The source code is below, you can adapt it to your needs !

 

 

The idea is to add a "<FJ>" tag in the USER tab or in the beginning of any string from a textbox in a report, to tell the ReportListener that it will draw the text using the DRAWSTRINGJUSTIFIED method from GdiPlusX. Special thanks to Victor Espinoza, from Miami, FL, for his important feedback, suggestions and fixes.

 

The "FullJustifyListener" performs the following actions:

- Initializes GdiPlusX

- Creates a GDI+ Graphics object that will be used to draw in the report

- Stores in an array the required information needed to draw the string(Font, Size, Style and Color)

- Before Rendering the string, checks if the "<FJ>" tag is at the beginning of text or at the "USER" tab in the report designer - if yes, draws the string using the new method.

Here are the steps for you to bring this to your reports:

 

1 - Download the updated GdiPlusX library - the System.App file

VERY IMPORTANT - READ THIS !

This report listener needs the updated version of the GdiPlusX main file of the library, "System.App". As it will take some time till a new version will be released, I've uploaded this file separately, so that people can try this feature from now.

Go to this link: http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=8606

And download the file "GdiPlusX Updated System.App for FullJustified purposes"

If you prefer, this file is found in the downloadable source code from this article.

 

 

2 - Save the ReportListener:

Please Copy and Paste the code below, and save it as FJLISTENER.PRG in the samples folder of GdiPlusX 

 

* Program : FJLISTENER.PRG
* Version : 2.0
* Purpose : Provides a Report Listener that allows rendering text in
* Full Justify alignment.
* Authors : Cesar Ch
http://weblogs.foxite.com/vfpimaging
* Class based on article "Listening to a report" by Doug Hennig
* New tweaked version allows drawing strings that need to be divided in more than one page

* Special thanks to Victor Espinoza 
*
http://msdn2.microsoft.com/en-us/library/ms947682.aspx

DEFINE CLASS FullJustifyListener AS FXListener
oGDIGraphics =
NULL
nSaveGraphicsHandle = 0
nTimes = 1
DIMENSION aRecords[1]
 
* Before we run the report, go through the FRX and store information about any
* field with our expected directive in its USER memo into the aRecords array.
FUNCTION BEFOREREPORT
   DODEFAULT
()
   * Check if we already have the "System" object in "_Screen"
   IF NOT PEMSTATUS(_Screen,"System",5)
      DO LOCFILE("System.App")
   ENDIF
   WITH This
      .oGDIGraphics = _SCREEN.SYSTEM.Drawing.Graphics.New()
      .SetFRXDataSession()
      DIMENSION .aRecords[reccount(), 13]
      SCAN FOR "<FJ>" $ UPPER(User)
         .aRecords[recno(), 13] = "FJ"
      ENDSCAN
     .ResetDataSession()
   ENDWITH
ENDFUNC

FUNCTION BEFOREBAND(nBandObjCode, nFRXRecNo)
   This.SharedGDIPlusGraphics = This.GDIPLUSGRAPHICS
   This
.oGDIGraphics.Handle = This.SharedGDIPlusGraphics
   DODEFAULT(nBandObjCode, nFRXRecNo)
ENDFUNC
 
PROCEDURE RENDER
(tnFRXRecNo,;
   tnLeft,tnTop,tnWidth,tnHeight,;
   nObjectContinuationType, ;
   cContentsToBeRendered, GDIPlusImage)

   LOCAL lcText, llFlag
   llFlag = .F.
   lcText =
This.aRecords(tnFRXRecNo,1)

   IF (VARTYPE(lcText) = "C" AND LEFT(lcText,4) = "<FJ>") OR ;
      (
VARTYPE(This.aRecords(tnFRXRecNo,13)) = "C" AND This.aRecords(tnFRXRecNo,13) == "FJ")

      IF nObjectContinuationType > 0

      * nObjectContinuationType
      * -----------------------
      * Indicates the current continuation state for the rendered element. When layout elements span pages, they are rendered in multiple sections (once for each page).
      * Value Continuation Type
      * 0 Complete (no continuation).
      * 1 Start of layout element occurrence, will not finish on the current page.
      * 2 Mid-element, neither started nor finished on the current page.
      * 3 End of element, completed on the current page.

      * cContentsToBeRendered
      * ---------------------
      * Indicates the text to be rendered for Expression (Field) and Label layout elements.
      * If your derived class sends the text value through some additional processing, such as storage in a table, you can use the STRCONV() function, and its optional regional script parameter, to convert the string to DBCS first. For more information, see STRCONV( ) Function.

         lcText = STRCONV(cContentsToBeRendered,6)

            IF INLIST(nObjectContinuationType, 1, 2)
               llFlag = .T.
            ENDIF
         ENDIF
 
         IF UPPER
(LEFT(lcText,4)) = "<FJ>"
            lcText =
SUBSTR(lcText,5) && Remove the <FJ> tag from string
         ENDIF

         WITH _SCREEN.SYSTEM.Drawing

         This.oGDIGraphics.Handle = This.GDIPlusGraphics
         *!* Create a GDI+ Rectangle which specifies where on the
         *!* surface we're drawing the text.
         LOCAL loRectF as xfcRectangleF
         loRectF = .RectangleF.New(tnLeft, tnTop, tnWidth, tnHeight)

         LOCAL loFont as xfcFont
         loFont = .
Font.New(This.aRecords(tnFRXRecNo,2) ;
            ,
This.aRecords(tnFRXRecNo,4), This.aRecords(tnFRXRecNo,3) ;
            , .GraphicsUnit.
Point)

         * Retrieve colors for the background
         LOCAL lnRed, lnGreen, lnBlue, lnAlpha
         lnRed =
This.aRecords[tnFRXRecno,5]
         lnGreen =
This.aRecords[tnFRXRecno,6]
         lnBlue =
This.aRecords[tnFRXRecno,7]
         lnAlpha =
This.aRecords[tnFRXRecno,8]
         LOCAL loBackBrush as xfcSolidBrush
         loBackBrush = .SolidBrush.New(;
            .
Color.FromArgb(lnAlpha,lnRed, lnGreen, lnBlue))

         This.oGdiGraphics.FillRectangle(loBackBrush, tnLeft, tnTop, tnWidth, tnHeight)

         * Retieve colors for the Text
         lnRed = This.aRecords[tnFRXRecno,9]
         lnGreen =
This.aRecords[tnFRXRecno,10]
         lnBlue =
This.aRecords[tnFRXRecno,11]
         lnAlpha =
This.aRecords[tnFRXRecno,12]
         LOCAL loTextBrush as xfcSolidBrush
         loTextBrush = .SolidBrush.New(;
            .
Color.FromArgb(lnAlpha,lnRed, lnGreen, lnBlue))

         This.oGdiGraphics.DrawStringJustified(lcText, loFont, loTextBrush, loRectF, llFlag)

         ENDWITH
      ELSE
      *!* If we're not drawing a full justified string,
      *!* let Fox draw the text as usual.
         DODEFAULT(tnFRXRecNo, tnLeft, tnTop, tnWidth, tnHeight, ;
            nObjectContinuationType, cContentsToBeRendered, GDIPlusImage)
      ENDIF

      *!* Since we already drew the text, we don't want the default
      *!* behavior to occur.
   NODEFAULT
ENDPROC

FUNCTION EvaluateContents
(tnFRXRecno, toObjProperties)
   * Get the FRX data
   This.aRecords[tnFRXRecno,1] = toObjProperties.Text
   This
.aRecords[tnFRXRecno,2] = toObjProperties.FontName
   This
.aRecords[tnFRXRecno,3] = toObjProperties.FontStyle
   This.aRecords[tnFRXRecno,4] = toObjProperties.FontSize
   This
.aRecords[tnFRXRecno,5] = toObjProperties.FillRed
   This.aRecords[tnFRXRecno,6] = toObjProperties.FillGreen
   This.aRecords[tnFRXRecno,7] = toObjProperties.FillBlue
   This.aRecords[tnFRXRecno,8] = toObjProperties.FillAlpha
   This.aRecords[tnFRXRecno,9] = toObjProperties.PenRed
   This.aRecords[tnFRXRecno,10] = toObjProperties.PenGreen
   This.aRecords[tnFRXRecno,11] = toObjProperties.PenBlue
   This.aRecords[tnFRXRecno,12] = toObjProperties.PenAlpha
ENDFUNC

ENDDEFINE

 

3 - Update the report:

Below is a short tutorial for the beginners:

- Open any of your reports, that contains a field of more than one line that will receive the effect. Double-Click on that field, select the GENERAL tab, and add BEFORE your expression, this simple string: [  "<FJ>" +  ], like in the picture below.

 

 

Another better option is to add the tag to the USER tab, that is available only in VFP9 Report Designer. Just like before, double-click in the desired field, select the "OTHER" tab, then click on the "EDIT USER DATA" button, and add the <FJ> tag to the window, just like the picture below. This is the most recommended approach, because the original data will not be affected, and if one day you decide to stop using the report listener, your report data will not be affected.

 

 

4 - Run the report

 

* Tell VFP that we'll be using the new report features
SET REPORTBEHAVIOR 90
LOCAL loReportListener
loReportListener = CREATEOBJECT("FullJustifyListener")
loReportListener.ListenerType = 1
REPORT FORM YourReport OBJECT loReportListener

 

 

Below a last screenshot, showing the of the continued field issue solved:

 

Enjoy !!!

 

CLICK HERE TO DOWNLOAD THE SOURCE CODE AND SAMPLE FROM THIS ARTICLE

Published Sunday, June 15, 2008 5:46 AM by cesarchalom

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

VFP IMAGING said:

Tradução para o português deste artigo (Portuguese translation):
http://vfpimaging.spaces.live.com/blog/
June 15, 2008 7:43 AM
 

3 Below » Full Justified texts in reports with GdiPlusX said:

June 15, 2008 7:56 AM
 

Pages tagged "layout" said:

June 15, 2008 10:02 AM
 

Cesar Chalom said:

Trackback - Cesar has a great post with examples, code and screenshots, of how to do reporting in VFPwith text justification using GdiPlusX. Well done!
June 15, 2008 11:50 PM
 

ravisobhan said:

Sir
The Full justification download and programs are not  working. Please guide us.
June 30, 2008 11:50 AM
 

willian said:

How can We show unicode in Vfp9_Report ?
July 14, 2008 4:18 PM

What do you think?

(required) 
(optional)
(required)