SIMPOL Documentation

Working with graphicreport1

The Graphic Report is extremely flexible in its design. The actual report is separate from the physical representation of its output. The graphicreport1 type contains a graphicreport1form type, which in turn contains a dring of graphicreport1formpage objects. The graphicreport1 type also incorporates the report1 type and is therefore similar to working with report1 as discussed previously. Unlike the quickreport1 type, however, this type is considerably more powerful and therefore also considerably more complex. It uses the printform1 type to provide templates for each area of the report. Each band of the report is defined as a page in the graphicreport1form. See Chapter 24, Using Data-Aware Print Forms in SIMPOL for more information about printform1.

The Graphic Report is a banded report system. That means that the components are broken up into bands, each the width of the page. The bands that are provided include:

Graphic Report Band Categories
  • Page header

  • Page footer

  • Body

  • Report header

  • Report footer

  • Group header

  • Group footer

None, some or all of these bands may be used (the group bands are for each group defined). When the report is run, it assembles the page from these bands. At the start of the report it will output the report header if it has been defined and at the beginning of each page it outputs the page header if that has been defined. Since it may be messy to have both on the same page, there is an option to suppress output of the page header on the first page. Following that, if there are any groups defined and there is a group header for the group, that will be output, then the body section of the report will be output until a group change, or the bottom of the page, (allowing for the page footer if it has been defined). Each page is then assembled as required until the end of the report is reached, at which point the report footer will be output followed by the page footer (this can also be suppressed on the last page). Each band is defined as a graphicreport1formpage that contains a printform1page object. Each of these pages has a specific naming format so that the engine will recognize them. These are also stored as constants in an includable SIMPOL source code file called graphicreporthdr.sma, but the list is as follows:

Graphic Report Band Page Names
  • "pageheader"

  • "pagefooter"

  • "body"

  • "reportheader"

  • "reportfooter"

  • "groupheader"

  • "groupfooter"

In turn, each page can contain any of the following content elements:

Graphic Report Page Elements
  • graphicreport1arc

  • graphicreport1ellipse

  • graphicreport1line

  • graphicreport1rectangle

  • graphicreport1triangle

  • graphicreport1formtext

  • graphicreport1formbitmap

Each of these contains a printform1 graphic or control of equivalent type. In the case of the graphics, there is little difference between them. The bitmap and text objects are different however, since they can be associated with a column value in the body page. In addition, the text objects can also be associated with an aggregate value in the group and report footers, or defined as a calculation using a system variable in the group header (for the GROUP items below), otherwise any of them can be used anywhere, though page headers and footers would be the most logical choice for most. The supported system variables include:

