Subject Re: Report group headers
From Mervyn Bick <invalid@invalid.invalid>
Date Wed, 3 Jan 2024 11:56:06 +0200
Newsgroups dbase.getting-started
Attachment(s) report_tree1.pdfcollection.rep

On 2023/12/31 23:16, Mervyn Bick wrote:

> I can't run your report without the two tables (collection and category)
> so it would help if you post them here.  If you don't want to make the
> tables generally available perhaps you would email them to me at
>
> bickmeo at gmail dot com
>
> I did, however, notice one potential problem.  The rowset must be
> ordered primarily by the field used in the group1 groupBy property. This
> field is 'category'  but the rowset is ordered by ordr,sku   You should
> change that to ... order by category,ordr,sku

I assumed that the grouping was by category in alphabetical order.  Now
that I've seen the tables I realise you have added a field to the
category table to present the categories in priority order.  This means
that the JOINed rowset is correctly ordered by ordr,sku.  In as much as
ordr and category are paired in records it doesn't really matter which
of the two is used in the group's groupBy property.

The "missing rowset" message came about because you used the
reportgroup's footerband onRender event, which is only triggered once at
the end of the report, instead of the group1 footerband onRender event
to trigger the footerband_onRender event handler.

In the case of the group1 footerband, this.parent.parent is
streamsource1 which does have the rowset as a property.  In the case of
the reportgroup footerband, this.parent.parent is the form which does
not have the rowset as a property resulting in oStream.rowset causing an
error.

Attached is report_tree1.pdf which I use to help trace the parentage of
objects when I need to move data from one object to another.

You used the <H3> and </H3> HTML tags to format the text for the
category name.  I couldn't get Ken's code to add (Continued..) to the
category name when the group1 headerband was repeated on a new page.  I
removed the HTML tags and used the text object's fontsize and fontbold
properties to achieve the same "look" and now the (Continued..) works as
expected.  I've added code to display at the bottom of the page if a
group carries over to a new page.

The method of looping through the rowset to count the number of records
in a group had a problem where the group headerband was repeated at the
top of a new page by giving a false value for the next group.  Instead
of trying to fix the code I abandoned it and added a parameter driven
query to count the records.  Apart from being a simpler method, it also
allows the number of items in a category to be easily displayed in the
group headerband.  You can, of course, remove the additional text from
the headerband if you don't want it there.

I've commented out the code in the FOOTERBAND_onRender event handler to
start a group on a new page if there isn't enough space left on a page
for the entire group.  The code increases the report length from 5 to 7
pages and leaves a LOT of white space on some pages.  The code is,
however, clearly marked so you can uncomment it if you wish.

Mervyn.


** END HEADER -- do not remove this line
//
// Generated on 2024-01-03
//
local r
r = new COLLECTIONREPORT()
r.render()

