HOME
Login
Change Info
Logout


TUTORIALS

C, C++
Win32
Java
Visual Basic
MFC
DCOM
Networking
C#
Perl
HTML
XML
ASP
PHP
Javascript
Other

DOWNLOADS
ITCLib
SourceVizor meets the notification, reporting, and admin needs of teams using Microsoft Visual SourceSafe.
Free 30-day trial!


Preventing Widowed Group Headers in Crystal Reports

by Russell VanBlon

Questions, comments, suggestions - We want to hear from you!Comment on this article Get the Acrobat PDF File For This Article Get Adobe Acrobat Reader
Most downloads under 500KB


Problem:

This article will explain how to prevent widowed group headers and footers from appearing in Crystal Reports. The knowledge base at http://support.crystaldecisions.com/ attempts to provide a solution for this problem in articles C2000972 and C2000973. However, these articles describe how to prevent widowed headers OR widowed footers, not both together, which is what is really needed in a report. Article C2005815 describes a method similar to what is described here by counting lines in a report, but again, it only applies to widowed headers. This article will show you how to modify any report to prevent widowed headers and widowed footers from being printed.

What are Widowed Group Headers and Widowed Group Footers?

Sometimes, when a report prints, new groups begin near the bottom of a page. This causes the group header to appear at the bottom of the page with no details. The details associated with that group header then print on the next page. This is known as a “widowed” group header or “orphaned” group header.

Similarly, there could be just enough room on a page to print the details, causing the group footer to print at the top of the next page with no associated details. This is a “widowed” group footer.

Crystal Reports has an option called ‘Keep Group Together’ that prevents headers and footers from printing in this manner. However, when groups are printed with more than a couple of lines of detail, a large amount of whitespace will appear since this option moves the entire group to the next page instead of moving only one detail line. The solution below will guide you through the process of modifying your report to print at least one detail line for every group header and footer.

Prior Solution Attempts:

The method used on Crystal’s knowledge base to solve this problem involved adding sections to the group header or footer and copying the details into these extra sections. They wrote two different articles, the first fixed widowed headers, and the other widowed footers. If you go through the steps in both articles so as to fix both problems at once, a problem arises which only occurs when you have a group with one line of detail at the bottom of a page. The articles also only apply to reports with a single group. So if you have multiple layered groups, you’re out of luck with their solution.

In the Crystal Reports designer, there is an option called “Keep Group Together”. This option works great with only one problem. If you have large groups, they will often be pushed to the next page entirely, leaving large amounts of white space in the report. For those of us who need our reports to appear professional, this doesn’t cut it either.

Solution:

From here on, it is assumed that you have a basic familiarity with Crystal Reports designer. There are two reports you can download to aid you in fixing your own report. One is called Generic Report, the other is that same report which includes the fixes so that it has no widowed headers or footers. All the example reports and the database used by these reports can be downloaded from this link: crystalreports_widow.zip You should extract the contents of the zip file to the directory: c:\crystalreports_widow. The zip file contains these files:

  • Generic Report.rpt
  • Generic Report - Fixed - 1 Layer.rpt
  • Generic Report - Fixed - 2 Layers.rpt
  • Generic Report - Fixed - 3 Layers.rpt
  • Generic Report - Fixed - 4 Layers.rpt
  • Reports.mdb

In order to rid a report of widowed headers and footers, we need to know how many lines can fit on a page. To do that, you will need to take a few minutes to set up your report.

First, make sure you have the “Snap To Grid” checkbox turned on in the File|Options dialog. You need to set the height of all sections in your report, and this is much easier with this option turned on. Notice that when you turn on this option, and you drag a vertical “tab” in the report designer up or down, the tab moves a uniform distance as you move it. This uniform distance between tab movements is one twelfth of an inch. The “tabs” referred to here are shown in the following screenshot, circled in red.

Tabs

Now, to find out how many lines will fit on a page, all section heights have to be a constant size. This is where the tabs help us. Set each section of your report to a constant height using the tabs. Some guidelines to follow when doing this are:

  • Select a height for all sections, measured in twelfths of an inch or “tabs”. Remember that 1/12 inch is equal to one unit of tab movement. The height for most report sections will be 2 or 3 units. A height of 3 is used in “Generic Report – Fixed – 1 Layer.rpt”.
  • For sections of your report that need to be greater than this, choose a height that is a multiple of the first number. For example, if you use a height of 3 and some sections won’t fit in that much space, use a height of 6, 9, 12, etc. for the larger sections.
  • Every section of your report should be sized in this manner unless it is a page header, page footer or any section that is always hidden or suppressed.

In “Generic Report – Fixed – 3 Layers.rpt”, a predetermined height of 3 units was chosen for the detail section and report footer. The group headers and footers in this report were set to a height of 6 units. The three sections in this report that are not sized like this are the page header, page footer, and report header since it is hidden.

The following movie clips give an example of how the sizing is done. There is a lot of emphasis on sizing your report sections here because it is very important that it is done right in your report for the next steps to work correctly. Observe in the movie clips that once the tabs are set to the correct height, the lower bar of each section is moved up as far as possible, which leaves only half of the tab viewable once it is in place.