Graphic Report System Variables
  • PAGE – (returns the page number in the report formatted using the minimum characters (pure .tostr() call

  • TODAY – (returns the current date formatted using the default date format and date locale information as provided to the report

  • NOW – (returns the current time formatted using the default time format information as provided to the report

  • TIMESTAMP – (returns the current date and time formatted using the default datetime format and date locale information as provided to the report

  • COUNT – (returns either the count of rows in the report or the group, depending on the page)

  • GROUP – (returns the value of the current group)

  • GROUPNAME – (returns the name of the column for the current group)

  • GROUPINFO – (returns the name of the current group, followed by a colon and a space, and then the group's current value

Each item is placed on the page using print coordinates (to the nearest micrometer). Positioning is absolute, so if something is too close to an edge to be printed without being cropped, then it will be cropped.

When creating any of these controls, one of the arguments to each is an appropriate printform1control or printform1graphic object. In the case of the two form objects, they can each take a column number (which is based on the order of the select clause), in the colno parameter. Furthermore, the text control can also be assigned an aggregate type, or instead of a column number it can have a calculation assigned. Both of the form controls can also be assigned static values, a fixed bitmap or text value. All of this is handled in the graphicreport1form.addcontrol() method.

The easiest way to understand how to use the report is to make one:

            include "graphicreporthdr.sma"

function main()
  integer e, erridx, stdtexthgt
  string s, errmsg
  sbme1 sbmfile
  sbme1table address
  graphicreport1 gr
  wxfont font, font2, font3, font4
  report1group group
  dataform1datasource ds1
  graphicreport1formpage page
  graphicreport1formtext ptxt
  SBLlocaledateinfo datelocale
  SBLNumSettings numlocale

  e = 0
  sbmfile =@ sbme1.new("address.sbm", error=e)
  if sbmfile =@= .nul
    s = "Error number " + .tostr(e, 10) + " opening \
         ""address.sbm""{d}{a}"
  else
    address =@ sbmfile.opentable("Address", \
       recordidfieldname="recid_ro_internal", error=e)
            
    if address =@= .nul
      s = "Error number " + .tostr(e, 10) + " opening the \
           ""Address"" table{d}{a}"
    else
      datelocale =@ SBLlocaledateinfo.new(format="dd/mm/yy")
      numlocale =@ SBLNumSettings.new("£", ",", ".", .false)
      stdtexthgt = 4900
      errmsg = ""
      erridx = 0
      font =@ wxfont.new("Arial Narrow", 10, "n", "n", "", error=e)
      font2 =@ wxfont.new("Arial Narrow", 10, "n", "b", "",error=e)
      font4 =@ wxfont.new("Arial Narrow", 13, "n", "b", "",error=e)
      font3 =@ wxfont.new("Arial", 14, "n", "b", "", error=e)
      gr =@ graphicreport1.new(paperwidth=210000, \
            paperheight=297000, outputtarget=GR_OUTPUTWINDOW, \
            title="Address List", datelocale=datelocale, \
            numlocale=numlocale, error=e)
      gr.reportform.wrapkludgevalue = .toval("1.15", .nul, 10)
      gr.reportform.fontresizekludgevalue = .toval("0.7", .nul, 10)
      gr.reportform.wrapcharcountkludgevalue = .toval("1", .nul,10)
      gr.usewrapheight2 = .true

      gr.setselectclause("AddressID, FirstNames, Surname, City, \
                          CountryCode", errmsg, erridx)
      gr.setwhereclause("", errmsg, erridx)
      gr.setorderclause("City, Surname")
      ds1 =@ gr.adddatasource(sbmfile, "address.sbm", error=e)
      gr.addtable(address, ds1, error=e)

      // Body Page
      page =@ gr.addpage(210000, 600 + stdtexthgt, 0xffffff, \
              name=sGR_BODY, error=e)
      gr.addcontrol(graphicreport1formtext, printleft=20000, \
            printtop=300, printwidth=12000, \
            printheight=stdtexthgt, printalignment="right,top", \
            font=font, printname="tbAddressID", page=page, \
            colno=1, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=34000, \
            printtop=300, printwidth=50000, \
            printheight=stdtexthgt, font=font, \
            printname="tbFirstNames", page=page, colno=2, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=86000, \
            printtop=300, printwidth=50000, \
            printheight=stdtexthgt, font=font, \
            printname="tbSurname", page=page, colno=3, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=138000, \
            printtop=300, printwidth=50000, \
            printheight=stdtexthgt, font=font, \
            printname="tbCity", page=page, colno=4, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=190000, \
            printtop=300, printwidth=12000, \
            printheight=stdtexthgt, font=font, \
            printname="tbCountryCode", page=page, colno=5, error=e) 

      // Page Header
      page =@ gr.addpage(210000, 16320 + stdtexthgt, 0xffffff, \
            name=sGR_PAGEHEADER, error=e)
      gr.addcontrol(graphicreport1formtext, printleft=50000, \
            printtop=6000, printwidth=110000, printheight=8200, \
            printalignment="", text="Address List", font=font3, \
            printname="lPageTitle", page=page, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=20000, \
            printtop=16000, printwidth=12000, \
            printheight=stdtexthgt, printalignment="right,top", \
            text="Addr ID", font=font2, printname="lAddressID", \
            page=page, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=34000, \
            printtop=16000, printwidth=50000, \
            printheight=stdtexthgt, text="First Names", \
            font=font2, printname="lFirstNames", page=page, \
            error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=86000, \
            printtop=16000, printwidth=50000, \
            printheight=stdtexthgt, text="Surname", font=font2, \
            printname="lSurname", page=page, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=138000, \
            printtop=16000, printwidth=50000, \
            printheight=stdtexthgt, text="City", font=font2, \
            printname="lCity", page=page, error=e) 
      gr.addcontrol(graphicreport1formtext, printleft=190000, \
            printtop=16000, printwidth=12000, \
            printheight=stdtexthgt, text="Ctry", font=font2, \
            printname="lCountryCode", page=page, error=e) 
      gr.addgraphic(graphicreport1line, point.new(20000, \
            16300 + stdtexthgt), point.new(202000, 16300 + \
            stdtexthgt), width=100, printname="lBorder", page=page, \
            error=e)

      // Page Footer
      page =@ gr.addpage(210000, 9000 + STDTEXTHGT, 0xffffff, \
            name=sGR_PAGEFOOTER, error=e)
      gr.addgraphic(graphicreport1line, point.new(20000, 1000), \
            point.new(190000, 1000), width=100, \
            printname="lBorderFooter", page=page, error=e)
      ptxt =@ gr.addcontrol(graphicreport1formtext, \
            printleft=98000, printtop=3000, printwidth=14000, \
            printheight=stdtexthgt, printalignment="", text="", \
            font=font2, printname="lPageNo", page=page, error=e) 
      if ptxt !@= .nul
        ptxt.calculation = "PAGE"
      end if

      group =@ gr.addgroup("City", 4, string, error=e)
      if group !@= .nul
        gr.addaggregate(group, GR_AGG_COUNT, .nul, integer,error=e)
      end if

      // Group Header
      page =@ gr.addpage(210000, 12000, 0xffffff, \
            name=sGR_GROUPHEADER, group=group, error=e)
      if page !@= .nul
        ptxt =@ gr.addcontrol(graphicreport1formtext, \
                printleft=20000, printtop=5000, printwidth=30000, \
                printheight=integer.new(stdtexthgt * (135/100)), \
                printalignment="left,top", text="", font=font4, \
                printname="lGroupname", page=page, error=e) 
        if ptxt !@= .nul
          ptxt.calculation = "GROUPINFO"
        end if
      end if

      // Group Footer
      page =@ gr.addpage(210000, 8500, 0xffffff, \
              name=sGR_GROUPFOOTER, group=group, error=e)
      if page !@= .nul
        ptxt =@ gr.addcontrol(graphicreport1formtext, \
            printleft=20000, printtop=2000, printwidth=30000, \
            printheight=integer.new(stdtexthgt * (135/100)), \
            printalignment="left,top", text="", font=font4, \
            printname="lGroupcount", page=page, error=e) 
        if ptxt !@= .nul
          ptxt.calculation = "COUNT entries"
        end if
      end if

      gr.addaggregate(.nul, GR_AGG_COUNT, .nul, integer, error=e)

//      savegraphicreport(gr, "addresslist.sxr", error=e)
//      gr =@ loadgraphicreport("addresslist.sxr", error=e, \\
//            errortext=errmsg)

      gr.startat100percent = .true
      gr.centeroverdisplay = .true

      e = 0
      gr.run(errmsg, erridx, error=e)
      if not (errmsg > "" or e != 0)
        wxprocess(20000000)
        s = "Success!{d}{a}"
      else
        if errmsg > ""
          s = errmsg + "{d}{a}"
        else
          s = "Error number " + .tostr(e, 10) + \
              " running report{d}{a}"
        end if
      end if
    end if
  end if
end function s
        

As can be seen from the preceding code, there is a lot more involved in creating a Graphic Report than there is for a Quick Report, but the difference is in the amount of control over the resulting look of the report. Just as with the Quick Report, the initial stages of creating a Graphic Report consists of opening the data source(s) and table(s), creating the graphicreport1 object, and setting the select, where, and order clauses. In addition, the fonts that will be used are created, and there is a set of properties that are related to the "wrap" functionality that can be set. These occasionally need tweaking to get the best results. Like with the Quick Report, only add the "wrap" capability if it is required, since it adds considerable processing overhead to each time a control that uses it is output. Two of the arguments passed to the new() method of the graphicreport1 are the pagewidth and the pageheight parameters. The ones used in the example are for A4 paper. The US Letter paper size is: 215900 x 279400.

Once the standard tasks have been dealt with, the various page bands are added, each with the controls that are required. Interestingly, just because a column is in the select statement does not mean that it will appear in the report. Unless it is associated with a control in the body page, there will no output for that column. This is useful when it is necessary to retrieve extra column information for use in report or group footers. Also, to do a summarization, it is only necessary to not define the body page.

If the level of control that is available in the basic design is still not enough, at the point of outputting a page chunk onto the final output page, there is an onoutput event for each page that can be used to call the programmer's code. A different function should be assigned for each unique band or graphicreport1formpage object. The various function prototypes for the types of pages are as follows.

Table 25.1. onoutput Function Prototypes
Band TypeFunction Prototype
Body band
onoutput_handler(page,  
 pagechunk,  
 report,  
 reportinst,  
 columns,  
 currcolvalues,  
 reference); 
graphicreport1formpage page;
printform1page pagechunk;
report1 report;
report1inst reportinst;
array columns;
array currcolvalues;
type(*) reference;
 
Page header and footer, report header and footer
onoutput_handler(page,  
 pagechunk,  
 report,  
 reportinst,  
 reference); 
graphicreport1formpage page;
printform1page pagechunk;
report1 report;
report1inst reportinst;
type(*) reference;
 
Group header and footer
onoutput_handler(page,  
 pagechunk,  
 group,  
 groupinst,  
 reference); 
graphicreport1formpage page;
printform1page pagechunk;
report1group group;
report1groupinst groupinst;
type(*) reference;
 


At the point where this is called, all of the data and calculations have been done, and the resulting output can still be manipulated by the programmer. For example, in the body, if the total of a row is negative, the foreground color could be changed to red. This change only affects the current output chunk, not the template, so it needn't be reversed for rows that are positive. The names of the controls on the pagechunk will be the same as on the template, making it easy to address thae various controls. As was the case with the Quick Report example, there are two commented lines of code that save and then load the Graphic Report. The default file extension for SIMPOL Graphic Reports is .sxr.