2007-04-05

Full Justified Texts in your reports with GdiPlus X

This is a continuation of my previous post, Full-Justified Text with GdiPlusX . Now I'll show how we can use the new method DRAWSTRINGJUSTIFIED from GdiPlusX library to have full Justified texts in our reports.


 

There are 2 ways of using this feature in reports.

The most obvious is to use the picture saved in the samples from the previous post, and use it directly in the report.

But VFP9 brings so many other cool possibilities, that I couldn't leave them without a try, so I decided to create a subclass of the Report Listener that will transform some of the texts from my reports to Full-Justified. My idea was that the user would just need to add a "<FJ>" tag in the beginning of any string from a textbox in a report, to tell my ReportListener that it will draw the text using the DRAWSTRINGJUSTIFIED method from GdiPlusX.

Please note that I'm NO expert in the new Object Assisted Reports from VFP9. My experience using Report Listeners is really very limited. I'm sure that the report listener below can be improved, so, if you have any suggestion that can improve the performance or ease the process, please tell me !

My "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 - if yes, draws the string using the new method.

VERY IMPORTANT 

The main GDI+ part of the custom report listener is located at the procedure "Render" of the subclass.

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

DEFINE CLASS FullJustifyListener AS _ReportListener OF ;
        ADDBS(HOME(1)) + "FFC\_ReportListener.VCX"
    oGDIGraphics = NULL
    DIMENSION aRecords[1]

    * Before we run the report, we need to Make sure that GdiPlusX
    * was initialized, and create a new Graphics object
    FUNCTION BEFOREREPORT
        DODEFAULT()
        WITH THIS
            * Check if we already have the "System" object in "_Screen"
            IF NOT PEMSTATUS(_SCREEN, "System", 5)
                DO LOCFILE("System.App")
            ENDIF
            .oGDIGraphics = _SCREEN.SYSTEM.Drawing.Graphics.New()
            .SetFRXDataSession()
            DIMENSION .aRecords[reccount(), 12]
            .ResetDataSession()
        ENDWITH
    ENDFUNC

    FUNCTION BEFOREBAND(nBandObjCode, nFRXRecNo)
        THIS.SharedGDIPlusGraphics = THIS.GDIPLUSGRAPHICS
        THIS.oGDIGraphics.Handle   = THIS.SharedGDIPlusGraphics
        DODEFAULT(m.nBandObjCode, m.nFRXRecNo)
    ENDFUNC

    PROCEDURE RENDER(tnFRXRecNo, ;
              tnLeft, tnTop, tnWidth, tnHeight, ;
              nObjectContinuationType, ;
              cContentsToBeRendered, GDIPlusImage)
        LOCAL lcText
        m.lcText = THIS.aRecords(m.tnFRXRecNo, 1)

        IF VARTYPE(m.lcText) = "C" AND m.lcText = "<FJ>"
            m.lcText				 = SUBSTR(m.lcText, 5) && Remove the <FJ> tag from string
            THIS.oGDIGraphics.Handle = THIS.GDIPLUSGRAPHICS

            WITH _SCREEN.SYSTEM.Drawing

                * Create a GDI+ Rectangle which specifies where on the
                * surface we're drawing the text.
                LOCAL loRectF AS xfcRectangleF
                m.loRectF = .RectangleF.New(m.tnLeft, m.tnTop, m.tnWidth, m.tnHeight)

                * Create a Font Object based on the report original settings
                LOCAL loFont AS xfcFont
                m.loFont = .FONT.New(THIS.aRecords(m.tnFRXRecNo, 2) ;
                      , THIS.aRecords(m.tnFRXRecNo, 4), THIS.aRecords(m.tnFRXRecNo, 3) ;
                      , .GraphicsUnit.POINT)

                * If we have an opaque background set for the text, then draw a rectangle
                * using the background chosen background color
                IF THIS.aRecords[m.tnFRXRecno, 8] <> 0 && Alpha

                    * Retrieve colors for the background
                    LOCAL lnRed, lnGreen, lnBlue, lnAlpha
                    m.lnRed	  = THIS.aRecords[m.tnFRXRecno, 5]
                    m.lnGreen = THIS.aRecords[m.tnFRXRecno, 6]
                    m.lnBlue  = THIS.aRecords[m.tnFRXRecno, 7]
                    m.lnAlpha = THIS.aRecords[m.tnFRXRecno, 8]

                    * Create a Solid Brush that will be used to draw the Background
                    LOCAL loBackBrush AS xfcSolidBrush
                    m.loBackBrush = .SolidBrush.New(;
                          .COLOR.FromArgb(m.lnAlpha, m.lnRed, m.lnGreen, m.lnBlue))

                    * Draw the background rectangle
                    THIS.oGDIGraphics.FillRectangle(m.loBackBrush, m.tnLeft, m.tnTop, m.tnWidth, m.tnHeight)
                ENDIF

                * Retieve colors for the Text
                m.lnRed	  = THIS.aRecords[m.tnFRXRecno, 9]
                m.lnGreen = THIS.aRecords[m.tnFRXRecno, 10]
                m.lnBlue  = THIS.aRecords[m.tnFRXRecno, 11]
                m.lnAlpha = THIS.aRecords[m.tnFRXRecno, 12]

                * Create a Solid Brush that will be used to draw the text
                LOCAL loTextBrush AS xfcSolidBrush
                m.loTextBrush = .SolidBrush.New(;
                      .COLOR.FromArgb(m.lnAlpha, m.lnRed, m.lnGreen, m.lnBlue))

                * Finally, draw the text in FullJustified mode.
                THIS.oGDIGraphics.DrawStringJustified(m.lcText, m.loFont, m.loTextBrush, m.loRectF)
            ENDWITH
        ELSE

            * If we're not drawing a full justified string,
            * let VFP draw the text as usual.
            DODEFAULT(m.tnFRXRecNo, m.tnLeft, m.tnTop, m.tnWidth, m.tnHeight, ;
                  m.nObjectContinuationType, m.cContentsToBeRendered, m.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[m.tnFRXRecno, 1]	= m.toObjProperties.TEXT
        THIS.aRecords[m.tnFRXRecno, 2]	= m.toObjProperties.FONTNAME
        THIS.aRecords[m.tnFRXRecno, 3]	= m.toObjProperties.FontStyle
        THIS.aRecords[m.tnFRXRecno, 4]	= m.toObjProperties.FONTSIZE
        THIS.aRecords[m.tnFRXRecno, 5]	= m.toObjProperties.FillRed
        THIS.aRecords[m.tnFRXRecno, 6]	= m.toObjProperties.FillGreen
        THIS.aRecords[m.tnFRXRecno, 7]	= m.toObjProperties.FillBlue
        THIS.aRecords[m.tnFRXRecno, 8]	= m.toObjProperties.FillAlpha
        THIS.aRecords[m.tnFRXRecno, 9]	= m.toObjProperties.PenRed
        THIS.aRecords[m.tnFRXRecno, 10]	= m.toObjProperties.PenGreen
        THIS.aRecords[m.tnFRXRecno, 11]	= m.toObjProperties.PenBlue
        THIS.aRecords[m.tnFRXRecno, 12]	= m.toObjProperties.PenAlpha
    ENDFUNC
ENDDEFINE

To use it is very simple:

Open any report, and select a textbox that has a memo field associated to it. In the field properties, tab General, on expression, just add a "<FJ>" string before the original field. Supposing you had the expression "MyTable.MyMemoField", to have it justified, you'll change it to: "<FJ>" + MyTable.MyMemoField.

The next step is to make sure that VFP will use our new listener to render the report.

* Tell VFP that we'll be using the new report features
SET REPORTBEHAVIOR 90
LOCAL loReportListener
m.loReportListener = NEWOBJECT("FullJustifyListener", LOCFILE("FJListener.prg"))
* loReportListener = CREATEOBJECT("FullJustifyListener")
m.loReportListener.LISTENERTYPE = 1
REPORT FORM MyReport OBJECT m.loReportListener

  

  

 

 

UPDATE 04/07/2007

After some good suggestions from Victor Espinoza, below is a modified version of the "FJListener" class, that will receivethe <FJ> tag at the user data field for the textbox (under the "Other" tab), this way, the "<FJ>" tag wouldn't affect the reports if it was latter decided to use an alternative report listener.



* Program : FJLISTENER.PRG
* Purpose : Provides a Report Listener that allows rendering text in
*           Full Justify alignment.
* Author : Cesar Ch and Victor Espinoza
* Class based on article "Listening to a report" by Doug Hennig
* http://msdn2.microsoft.com/en-us/library/ms947682.aspx

DEFINE CLASS FullJustifyListener AS _ReportListener OF ;
        ADDBS(HOME(1)) + "FFC\_ReportListener.VCX"
    oGDIGraphics = NULL
    DIMENSION aRecords[1]

    * Doug Hennig - If ListenerType hasn't already been set, set it based on whether the report
    * is being printed or previewed.
    FUNCTION LOADREPORT
    WITH THIS
        DO CASE
        CASE .LISTENERTYPE <> -1
        CASE .COMMANDCLAUSES.PREVIEW
            .LISTENERTYPE = 1
        CASE .COMMANDCLAUSES.OutputTo = 1
            .LISTENERTYPE = 0
        ENDCASE
    ENDWITH
    DODEFAULT()
    ENDFUNC

    * Before we run the report, we need to Make sure that GdiPlusX
    * was initialized, and create a new Graphics object
    FUNCTION BEFOREREPORT
    DODEFAULT()
    WITH THIS
        * Check if we already have the "System" object in "_Screen"
        IF NOT PEMSTATUS(_SCREEN, "System", 5)
            DO LOCFILE("System.App")
        ENDIF

        .oGDIGraphics = _SCREEN.SYSTEM.Drawing.Graphics.New()
        .SetFRXDataSession() && switches to the FRX cursor's datasession
        DIMENSION .aRecords(RECCOUNT(), 13)
        SCAN FOR "<FJ>" $ UPPER(USER)
            .aRecords(RECNO(), 13) = "FJ"
        ENDSCAN
        .ResetDataSession() && restores the datasession ID to the one the listener is in
    ENDWITH
    ENDFUNC

    FUNCTION BEFOREBAND(nBandObjCode, nFRXRecNo)
    THIS.SharedGDIPlusGraphics = THIS.GDIPLUSGRAPHICS
    THIS.oGDIGraphics.Handle   = THIS.SharedGDIPlusGraphics
    DODEFAULT(m.nBandObjCode, m.nFRXRecNo)
    ENDFUNC

    PROCEDURE RENDER(tnFRXRecNo, ;
          tnLeft, tnTop, tnWidth, tnHeight, ;
          nObjectContinuationType, ;
          cContentsToBeRendered, GDIPlusImage)
    IF VARTYPE(THIS.aRecords(m.tnFRXRecNo, 13)) = "C" AND ;
            THIS.aRecords(m.tnFRXRecNo, 13) == "FJ"
        LOCAL lcText
        m.lcText				 = THIS.aRecords(m.tnFRXRecNo, 1)
        THIS.oGDIGraphics.Handle = THIS.GDIPLUSGRAPHICS

        WITH _SCREEN.SYSTEM.Drawing
            * Create a GDI+ Rectangle which specifies where on the
            * surface we're drawing the text.
            LOCAL loRectF AS xfcRectangleF
            m.loRectF = .RectangleF.New(m.tnLeft, m.tnTop, m.tnWidth, m.tnHeight)

            * Create a Font Object based on the report original settings
            LOCAL loFont AS xfcFont
            m.loFont = .FONT.New(THIS.aRecords(m.tnFRXRecNo, 2) ;
                  , THIS.aRecords(m.tnFRXRecNo, 4), THIS.aRecords(m.tnFRXRecNo, 3) ;
                  , .GraphicsUnit.POINT)

            * If we have an opaque background set for the text, then draw a rectangle
            * using the background chosen background color
            IF THIS.aRecords[m.tnFRXRecno, 8] <> 0 && Alpha
                * Retrieve colors for the background
                LOCAL lnRed, lnGreen, lnBlue, lnAlpha
                m.lnRed	  = THIS.aRecords[m.tnFRXRecno, 5]
                m.lnGreen = THIS.aRecords[m.tnFRXRecno, 6]
                m.lnBlue  = THIS.aRecords[m.tnFRXRecno, 7]
                m.lnAlpha = THIS.aRecords[m.tnFRXRecno, 8]

                * Create a Solid Brush that will be used to draw the Background
                LOCAL loBackBrush AS xfcSolidBrush
                m.loBackBrush = .SolidBrush.New(;
                      .COLOR.FromArgb(m.lnAlpha, m.lnRed, m.lnGreen, m.lnBlue))

                * Draw the background rectangle
                THIS.oGDIGraphics.FillRectangle(m.loBackBrush, m.tnLeft, m.tnTop, m.tnWidth, m.tnHeight)
            ENDIF

            * Retieve colors for the Text
            m.lnRed	  = THIS.aRecords[m.tnFRXRecno, 9]
            m.lnGreen = THIS.aRecords[m.tnFRXRecno, 10]
            m.lnBlue  = THIS.aRecords[m.tnFRXRecno, 11]
            m.lnAlpha = THIS.aRecords[m.tnFRXRecno, 12]

            * Create a Solid Brush that will be used to draw the text
            LOCAL loTextBrush AS xfcSolidBrush
            m.loTextBrush = .SolidBrush.New(;
                  .COLOR.FromArgb(m.lnAlpha, m.lnRed, m.lnGreen, m.lnBlue))

            * Finally, draw the text in FullJustified mode.
            THIS.oGDIGraphics.DrawStringJustified(m.lcText, m.loFont, m.loTextBrush, m.loRectF)
        ENDWITH
    ELSE
        * If we're not drawing a full justified string,
        * let VFP draw the text as usual.
        DODEFAULT(m.tnFRXRecNo, m.tnLeft, m.tnTop, m.tnWidth, m.tnHeight, ;
              m.nObjectContinuationType, m.cContentsToBeRendered, m.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[m.tnFRXRecno, 1]	= m.toObjProperties.TEXT
    THIS.aRecords[m.tnFRXRecno, 2]	= m.toObjProperties.FONTNAME
    THIS.aRecords[m.tnFRXRecno, 3]	= m.toObjProperties.FontStyle
    THIS.aRecords[m.tnFRXRecno, 4]	= m.toObjProperties.FONTSIZE
    THIS.aRecords[m.tnFRXRecno, 5]	= m.toObjProperties.FillRed
    THIS.aRecords[m.tnFRXRecno, 6]	= m.toObjProperties.FillGreen
    THIS.aRecords[m.tnFRXRecno, 7]	= m.toObjProperties.FillBlue
    THIS.aRecords[m.tnFRXRecno, 8]	= m.toObjProperties.FillAlpha
    THIS.aRecords[m.tnFRXRecno, 9]	= m.toObjProperties.PenRed
    THIS.aRecords[m.tnFRXRecno, 10]	= m.toObjProperties.PenGreen
    THIS.aRecords[m.tnFRXRecno, 11]	= m.toObjProperties.PenBlue
    THIS.aRecords[m.tnFRXRecno, 12]	= m.toObjProperties.PenAlpha
    ENDFUNC

ENDDEFINE

For now this seems good to me. But there's still some more to improve here. For the next version this can become a "Directive" to be used together with other custom report listeners, as Doug Hennig did in his great article "Listening to a Report"



Related links that helped me to understand how the Report Listener works:

Doug Hennig - Listening to a Report
Doug Hennig - Hyperlink your reports
Doug Hennig - Extending the Visual FoxPro 9 Reporting System
Cathy Pountney - VFP 9.0 Report Writer In Action
Cathy Pountney - What's New in the VFP 9 Report Writer
Garret Fitzgerald - Using the GDI+ FFCs to work with output

24 comments:

  1. Hi Cesar, as always, excellent code, Calvin's and yours are my all time favorite blogs.

    Just an idea, wouldn't it be better to use the user data field for the textbox (under the "Other" tab), this way, the "<FJ>" tag wouldn't affect the reports if it was latter decided to use an alternative report listener. All you would need is:
    - Move tag to user data field (apparently designed for custom user tags)
    - Increase "arecords" array to 13
    - In the "EvaluateContents" function add:
          This.aRecords[tnFRXRecno,13] = toObjProperties.User
    - In the Render method, validate against aRecords[tnFRXRecno,13] for "<FJ>"

    I'm no expert either, it's just a thought.

    Regards

    Victor
    Hi Victor,
    This sounds very nice, and I agree to move the tag to the "USER" tab. I'll just wait some more time, to see if some more suggestions arise.
    Thanks very much !
    Saludos
    Cesar

    ReplyDelete
  2. Thank's Cesar, for your sample,

    I was waited this sample since long time,

    Thank's also to victor for your answer.
    (but the link UT report preview Custom is broken)

    I will making on in action your sample !

    Thank's
    Olivier
    Hi Olivier,
    The links seems to be working fine here... You can also enter UT directly: www.universalthread.com , go to the downloads section, and search for "Dorin Vasilescu".
    HTH[
    Cesar

    ReplyDelete
  3. Hi Cesar, I found a problem in my approach, maybe you can help. Somehow, the property "toObjProperties.User" in the "EvaluateContents" function does not pass along the values in the User field of the Report file. Thus, the Render procedure does not activate the Justification routine. I'm still working on a solution, your original code works perfect.


    Regards


    Victor

    ReplyDelete
  4. Hi Cesar, found a solution for the EvaluateContents problem, please disregard previous post and this one, I will post a corrected suggestion in a couple of minutes... for all to see  :)


    It is a pleasure to contribute to your Blog ...


    Thank you


    Victor


    ReplyDelete
  5. Hi Cesar, here is my updated suggestion. My original idea was sound, but flawed, in the sense that the "toObjProperties" object in the "EvaluateContents" function does not contain a property with the value of the "user" field in the report file. Thus, the validation in the Render method would never find the <FJ> tag.
    So here is my updated suggestion; I have tried it and is working properly now.

    - move the <FJ> tag to the "User" field (under "Other" tab of textbox properties)
     (this avoids affecting output when using alternate listener)

    - modify the BeforeReport method like so:
    FUNCTION BEFOREREPORT
      DODEFAULT()
      WITH This
         * Check if we already have the "System" object in "_Screen"
         IF NOT PEMSTATUS(_Screen,"System",5)
            _SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", locfile("system.vcx")))
         ENDIF
         .oGDIGraphics = _SCREEN.SYSTEM.Drawing.Graphics.New()
         .SetFRXDataSession()
         DIMENSION .aRecords[reccount(), 13]
         SCAN FOR "<FJ>" $ UPPER(User)
          .aRecords[recno(), 13] = "FJ"
         ENDSCAN      
         .ResetDataSession()
      ENDWITH
    ENDFUNC

    - In the Render method validate like so :
    IF VARTYPE(This.aRecords(tnFRXRecNo,13)) = "C" AND This.aRecords(tnFRXRecNo,13) == "FJ"

    Note: there is no need anymore to trim <FJ> tag from lcText variable

    Thank you for the chance to contribute to your excellent Blog....

    Regards

    Victor Espinoza
    Miami, FL
    Hi Victor,
    Thanks very much for the suggestions. Unfortunately, I'm out of town, at this moment, and without my working machine, so I did not test any of the suggestions. But this last makes a lot of sense. Have you tested the performance of both aproaches ?
    Regards
    Cesar 

    ReplyDelete
  6. Hi Victor,

    Thanks for the suggestions, it's working like a charm.

    I've just updated the post, with the full code.

    Thanks again

    Cesar

    ReplyDelete
  7. the FJ is functioning well. thank you.
    the problem of splitting text between pages is not sorted out.
    please look into and post at the arliest for community.
    Hi, sorry for the late answer...
    I don`t unsderstand what you mean, can you explain it better ? Maybe sending me some screenshots ?
    Thanks in advance
    Cesar

    ReplyDelete
  8. I have a program printing a daily report with about 20 lines that need to be full justified, the report is printing for 500 clients in one shot, vfp9 sp1. How much of a slowdown do you think it would be to include this listener to full justify the lettering.
    Hi, sorry for the late answer... :-(
    For sure this report will run slower using a listener. The full justify function is really extremely fast. You can try it using the full justify samples from the GdiPlusX library.
    I really don't know about how important the delay will be in a big report. I suggest you to make some tests, and tell us how it works for you. At this moment, for my own needs, it's working nice, and I didn`t notice a significant delay.
    Hope to hear from your tests soon!

    ReplyDelete
  9. sir I saw yor reply

    sorry I could not explain properly.

    The problem is the memo field having more lines of data running in to pages, while drawing the same on report from one page to next page. The data already rendered in the previous page is  repeating in the next page and truncating/ limiting the balance to be rendered.


    actually it has to render balance lines only on the subsequent pages till the data is complete.

    it needs additional handling which has been explained by BO Durban in his clear method of rendering RTF in reports without full justification.

    shortly i will send screen shots / movie for better understanding

    kindly pardon me i fail to explain my views.

    thanking you sir


    --ravisobhan

    ReplyDelete
  10. Thank's Cesar, for your sample, Great Cesar

    but ...

    I found bug in gdiplusx when i try use, SET ANSI ON, SET EXACT ON, SET NEAR ON the report cannot fulljustify. Then When I try Use Clear dlls, Error in xfcbrush (vcx error)

    ReplyDelete
  11. O exemplo de "justificar texto" corresponde ao que preciso. No entanto, tenho alguma dificuldade de traduzir todas as indicações de Inglês/Português.

    Será que era possível disponibilizá-lo já traduzido para Português e enviadi para o seguinte Email : fernando.p.mesquita@iol.pt

    ReplyDelete
  12. Alejandro FernándezMay 27, 2008 at 9:00 PM

    Cómo podría integrarlo con xfrx para convertir mi report a pdf pero con texto justificado de un campo memo del fichero pdf ?.

    Espero su ayuda. Gracias
    Hola,
    Desafortunadamentem nunca utilize XFRX. Pero convertir la grafica para una imagen es super simples ! Puedes salvar en un archiivo de imagen o entonces imprimir directamiente. Mire el codigo en el boton "Print" del formulario de ejemplo.
    Saludos !

    ReplyDelete
  13. I need so much this, plese if you can, post a full compiled project with this justifying option. Put it in an archive, please. because i tried to make this work, and i couldn't. i'm a beginner with FoxPro. Please help me.
    Please just follow the steps I provided here. If you face any problems, please tell me exactly what is not going well.

    ReplyDelete
  14. I have a form, an editbox and a button. I just want to enter some text in that editbox and when i press the button, i want to preview the report with that text from the editbox, full justified. that's all. can you help me? please
    Hi,
    I'm sorry, but this is not on the scope of this article. I suggest you to adapt the FRX and the PRG I used for this sample. You'll loose just some few minutes, and I'm sure you'll obtain the results you need.
    For more detailed information, you may try the Foxite forum, and ask the users directly: www.foxite.com;forum - it's free ! and one of the best VFP resources we have!
    Good luck !

    ReplyDelete
  15. Utilicé tu herramienta, me parece genial y ha funcionado sin problemas en los equipos clientes (HP, Compaq, Dell, Toshiba, Acer, Gateway), sin embargo se me presentó un problema en un equipo portatil HP Pavillion DV6420la AMD Turion 64 X2 Dual Core, con tarjeta gráfica NVIDIA GeForce Go 6150; al enviar la impresión no muestra la previsualización ni imprime. No sé que pueda estar pasando.

    Gracias por su ayuda.

    Eduardo Laguna
    Hola Eduardo,
    Sinceramente, no tengo ninguna idea de como ayudarle... El problema solo acontece con esta clase o tambien quando imprimes desde el generador de reportes convencional?
    Saludos
    Cesar

    ReplyDelete
  16. Good afternoon. I find television very educating. Every time somebody turns on the set, I go into the other room and read a book.

    I am from Luxembourg and also now am reading in English, please tell me right I wrote the following sentence: "Cheap air tickets available for new delhi, goa, bangalore, chennai, calcutta, air tickets available from bangalore hyderabad for rs."


    Thanks for the help :p, Onur.

    ReplyDelete
  17. I'm sure this is really nice, but unfortunately I cannot get it to work. I copied the code, including Victor's modifications.


    1.  I cannot locate "System.vcx"

    2.  If I use the "Function BeforeReport", the report runs bur the text is not modified. The vale in the expression field is a string, not a memo, but I don't think it should make a difference.  I set the ReportBehaviot to 90 and Listenertype to 0.


    Can I be missing somethin else.

    ReplyDelete
  18. Sorry. I menat to leave my email if someone needs it.

    mkatzla@juno.com

    ReplyDelete
  19. Sir,

    Is there any development on RTF text with full justification in reports?


    Yes, there is. Look for Bo Durban and For Mike Gagnon's articles regarding this on the web !

    ReplyDelete
  20. I found this article very good, but I have problem with my exe application. When I working in project everything is fine, but when I build exe, my report doesnt render. I include all files in project. Any suggestion?

    ReplyDelete