Resize Details

Resize Headers

Once the sections of your report are sized like they should be, you need to know how many lines will fit on each page of your report. To do that, create a formula to count the lines:


@CountLines+1

WhilePrintingRecords;
NumberVar CountLines := CountLines + 1

If certain sections take up more space than another section you need to create a separate formula for that section. For example, if the Group Footer is twice the height of the Details section, create this formula:


@CountLines+2

WhilePrintingRecords;
NumberVar CountLines := CountLines + 2

Place the @CountLines+x formulas in each corresponding section of your report, depending on the section height you chose for each section when sizing them.

Create another formula to reset the counter for each page:


@ResetCountLines

WhilePrintingRecords;
NumberVar CountLines := 0

Place this counter in the Page Header section. This ensures that line counting returns to 0 at the beginning of each page.

Make sure you don’t have the “Keep Group Together” (found under Report | Change Group Expert | Options) option turned on for any group. With these formulas in place, you should be able to preview your report and see line numbers. The last line number you see on your report is how many lines can fit on a page. Make a note of this number.

The rest of the necessary formulas will now be discussed. Your report formulas will vary, depending on how many layered subgroups you have, the height of your groups, as well as the name of your database fields. Please note that the formulas about to be described are for reports that have 3 layered groups.

Insert the following formula into the Page Header Section:


@CounterConstants

BeforeReadingRecords;

NumberVar TotalLinesInReport := 37;

NumberVar GH1Height := 2;
NumberVar GH4Height := 2;
NumberVar GH4Height := 2;
NumberVar DetailHeight := 1;
NumberVar GF3Height := 2;
NumberVar GF2Height := 2;
NumberVar GF1Height := 2;
NumberVar ReportFooterHeight := 1;

NumberVar LinesRequiredInGroup1ForSingleDetailLine :=
   GH1Height + GH4Height + GH4Height + DetailHeight +
   GF3Height;
NumberVar LinesRequiredInGroup1ForManyDetailLines :=
   GH1Height + GH4Height + GH4Height + DetailHeight;
NumberVar LinesRequiredInGroup2ForSingleDetailLine :=
   GH4Height + GH4Height + DetailHeight + GF3Height;
NumberVar LinesRequiredInGroup2ForManyDetailLines :=
   GH4Height + GH4Height + DetailHeight;
NumberVar LinesRequiredInGroup3ForSingleDetailLine :=
   GH4Height + DetailHeight + GF3Height;
NumberVar LinesRequiredInGroup3ForManyDetailLines :=
   GH4Height + DetailHeight;
NumberVar LinesRequiredInDetailsForLastDetail :=
   DetailHeight + GF3Height;

This formula contains constants used by other formulas in the report. For “Generic Report.rpt”, the total lines was found to be 37, seen above. This means that 37 lines, each with a height of 3 twelfths of an inch, can fit on each page. The height of sections in the report are set according to how they were sized. This height is 2 for the group headers and footers, and 1 for the detail section. Also notice that each group requires a different number of lines, depending on how many detail lines are left to print. This is because a group with a single detail line will require enough room on the page for the group header, detail, and footer which follows, where a group with more than one detail line only requires room for the group header and one line of detail.

Also insert this formula into the Page Header Section.


@CounterVariables

BeforeReadingRecords;
NumberVar TotalRecordsPrinted := 0;
NumberVar Group1DetailsPrinted := 0;
NumberVar Group2DetailsPrinted := 0;
NumberVar Group3DetailsPrinted := 0;
NumberVar LinesRequired := 0;

These are counters used for each section of the report.

The next formula also goes in the Page Header Section:


@InitReportLines

WhilePrintingRecords;
NumberVar ReportRecordsTotal := count
   ({SimpleData.CategoryC});

This formula counts the total number of lines in the report. It is only needed if you use the report footer section.

Insert the following formula in Group Header #1:


@InitGroup1Lines

WhilePrintingRecords;
NumberVar Group1DetailsTotal :=
   count({SimpleData.CategoryC},
      {SimpleData.CategoryA});

Insert the following formula in Group Header #2:


@InitGroup2Lines

WhilePrintingRecords;
NumberVar Group2DetailsTotal :=
   count({SimpleData.CategoryC},
      {SimpleData.CategoryB});

Insert the following formula in Group Header #1, Group Header #2 and Group Header #3 (i.e. in ALL Group Header sections):


@InitGroup3Lines

WhilePrintingRecords;

NumberVar Group3DetailsTotal :=
   Count({SimpleData.CategoryC},
      {SimpleData.CategoryC});

1. On the Format menu, click 'Section'. This opens the Section Expert. 2. Under the 'Sections' list, click the Group Header #1 section. 3. Beside the 'New Page Before' check box, click 'X+2'. This opens the Conditional Formatting Formula Editor.

Type this formula:


WhilePrintingRecords;

NumberVar LinesRequired := 0;

if (1 = (NumberVar Group3DetailsTotal -
         NumberVar Group3DetailsPrinted))