class COLLECTIONREPORT of REPORT
   set procedure to :ReportControls:REPORT.Co additive
   with (this)
      title = "Collection"
      metric = 3        // Inches
      autoSort = false
   endwith

   this.COINDATA1 = new DATABASE(this)
   with (this.COINDATA1)
      databaseName = "COINDATA"
      active= true
   endwith

   this.COUNT_CAT1 = new QUERY(this)
   with (this.COUNT_CAT1)
      left = 4.0
      database = form.coindata1
      sql = "select count(*) from collection where category = :category"
      params["category"] = ""
      active = true
   endwith

   this.CATEGORY1 = new QUERY(this)
   with (this.CATEGORY1)
      left = 4.0
      database = form.coindata1
      sql = "select * from collection inner join category on collection.category = category.cat order by ordr,sku"
      requestLive = false
      active = true
   endwith

   this.STREAMSOURCE1 = new STREAMSOURCE(this)
   this.STREAMSOURCE1.GROUP1 = new GROUP(this.STREAMSOURCE1)
   with (this.STREAMSOURCE1.GROUP1)
      groupBy = "ORDR"
      headerEveryFrame = true
   endwith

   with (this.STREAMSOURCE1.GROUP1.footerBand)
      onRender = class::FOOTERBAND_ONRENDER
   endwith

   with (this.STREAMSOURCE1.GROUP1.headerBand)
      preRender = class::HEADERBAND_PRERENDER
      onRender = class::HEADERBAND_ONRENDER
      height = 0.35
   endwith

   this.STREAMSOURCE1.GROUP1.headerBand.LINE1 = new LINE(this.STREAMSOURCE1.GROUP1.headerBand)
   with (this.STREAMSOURCE1.GROUP1.headerBand.LINE1)
      canRender = {||this.parent.context == 0}
      left = 0.0
      right = 6.5
      top = 0.0729
      bottom = 0.0729
      width = 1
   endwith

   this.STREAMSOURCE1.GROUP1.headerBand.TEXT1 = new TEXT(this.STREAMSOURCE1.GROUP1.headerBand)
   with (this.STREAMSOURCE1.GROUP1.headerBand.TEXT1)
      height = 0.2083
      left = 0.0
      top = 0.1354
      width = 0.8438
      prefixEnable = false
      colorNormal = "b+"
      text = "<H3>Category :</H3>"
   endwith

   this.STREAMSOURCE1.GROUP1.headerBand.TEXT2 = new TEXT(this.STREAMSOURCE1.GROUP1.headerBand)
   with (this.STREAMSOURCE1.GROUP1.headerBand.TEXT2)
      height = 0.2083
      left = 0.8958
      top = 0.1354
      width = 2.7813
      prefixEnable = false
      colorNormal = "b+"
      fontSize = 11.0
      fontBold = true
      text = {||this.parent.parent.parent.rowset.fields["CATEGORY"].value}
   endwith

   this.STREAMSOURCE1.GROUP1.headerBand.TEXT3 = new TEXT(this.STREAMSOURCE1.GROUP1.headerBand)
   with (this.STREAMSOURCE1.GROUP1.headerBand.TEXT3)
      canRender = class::TEXT3_CANRENDER
      height = 0.2083
      left = 3.8229
      top = 0.1354
      width = 0.5
      prefixEnable = false
      colorNormal = "b+"
      fontSize = 11.0
      text = "Items :"
   endwith

   this.STREAMSOURCE1.GROUP1.headerBand.TEXT4 = new TEXT(this.STREAMSOURCE1.GROUP1.headerBand)
   with (this.STREAMSOURCE1.GROUP1.headerBand.TEXT4)
      canRender = class::TEXT4_CANRENDER
      height = 0.2083
      left = 4.3438
      top = 0.1354
      width = 0.75
      prefixEnable = false
      colorNormal = "b+"
      fontSize = 11.0
      text = "Text4"
   endwith

   with (this.STREAMSOURCE1.detailBand)
      height = 0.1729
   endwith

   this.STREAMSOURCE1.detailBand.TITLETEXTID1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TITLETEXTID1)
      canRender = {||this.parent.firstOnFrame}
      height = 0.22
      left = 0.0
      top = 0.0
      width = 0.6146
      prefixEnable = false
      suppressIfBlank = true
      fontSize = 9.0
      text = "<H3>Date/Id</H3>"
   endwith

   this.STREAMSOURCE1.detailBand.TEXTID1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TEXTID1)
      height = 0.0
      left = 0.0
      top = 0.22
      width = 0.85
      variableHeight = true
      prefixEnable = false
      fontSize = 9.0
      text = {||this.form.CATEGORY1.rowset.fields["ID"].value}
   endwith

   this.STREAMSOURCE1.detailBand.TITLETEXTGRADE1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TITLETEXTGRADE1)
      canRender = {||this.parent.firstOnFrame}
      height = 0.22
      left = 0.91
      top = 0.0
      width = 0.6146
      prefixEnable = false
      suppressIfBlank = true
      fontSize = 9.0
      text = "<H3>Grade</H3>"
   endwith

   this.STREAMSOURCE1.detailBand.TEXTGRADE1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TEXTGRADE1)
      height = 0.0
      left = 0.91
      top = 0.22
      width = 0.6146
      variableHeight = true
      prefixEnable = false
      fontSize = 9.0
      text = {||this.form.CATEGORY1.rowset.fields["GRADE"].value}
   endwith

   this.STREAMSOURCE1.detailBand.TITLETEXTBDATE1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TITLETEXTBDATE1)
      canRender = {||this.parent.firstOnFrame}
      height = 0.22
      left = 1.73
      top = 0.0
      width = 0.9375
      prefixEnable = false
      suppressIfBlank = true
      fontSize = 9.0
      text = "<H3>Bdate</H3>"
   endwith

   this.STREAMSOURCE1.detailBand.TEXTBDATE1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TEXTBDATE1)
      height = 0.0
      left = 1.73
      top = 0.22
      width = 0.9375
      variableHeight = true
      prefixEnable = false
      fontSize = 9.0
      text = {||this.form.CATEGORY1.rowset.fields["BDATE"].value}
   endwith

   this.STREAMSOURCE1.detailBand.TITLETEXTQTY1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TITLETEXTQTY1)
      canRender = {||this.parent.firstOnFrame}
      height = 0.22
      left = 2.8
      top = 0.0
      width = 0.4375
      prefixEnable = false
      alignHorizontal = 1        // Center
      suppressIfBlank = true
      fontSize = 9.0
      text = "<H3>Qty</H3>"
   endwith

   this.STREAMSOURCE1.detailBand.TEXTQTY1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TEXTQTY1)
      height = 0.0
      left = 2.8
      top = 0.22
      width = 0.4896
      variableHeight = true
      prefixEnable = false
      fontSize = 9.0
      text = {||this.form.CATEGORY1.rowset.fields["QTY"].value}
   endwith

   this.STREAMSOURCE1.detailBand.TITLETEXTESTV1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TITLETEXTESTV1)
      canRender = {||this.parent.firstOnFrame}
      height = 0.22
      left = 3.43
      top = 0.0
      width = 0.625
      prefixEnable = false
      alignHorizontal = 2        // Right
      suppressIfBlank = true
      fontSize = 9.0
      text = "<h3>Est Val</h3>"
   endwith

   this.STREAMSOURCE1.detailBand.TEXTESTV1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TEXTESTV1)
      height = 0.0
      left = 3.43
      top = 0.22
      width = 0.6875
      variableHeight = true
      prefixEnable = false
      alignHorizontal = 2        // Right
      fontSize = 9.0
      text = {||this.form.CATEGORY1.rowset.fields["ESTV"].value}
   endwith

   this.STREAMSOURCE1.detailBand.TITLETEXTDETAILS1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TITLETEXTDETAILS1)
      canRender = {||this.parent.firstOnFrame}
      height = 0.22
      left = 4.2
      top = 0.0
      width = 1.0
      prefixEnable = false
      suppressIfBlank = true
      fontSize = 9.0
      text = "<H3>Notes</H3>"
   endwith

   this.STREAMSOURCE1.detailBand.TEXTDETAILS1 = new TEXT(this.STREAMSOURCE1.detailBand)
   with (this.STREAMSOURCE1.detailBand.TEXTDETAILS1)
      height = 0.0
      left = 4.2
      top = 0.22
      width = 3.25
      variableHeight = true
      prefixEnable = false
      fontSize = 9.0
      text = {||this.form.CATEGORY1.rowset.fields["DETAILS"].value}
   endwith

   with (this.printer)
      duplex = 1        // None
      orientation = 1        // Portrait
      paperSource = 15
      paperSize = 1
      resolution = 0        // Default
      color = 2        // Color
      trueTypeFonts = 3        // Substitute
   endwith

   this.PAGETEMPLATE1 = new PAGETEMPLATE(this)
   with (this.PAGETEMPLATE1)
      height = 11.0
      width = 8.5
      marginTop = 0.1
      marginLeft = 0.0
      marginBottom = 0.1
      marginRight = 2.7875
      gridLineWidth = 0
   endwith

   this.PAGETEMPLATE1.STREAMFRAME1 = new STREAMFRAME(this.PAGETEMPLATE1)
   with (this.PAGETEMPLATE1.STREAMFRAME1)
      height = 9.0
      left = 0.3958
      top = 0.8958
      width = 7.5
      form.STREAMFRAME1 = form.pagetemplate1.streamframe1
   endwith

   this.PAGETEMPLATE1.TEXT1 = new TEXT(this.PAGETEMPLATE1)
   with (this.PAGETEMPLATE1.TEXT1)
      height = 0.3646
      left = 0.6146
      top = 0.1354
      width = 2.9896
      prefixEnable = false
      text = "<h1>My Collection</h1>"
      form.TEXT1 = form.pagetemplate1.text1
   endwith

   this.PAGETEMPLATE1.TEXT2 = new TEXT(this.PAGETEMPLATE1)
   with (this.PAGETEMPLATE1.TEXT2)
      height = 0.1563
      left = 0.61
      top = 0.57
      width = 2.1458
      prefixEnable = false
      text = {||Date()}
      form.TEXT2 = form.pagetemplate1.text2
   endwith

   this.PAGETEMPLATE1.PAGENUMBER1 = new PAGENUMBER(this.PAGETEMPLATE1)
   with (this.PAGETEMPLATE1.PAGENUMBER1)
      height = 0.3958
      left = 4.0624
      top = 10.198
      width = 0.3854
      alignVertical = 0        // Top
      alignHorizontal = 1        // Center
      fontSize = 10.0
      form.PAGENUMBER1 = form.pagetemplate1.pagenumber1
   endwith

   this.PAGETEMPLATE1.TEXT3 = new TEXT(this.PAGETEMPLATE1)
   with (this.PAGETEMPLATE1.TEXT3)
      height = 0.2083
      left = 0.6979
      top = 10.0417
      width = 3.7396
      prefixEnable = false
      colorNormal = "b+"
      text = "Text3"
      form.TEXT3 = form.pagetemplate1.text3
   endwith

   with (this.reportGroup.footerBand)
      height = 0.0
   endwith

   with (this.reportGroup.headerBand)
      expandable = true
      height = 0.0
      beginNewFrame = true
   endwith

   this.firstPageTemplate = this.form.pagetemplate1
   this.form.pagetemplate1.nextPageTemplate = this.form.pagetemplate1
   this.form.pagetemplate1.streamframe1.streamSource = this.form.streamsource1
   this.form.streamsource1.rowset = this.form.category1.rowset

   function FOOTERBAND_onRender()  
           local oStream, nCount, nSpaceRemaining, nSpaceNeeded,cNextCategory
      oStream = this.parent.parent
      oStream.rowset.next() //Next record so we can get category for next group
      cNextCategory = oStream.rowset.fields["category"].value
      nCount = 0
      if not oStream.rowset.endofset
         this.parent.parent.parent.count_cat1.params['category'] = oStream.rowset.fields["category"].value
         this.parent.parent.parent.count_cat1.requery()
         nCount = this.parent.parent.parent.count_cat1.rowset.fields[1].value
      endif
      oStream.rowset.next(-1) //Back to last record of previous group so that report can continue where it left off      
      nSpaceRemaining = this.streamframe.height - this.renderOffset
      nSpaceNeeded =  0.39+(nCount*0.21)  //space for header, footer (which is 0) and rows

      //Uncomment the following section to force groups that are too long to fit in the
      //space available to start on a new page
      *--------------------