then
( // If there is one detail left to print
   LinesRequired := NumberVar
      LinesRequiredInGroup1ForSingleDetailLine;
   if (1 = (NumberVar Group2DetailsTotal -
      NumberVar Group2DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF2Height;
   if (1 = (NumberVar Group1DetailsTotal -
      NumberVar Group1DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF1Height;
   if (1 = (NumberVar ReportRecordsTotal -
      NumberVar TotalRecordsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar ReportFooterHeight
)

else ( // If there are multiple details left to print

   LinesRequired :=
      NumberVar LinesRequiredInGroup1ForManyDetailLines;
);

NumberVar CountLines >
   (NumberVar TotalLinesInReport - LinesRequired)

1. On the Format menu, click 'Section'. This opens the Section Expert. 2. Under the 'Sections' list, click the Group Header #2 section. 3. Beside the 'New Page Before' check box, click 'X+2'.

Type this formula:


WhilePrintingRecords;

NumberVar LinesRequired := 0;

if (1 = (NumberVar Group3DetailsTotal -
   NumberVar Group3DetailsPrinted))
then (
   LinesRequired := NumberVar
      LinesRequiredInGroup2ForSingleDetailLine;
   if (1 = (NumberVar Group2DetailsTotal -
      NumberVar Group2DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF2Height;
      if (1 = (NumberVar Group1DetailsTotal -
         NumberVar Group1DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF1Height;
      if (1 = (NumberVar ReportRecordsTotal -
         NumberVar TotalRecordsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar ReportFooterHeight
)
else (
   LinesRequired := NumberVar
      LinesRequiredInGroup2ForManyDetailLines;
);

NumberVar CountLines >
   (NumberVar TotalLinesInReport - LinesRequired)

1. On the Format menu, click 'Section'. This opens the Section Expert. 2. Under the 'Sections' list, click the Group Header #3 section. 3. Beside the 'New Page Before' check box, click 'X+2'.

Type this formula:


WhilePrintingRecords;

NumberVar LinesRequired := 0;

if (1 = (NumberVar Group3DetailsTotal -
   NumberVar Group3DetailsPrinted))
then (
   LinesRequired := NumberVar
      LinesRequiredInGroup3ForSingleDetailLine;
   if (1 = (NumberVar Group2DetailsTotal -
      NumberVar Group2DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF2Height;
   if (1 = (NumberVar Group1DetailsTotal -
      NumberVar Group1DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF1Height;
   if (1 = (NumberVar ReportRecordsTotal -
      NumberVar TotalRecordsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar ReportFooterHeight
)

else (
   LinesRequired := NumberVar
      LinesRequiredInGroup3ForManyDetailLines;
);

NumberVar CountLines >
   (NumberVar TotalLinesInReport - LinesRequired)

1. On the Format menu, click 'Section'. This opens the Section Expert. 2. Under the 'Sections' list, click the Details section. 3. Beside the 'New Page Before' check box, click 'X+2'.

Type this formula:


WhilePrintingRecords;

NumberVar LinesRequired := 0;

if (1 = (NumberVar Group3DetailsTotal -
   NumberVar Group3DetailsPrinted))
then (
   LinesRequired := NumberVar
      LinesRequiredInDetailsForLastDetail;
   if (1 = (NumberVar Group2DetailsTotal -
      NumberVar Group2DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF2Height;
   if (1 = (NumberVar Group1DetailsTotal -
      NumberVar Group1DetailsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar GF1Height;
   if (1 = (NumberVar ReportRecordsTotal -
      NumberVar TotalRecordsPrinted))
   then LinesRequired := LinesRequired +
      NumberVar ReportFooterHeight
);

NumberVar Group1DetailsPrinted :=
   Group1DetailsPrinted + 1;
NumberVar Group2DetailsPrinted :=
   Group2DetailsPrinted + 1;
NumberVar Group3DetailsPrinted :=
   Group3DetailsPrinted + 1;
NumberVar TotalRecordsPrinted :=
   TotalRecordsPrinted + 1;


if (NumberVar Group1DetailsPrinted =
   NumberVar Group1DetailsTotal) then
      Group1DetailsPrinted := 0;
if (NumberVar Group2DetailsPrinted =
   NumberVar Group2DetailsTotal) then
      Group2DetailsPrinted := 0;
if (NumberVar Group3DetailsPrinted =
   NumberVar Group3DetailsTotal) then
      Group3DetailsPrinted := 0;

NumberVar CountLines >
   (NumberVar TotalLinesInReport - LinesRequired)

With these formulas in place, no conditions should occur that allow for widowed headers or footers to appear.



Developed Under:

Crystal Reports v8.0




Featured Article

An Introduction to C#
By Joey Mingrone

Register Today!


100% FREE

Members enjoy these benefits:
Access to ITI Downloads
Access to more articles and tutorials
Optional weekly newsletter
And more...

Click here to register
Or
Click here to log in



© 2008 Interface Technologies, Inc. All Rights Reserved
Questions or Comments? devcentral AT iticentral DOT com
PRIVACY POLICY