//            if nSpaceRemaining < nSpaceNeeded
//               this.parent.headerband.beginNewframe := true
//            else
//               this.parent.headerband.beginNewframe := false
//            endif
      *--------------------
                return


   function HEADERBAND_onRender()
      local nSpaceRemaining,nSpaceNeeded
      //Copy & paste direct from Ken's dBASE Reports book.
      *--------
         f = this.parent.parent.rowset.fields
         this.BreakField = f["category"].value.rightTrim()
         this.text2.text = {||this.parent.parent.parent.rowset.fields["CATEGORY"].value }
      *-------
      //Display notice at bottom of page if group continues on next page
      nSpaceRemaining = this.streamframe.height - this.renderOffset
      nSpaceNeeded =  this.count*0.21  //header has already been rendered  so space for footer (which is 0) and rows
      if nSpaceNeeded > nSpaceRemaining
         this.parent.parent.parent.pagetemplate1.text3.text = ;
            this.BreakField + ' continued on next page'
      else
         this.parent.parent.parent.pagetemplate1.text3.text = ''
       endif  
      return

   function HEADERBAND_preRender()
      local oStream
      //Count records in group for display on headerband
      oStream = this.parent.parent
      this.parent.parent.parent.count_cat1.params['category'] = oStream.rowset.fields["category"].value
      this.parent.parent.parent.count_cat1.requery()
      this.count = this.parent.parent.parent.count_cat1.rowset.fields[1].value
      this.text4.text = ltrim(this.count+'')  //Convert to text then left trim for better alignment
      
      //Copy & paste direct from Ken's dBASE Reports book to add (Continued..) to categrory name
      // check to see if custom property exists, if not create it:
      if type( "this.BreakField" ) == "U"
      this.BreakField = "XXX" // value not in table
      endif
      // this = headerBand
      // parent = group1
      // parent = streamSource1
      f = this.parent.parent.rowset.fields
      this.Text2.text := f["category"].value.rightTrim()
      if this.BreakField == f["category"].value.rightTrim()
      // add extra text: the word<
      // "(Continued ...)" in italics
      this.Text2.text += " <i>(Continued ...)</i>"
      this.count = 0  //Set to 0 so that if group is continued on next page
                             //the onRender event handler doesn't set set the Continued
                            //notice at the bottom of the new page.                            
      endif
      return

   function TEXT3_canRender()
      local lRet
      if 'Continued'$this.parent.text2.text
         lRet = false
      else
         lRet = true
      endif
      return lRet


   function TEXT4_canRender()
      local lRet
      if 'Continued'$this.parent.text2.text
         lRet = false
      else
         lRet = true
      endif
      return lRet

endclass