Showing posts with label Report. Show all posts
Showing posts with label Report. Show all posts

Friday, May 1, 2009

Cathy to speak at Southwest Fox 2009

I'm excited to announce that I will be speaking at Southwest Fox 2009 and will be making two presentations:


Making the Most of VFP 9 SP2 Reports (Part I)
In addition to lots of bug fixes, VFP 9 SP2 offered up some major enhancements to the Visual FoxPro Report Writer. This session (the first of a 2-part series) explores the new Dynamics, Advanced, and Rotation features. It also takes you behind the scenes and explains how these features are implemented. If you want to write professional reports with lots of pizzazz, this session is a must-see.

You will learn:

  • How to correctly install SP2 and obtain the hotfixes
  • How to use the new Dynamics feature (e.g. negative numbers in red)
  • How to use the new Advanced features (e.g. HTML-related properties)
  • How to use the new Rotation feature
  • How the new features are implemented behind the scenes

Making the Most of VFP 9 SP2 Reports (Part II)
Part I of this 2-part series shows you how to use the new reporting features introduced in VFP 9 SP2. This session steps it up several notches by showing you how to add your own features. Not only will you learn how to implement those features on your reports, but you'll also learn how to make the features available in the Report Builder's UI. In addition, you'll see a "best practices" methodology that makes it easy for developers to share their enhancements with one another. You don't want to miss this session. Come be a part of history in the making!

You will learn:

  • How to dynamically shrink a font
  • How to create text and graphic watermarks
  • How to modify the Report UI to include your custom features
  • How to data-drive all your custom features
  • How to share new features with other developers

There's a wonderful lineup of speakers and sessions this year so I hope you all can make it to Mesa, Arizona from October 15 through the 18th. You can read all the details on the website: www.swfox.net.





Thursday, April 9, 2009

SET TALK appears to be on when running reports with SP2

I've been using VFP 9 SP2 ever since it first came out which was a long time ago. Yeah, I know there was that nasty Data Group bug, but to me, the enhancements in SP2 far outweighed the negative. Now that Microsoft has released a hotfix for the Data Group bug, I'm hoping more developers jump on the bandwagon and start adopting SP2. That said, a colleague reminded me last night about a bug where text is echoed to the screen as if a mysterious SET TALK ON had been issued.

This is a bug, but it’s one that you can easily fix yourself. You see, some of the new enhancements in SP2 were not implemented in the core VFP exe. They were implemented with a creative use of several Report Listener subclasses that reside in the FFC directory. When you run reports with SP2, the default behavior is to utilize these Report Listeners instead of the base VFP Report Listener class. The bug exists in one of those classes so you can change it yourself.

Modify the fxListener class of the _ReportListener class library and change the code in the LoadReport method. Simply move This.setFRXDataSessionEnvironment() so it comes before This.createHelperObjects() and the problem is solved.  

If you’re running on Vista, however, you have to be aware of the Virtual Store and work around it. When you edit the fxListener class, Vista makes a copy of the _ReportListener class library in the Virtual Store and your modifications are actually saved there and not in the C:\Program Files\Microsoft Visual FoxPro 9\FFC directory as you expected. Because a Virtual Store is specific to each user, it means the change you just made only works for the login you’re currently using. As soon as you switch to another login, the changes don’t exist for that user. To permanently fix the bug, move the _ReportListener class library from your Virtual Store back to the C:\Program Files\Microsoft Visual FoxPro 9\FFC directory, overwriting the original. Also, be sure to delete the _ReportListener class library from the Virtual Store for all users. If you forget this step, those users could be accessing an old copy of the class library.

Wednesday, April 8, 2009

VFP 9 SP2 Hotfix Updated

The VFP 9 SP2 Hotfix which addresses the Report Data Group bug (download from http://code.msdn.microsoft.com/KB968409) has been updated. This latest file includes the missing VFP9T.DLL (Multi-threaded runtime) file. In addition, the other hotfixes are no longer password protected.

Saturday, April 4, 2009

VFP 9 SP2 Hotfix Minor Glitch

A few days ago I blogged about Microsoft releasing a hotfix for the VFP 9 SP2 Report Data Group bug (read it here). Last night, Rick Schummer blogged about a slight glitch with the hotfix and let us all know that Microsoft will have a resolution quickly. Instead of repeating what he said, I'll just point you to his blog post: (read it here). 
 

Thursday, April 2, 2009

Microsoft fixes Data Group Bug in Reports!

Woo Hoo!!   Yippee!!  Hooray!!  I'm jumping for joy!!

I'm extremely excited to let everyone know that Microsoft has fixed the serious Data Group bug in VFP 9 SP2 reports which I blogged about here. The bug is officially described in the following Microsoft KB article, where you'll also find detailed instructions on how to get the fix. 

FIX: The group header of a data grouping is not printed at the top of each page as expected after you intall Microsoft Visual FoxPro 9.0 Service Pack 2 (968409)

I've heard lots of developers say they've held off upgrading to SP2 because of this one bug. So those of you that fall in this category .. it's time to upgrade!! There are no more excuses!! 

Several people in the FoxPro Community, myself included, worked hard at getting this bug fixed and spent a lot of time testing it. Please ... I don't want to hear any bitching from anyone about how long it took to get this. Instead, let's all focus on the positive side which is the fact that Microsoft listened and provided a fix to a serious bug.

P.S.  Read Rick Schummer's blog for more thoughts about this bug fix.  

Sunday, March 22, 2009

Workaround: Gap with Multiple Data Groups

In November, 2007, I reported a bug in the VFP 9 Report Writer that related to data groups (Bug 312572). This isn't the major data grouping bug that everyone's been talking about, but rather a smaller one I stumbled on while doing all my testing. It has to do with a strange gap of whitespace appearing on the report under certain circumstances as shown in the following:



After getting some insight from a developer at Microsoft, I was able to understand what was going on behind the scenes. That knowledge helped me figure out a workaround for this issue.

The report has three data groups. The first data group breaks on an expression of: .T. The second data group breaks on a field in the data: GrpField. The third group is used to print some whitespace every 5 detail records. Its expression is: INT(rnLine / 5). The report also has a variable defined to help count the number of detail lines: Name = rnLine, Value to store = 0, Initial Value = 0, Reset value = GrpField, Calculation = Count.

The problem is that the third data group uses the rnLine report variable which is reset on the second data group. As the second data resets, it alters the value of the report variable, which messes with the data grouping and completely confuses the Report Writer.

The solution is to alter the report variable in a slightly different way so it doesn't confuse the data grouping. Only two slight changes are required, but the changes are enough to make the Report Writer happy. First, change the definition of the report variable to reset at the end of the report instead of the second data group.

The second change is to add the following to the On Entry Expression in the Data Group Header of the second Data Group: _VFP.SetVar('rnLine', rnLine - MOD(rnLine,5)). This change manipulates the report variable by reducing the value back to the last number that triggered a break. It's a sneaky workaround that's pretty effective as shown in the following example that doesn't have the gap:



As with most of the Visual FoxPro Report Writer, a little creative thinking can go a long way!

Monday, September 8, 2008

Workaround: Dangling Datasession Left After Running Report

In December, 2007, I posted about a bug in VFP 9 that causes a dangling datasession after running a report from form with a private datasession and using report listeners chained together as successors. Microsoft still hasn't fixed the problem, but I now have a workaround for the bug.

First of all ... I have to give credit where credit is due. I didn't come up with the solution. It was given to me by Rick Hawkins ... so thanks Rick!! But now that I have the solution, I want to share it with everyone who follows my blog (all three of you.)

The solution is actually quite simple ... just before you instantiate any report listener object, switch to datasession 1, instantiate the object, then switch back to the previous datasession.

LOCAL lnDataSession, loListener, loListener2

lnDataSession = SET('DataSession')
SET DATASESSION TO 1
loListener = CREATEOBJECT('ReportListener')
loListener.ListenerType = 1
loListener2 = CREATEOBJECT('ReportListener')
loListener.Successor = m.loListener2
SET DATASESSION TO (m.lnDatSession)

REPORT FORM Whatever OBJECT m.loListener


I'd rather Microsoft fix the bug, but I guess a workaround is the next best thing!

Tuesday, April 15, 2008

How Do I ... Total fields for one detail band only

When multiple detail bands were introduced to Visual FoxPro it was a great addition that was long overdue. However, there's one aspect of that feature that wasn't clearly thought through and that's Calculations and Report Variables.

Let's say you create a report with multiple detail bands. Then you add a data group to the report and in the data group footer you add some fields that are defined to calculate using the SUM option. The problem that can arise is the calculation is applied to every record in both detail bands and maybe you only want to sum the records in the first detail band. Hmmm ... now what?

There's a workaround, but it takes some extra work on your part. Start by defining a Report Variable called rnDetail; Set the Value to Store to 0; Set the Initial Value to 0; Set the Reset option to End of Report; and set the Calculation option to Sum. This creates a Report Variable that the Report Engine doesn't ever change but now you have something you can manipulate.

The next step is to make sure each of the detail bands are marked to include the associated header and footer bands. In the OnEntry Expression of the Detail Header 1 band, enter the expression: _VFP.SetVar('rnDetail', 1). In the OnEntry Expression of the Detail Header 2 band, enter the expression: _VFP.SetVar('rnDetail', 2). These two expressions reset the Report Variable to 1 or 2 at the beginning of the respective detail band so now you have a way to know which detail band you are on.

The next step is to create Report Variables for each of the fields you want to sum. For example, if you want to sum the Qty and Price in the first Detail Band, create a Report Variable called rnQty and set the Value to Store to IIF(rnDetail = 1, Qty, 0). Create another Report Variable called rnPrice and set the Value to Store to IIF(rnDetail = 1, Price, 0). Leave the Calculation option of both variables at the default of None.

The final step is to add the field objects to the data group footer band. Instead of using the name of the field such as Qty or Price, use your new Report Variables of rnQty and rnPrice for the expression. Set the Calculation options to reset at the data group. Now you have some calculations in the data group footer that only contain values from the first data detail band.

This concept can be used in various situations when you need to create calculations or Report Variables that only get processed on one of many detail bands. Once you have the rnDetail Report Variable in place, you can reference it as needed. Just be sure this Report Variable is at the top of the list of Report Variables before any other Report Variables that need to access it. The Report Engine processes the Report Variables in the order they appear in the list.

Tuesday, January 1, 2008

How Do I ... Create some complicated data groups and build a recap?

I recently had to create a very complicated report for a client that covers several different techniques. I thought it would be good to share this modified sample with everyone.

At first, the report sounded simple (don't they all!) Create a list of orders, sorted and subtotaled by customer and each customer should start on a new page. That's easy, I can handle that. Put the orders in the detail band. Create a data group on the Customer and mark it to start on a new page. Put subtotals for the customer in the Data Group Footer band.

Oh .. the client says .. the list of orders per customer can get quite long. Can we have ledger-style shading or a line every so many lines? Sure, I think I can handle this. Oh ... the client says again ... we'd also like subtotals at the bottom of each page showing the totals of just that page. That should be easy .. I can use the page footer band. Oh wait .. as I think that through some more, it's not going to work because on the last page for the customer, the data group footer band would print and then the page footer would show up at the bottom. That's not cool. Hmm ... these two requirements combined make things a little sticky .. but I'm sure I can come up with the answer.

Then comes the killer requirement .. Remember those page subtotals we want at the bottom of each page .. well .. at the end of the customer we'd also like a recap that shows each one of those subtotals like the following:

Page 1, $999.99
Page 2, $999.99
Page 3, $999.99

Yuk .. I really don't like that one especially combined with the ledger-style and page subtotals. Now I'm really going to have to put some thought into this report. I think my head is spinning!

For this example, I'm using VFP 9 SP2 (although it should work with previous versions because I'm not using a ReportListener or any of the new features.) I'll use the TasTrade data stored in C:\Program Files\Microsoft Visual FoxPro 9\Samples\Tastrade\Data. I wanted to be flexible with the number of lines per ledger section and the number of lines per page so I decided to control them with a variable. That way, if the customer changes their mind down the road I can easily change it.

I also didn't want to mess around with trying to build the data for the recap ahead of time. Again, I was thinking down the road about using this technique for other situations and if I were to use it on a report with stretchable fields, I didn't want to use hard-coding to "count" each record and figure out the appropriate page it falls on. I just wanted to let it flow and let the report build the recap data for me no matter how many records appeared on a page. I also didn't want to have to hard-code all the variables to be totaled. I wanted some generic code that totals all the numeric or currency fields.

Let's start by looking at the final report as shown below in Figure 1. The first page shows the records for the first customer. The second page shows the "recap" for that customer, which only contains one page. The third and fourth pages do the same thing for the second customer. The fifth through seventh pages show the details for the third customer and the last pages shows the "recap" of each of the three previous pages which belong to the third customer.









Figure 1: The final printed report.

Next, let's look at the simple program that I use to create the data and print the report. Notice that I use two variables to control the groupings. I could have hard-coded this in the report itself, but this is more flexible.

*-- Build the data
SELECT '1' AS RecType,
Orders.Customer_ID, ;
Customer.Company_Name, ;
Orders.Order_Number, ;
Orders.Order_Date, ;
CAST(Orders.Discount AS N(14,2)) AS Discount, ;
CAST(Orders.Freight AS N(14,2)) AS Freight, ;
CAST(NVL(SumLines.nPrice, 0) AS N(14,2)) nPrice ;
FROM 'C:\Program Files\Microsoft Visual FoxPro 9\Samples\Tastrade\Data\Orders' ;
LEFT OUTER JOIN 'C:\Program Files\Microsoft Visual FoxPro 9\Samples\Tastrade\Data\Customer' ;
ON Customer.Customer_ID = Orders.Customer_ID ;
LEFT OUTER JOIN ;
(SELECT OrdItems.Order_ID, ;
SUM(OrdItems.Unit_Price * OrdItems.Quantity) AS nPrice ;
FROM 'C:\Program Files\Microsoft Visual FoxPro 9\Samples\Tastrade\Data\OrdItems' ;
GROUP BY OrdItems.Order_ID ;
) SumLines ;
ON SumLines.Order_ID = Orders.Order_ID ;
INTO CURSOR tmpReportData READWRITE

*-- Index the data
SELECT tmpReportData
INDEX ON Customer_ID + RecType + Order_Number TAG SortKey
GOTO TOP

*-- Set some variables to control # of lines
*-- for each section and # of lines per page.
nMaxLinesPerLedger = 2
nMaxLinesPerPage = 6

*-- Run the report
REPORT FORM ComplexGroups_Recap TO PRINTER PROMPT PREVIEW

Besides the above program, I also need a function that I'm going to call from the report itself. This function will update the cursor that is driving the report by either adding a new record for a particular page, or adding to the numeric fields for the given page. Note that I have to take great care to move the record pointer back to where it was when this function was called. Otherwise, you'll make a mess of the running report. Add the following function to the bottom of the program that runs the report so it's available to the report.

************************
FUNCTION AddToPageTotals
************************
LPARAMETERS tcField, txPage, tcSeek, tcIndex

LOCAL loRecord, lnRecNo, lcAlias, lcSeek, lx

*-- Don't do this on the total records themselves!
*-- (Can you say "infinite loop")
IF RecType = '2'
RETURN
ENDIF

*-- Remember where we are
lnRecNo = RECNO()
lcAlias = ALIAS()

SCATTER NAME m.loRecord
m.loRecord.RecType = '2'
m.loRecord.&tcField = txPage

lcSeek = EVALUATE(STRTRAN(m.tcSeek, 'XTMPX', 'm.loRecord'))
IF SEEK(m.lcSeek, m.lcAlias, m.tcIndex)
*-- add the amount fields to the existing record
lnFields = AFIELDS(laFields)
FOR ln = 1 TO lnFields
lcField = laFields[m.ln, 1]
lx = EVALUATE(m.lcField)
IF VARTYPE(lx) $ 'NY'
REPLACE (m.lcField) WITH NVL(EVALUATE(m.lcField),0) + NVL(m.loRecord.&lcField,0)
ENDIF
ENDFOR
ELSE
*-- Add the record for this page
INSERT INTO (m.lcAlias) FROM NAME m.loRecord
ENDIF

*-- Go back to the "detail" record that we were processing
GOTO m.lnRecNo

Now let's get to the definition of the report, which is the meat of this solution. Figure 2 shows how the report definition will look when we're done.


Figure 2: The report definition.

Start by creating 3 report variables:
  • rnLinesOnPage

    • Value to Store = 0
    • Reset = Report
    • Calculation Type = Count

  • rnLinesForCustomer

    • Value to Store = 0
    • Reset = Report
    • Calculation Type = Count

  • Dummy

    • Value to Store = AddToPageTotals('Order_Number', TRANSFORM(_PageNo, '999999'), 'XTMPX.Customer_ID + XTMPX.RecType + XTMPX.Order_Number', 'SortKey')
    • Reset = Report
    • Calculation Type = None

At first thought, it might look like I made a typo above because none of the variables reset at the Customer group or Page group. But trust me .. it's not a mistake. Just bear with me and it will make sense soon.

The last variable is used to call the function we created earlier. It looks a little complex but that's just because I made the function generic so I can reuse it on other reports. You could simplify it by taking away all the parameters and hard-coding the function.

Next, create 4 different Data Groups:
  • 1: Customer_ID, New Page Number 1, Reprint group header on each page

  • 2: RecType, New Page

  • 3: INT(rnLinesForCustomer / nMaxLinesPerPage), New Page

  • 4: INT(rnLinesOnPage / nMaxLinesPerLedger)


Expand the #1 Data Group Header band and put the Customer field.

Put the detail fields in the Detail band and lay them out as you desire.

Expand the #4 Data Group Header band and add a horizontal line to separate the chunks of detail records. I made my light gray so it's not so distracting.

Expand the Data Group Footer bands for #3 and #4 so you can add some totals. Copy your numeric fields from the Detail band into the two different group footer bands. Next, change the Calculate option on each to SUM and reset on the applicable group.

Now go ahead and add whatever column headings you want. You can use Print When logic of RecType = '1' if you want to print something for just the regular data. Use RecType = '2' if you want to print something on just the page recaps.

At this point you might think we're done, but we're not. Remember when we defined the report variables I mentioned that we are not resetting them at the appropriate data groups. The reason is that whenever you try to alter the variable that is being used to control the groups, the VFP Report Writer gets completely confused. You end up with more breaks than you want and often times you get pages with no detail records and just some totals.

So here's the trick behind this whole report. We need to reset the report variables ourselves. Well, actually, we aren't resetting them, we're fudging them. The problem is that if we reset them to zero, we get the extra breaks I just mentioned. So instead of resetting them to zero, we fudge them to a value that makes the next page start at a clean point.

We are going to alter these variables in the On Entry and On Exit Expressions of the #2 Group Footer band as follows:

On Entry: _VFP.SetVar('rnLinesForCustomer', rnLinesForCustomer- MOD(rnLinesForCustomer, nMaxLinesPerPage))

The above "expression" resets the rnLinesForCustomer variable to a value that is equal to what the count would be if the page was completely full of lines, without resetting it for each page. So if we allowed 10 lines per page, at the end of the first page we reset it to 10, at the end of the 2nd page we reset it to 20, and so on. Regardless of how many lines actually printed, we just make it think that full pages have been printed. By doing this, we avoid the funky extra breaks that happen when you try to zero out the variable.

On Exit: _VFP.SetVar('rnLinesOnPage', rnLinesOnPage- MOD(rnLinesOnPage, nMaxLinesPerLedger))

The above "expression" does the same thing for the ledger breaking as the previous one did for the page breaking. It really doesn't matter which one is in the On Exit and which one is in the On Entry. I just needed to reset two variables and this gave me a place to do each one.

That's it. We're done. Simple, right? Well .. of course it's simple when you already know the answer. Trust me .. it wasn't that simple for me to come to this conclusion, but now you can benefit from my troubles. If you want the sample program and report I used to create this blog, just send me an email and I'll gladly send it to you.

Friday, December 7, 2007

Gotcha: Dangling Datasession Left After Running Report

If you run a report using a ReportListener from the FFC directory, and you're using a successor listener, and that report is run from a form with a private datasession, you end up with a dangling datasession after the report completes. If you keeping running reports in this manner, you keep building up more dangling datasessions. I don't think I have to tell you the consequences of a long day of running reports like this!

I posted this on Microsoft's Connect site so anyone who wants to confirm, vote, comment, etc. about this bug, the ID number is 316134.

Here are the steps to reproduce the problem:

1. Create a form
2. Set the datasession to private
3. Add a button with the following code in the click

lcReport = SYS(2015)

CREATE CURSOR junk (test I)
FOR ln = 1 TO 10
INSERT INTO Junk VALUES (ln)
ENDFOR

CREATE REPORT &lcReport FROM Junk

ThisForm.AddProperty('oListener', null)

SET CLASSLIB TO 'C:\Program Files\Microsoft Visual FoxPro
9\Ffc\_reportlistener'
ThisForm.oListener = CREATEOBJECT('_ReportLIstener')
ThisForm.olistener.listenertype = 1

THisForm.AddProperty('o2', null)
ThisForm.o2 = CREATEOBJECT('ReportListener')
ThisForm.oListener.Successor = ThisForm.o2

REPORT FORM &lcReport OBJECT ThisForm.olistener


4. Run the form
5. Click the button
6. Close the report
7. Close the form
8. Open the data session window
9. Notice an Unknown(#) session.

Tuesday, December 4, 2007

Gotcha: Workaround for Data Group bug

I've had a few people ask for suggestions on how to work around the ugly data group bug that I previously blogged about. So far, the only work around I have is not generic and has to be applied to EVERY report that uses data groups. I HATE this solution, but it's the only one I have so far.

1. Create a report variable for any data you need to show in the Data Group Header. Set the expression to the data field. (rcCustomer)

2. Create a report variable to count the number of detail lines in the data group. Set the value to 0, Reset it on the data group, and set the Calculation to Count. (rnCustCount)

3. In the Data Group Footer, force the counter to zero after the data group by entering the following in the On Exit Expression: _VFP.SetVar('rnCustCount', 0)

4. In the field object in the Data Group header, enter the following in the Print When expression: rnCustCount = 0

5. Now copy the field object, but change the reference to the data field to refer to your report variable (rcCustomer). Then change the Print When to rnCustCount > 0. Just stack this on top of the original field object.

You now have two objects in the data group header. The original one prints only the first time the data group prints. The second one prints on subsequent pages and uses the report variable instead of the data reference so it will be the right record. An added bonus to this solution is that you can add the word "Continued" in the expression that prints on subsequent pages.

Tuesday, November 27, 2007

Gotcha: VFP Reporting Bugs

I'm really frustrated that I have not received ANY response at all from Microsoft about the recent Data Group bugs I reported. I was already frustrated that they hadn't addressed any of my other report-related bugs .. but these ones are serious and were introduced by SP2.

In hopes of putting more pressure on them .. here's a list of all the bugs I have reported through the official channels. You can use the following link to go to the Microsoft Connect page. Near the bottom of the page is a place to enter the ID of the issue. Then you can rate the bug, validate it, and provide any additional comments. Maybe if enough of us complain, they will address it.

Microsoft Connect

249264 VFP Print When processing wrong parent record
291486 VFP Detail Footer Band -- Wrong record
292987 VFP Preview - Zoom level not always programmatically changeable
293615 Print When logic is evaluated at the wrong time in VFP Reports
295113 Shapes stretched across Detail Header and Detail Footer bands whacko
288896 Squished Printing
286313 VFP SYS(1037) no longer has a PRINTER button in Vista
286314 Report Properties dialog locks up
286552 Code References - error printing when not in Admin on Vista
286958 Drag control from Toolbox to Pageframe and Labels disappear
287927 Intellisense on SET gets confused
312568 SP2 broke data group headers repeated on subsequent pages
312572 Gap with multiple data groups on reports

Tuesday, November 20, 2007

Gotcha: More on the Data Group Bug

I've been trying to see if I can come up with a ReportListener that will somehow generically workaround the serious Data Group bug I previously blogged about (Data Group Bug) In the process, I tried to come up with a really good test report to make sure I'm doing it right. I created a report with 3 data groups so I can be sure my code handles multiple data groups.

Well .. let's just say I haven't even gotten to the part of writing code yet. While developing a test report, I came across ANOTHER bug related to data groups. What I'm seeing is a gap on the report after the 3rd data group header prints, but not every time. It only happens for the third data group, when it immediately follows the second data group header. Oh .. and it doesn't happen the first time for the set.

Figure 1 shows how the report looks on page 1, which is correct. Figure 2 shows what happens on subsequent pages, which is incorrect.


Figure 1 - The first page - without any gap.


Figure 2 - Subsequent pages - with a big gap!

Obviously, this whole data group issue is getting worse and worse. I'm afraid to keep working on the "workaround" code. Who knows what other bugs I'll uncover! I sure hope Microsoft fixes this! Maybe we should ALL flood them with emails about these report bugs!!

Wednesday, November 14, 2007

Gotcha: Serious report bug with Data Groups introduced in VFP 9 SP2

Here's the situation: You have a report with a data group such as Customer. You checked the "Reprint group header on each page" option to make sure the group header reprints whenever the details for the group overflow to a new page. You put some total information in the group footer band. The report looks somewhat like what is in Figure 1.

Figure 1: The "Good" report

Now let's say that the data just so happens to work out so that the last detail record for customer 1 prints at the bottom of the page, thus, the data group footer needs to go to the top of the next page to print.

In VFP 7, VFP 8, and VFP 9 SP1 ... you get what's shown in Figure 2. The data group footer for customer 1 prints at the top of the next page, without bothering to reprint the data group header information for customer 1. This is a bug .. but not exactly the end of the world. I could probably live with this anomaly .. if I really had to.

Figure 2: The "Bad" report in VFP 7, VFP 8, and VFP 9 SP1

However, in VFP 9 SP2, Microsoft attempted to fix the bug and inadvertently introduced a more severe bug as shown in Figure 3. The data group header prints at the top of the next page BUT it's printing the data from Customer 2, the NEXT record. Then it backs up and the data group footer prints for Customer 1. Then the detail records for Customer 2 begin printing WITHOUT printing the data group header for Customer 2.

Figure 3: The "Bad" report in VFP 9 SP2

As you can see, this is a real mess. Printing the group header with the WRONG customer information is far worse than omitting the group header. This is completely unacceptable in my opinion!! It's completely misleading to print Customer 2 and then show the totals for Customer 1. In fact, as far as I'm concerned, it could cause some serious legal issues for my clients using my reports in some situations.

As it stands now, you cannot ever safely print data in the Data Group Header band if it's marked to repeat on subsequent pages. This is a serious bug --- and Microsoft needs to fix this ASAP!!!

Friday, November 9, 2007

Gotcha: Not all Printers Rotate the Same Direction

This is the first post in a series I'm calling "Gotcha". This is where I plan to talk about bugs ... er, "features" ... that I've run across or other issues that have caused me grief. Hopefully, by letting you know about them, and some possible work arounds, it will you save you from many future headaches!

I’ve been writing reports for years and I recently stumbled across an issue that threw me for a loop. A report that was designed on my machine in Michigan wasn’t working the same in the Tennessee home office. After a lot of hair pulling, the light bulb went off and I realized what the problem was.

To print a landscape report, my printer rotates the text counter-clockwise; the printer in the Tennessee office rotates the text clockwise!

What? You’ve got to be kidding me. How can this be? I just ASSUMED that all printers rotate the same direction! Isn’t there a “standard” or something that all printer manufacturers follow? Well .. apparently not!

So why is this important to you? The answer is … Unprintable Margins.

Most printers have unprintable margins that you have to consider when writing reports. Typically, the right and left margins are the same, but the top and bottom margins may be different. Often times, the bottom margin is the largest margin. For example, my printer has .25” on the right and left margins, .07” on the top margin, and a very greedy .48” on the bottom margin. The key here is that these figures apply to a portrait report. When you print a landscape report, these margins are swapped … and the direction of the rotation determines whether the left margin becomes .07” and the right margin becomes .48” or visa-versa.

Are you starting to see the problem yet? I designed a landscape report that was tight on the left side and had a half an inch on the right side to accommodate my greedy “bottom” margin. When my coworkers in Tennessee printed the report on their printer, the entire left side was cut off. That’s because their left margin is now the greedy bottom margin. That means they can’t print tight to the left side like I can .. but they can print tight to the right side.

So now that you know about this dilemma .. what should you do about it? You can take one of two approaches. The first approach is to design the reports as “Printable Page”, make the landscape width no more than 10.25”, and let the printer decide where to place the text. The other option is to design the report as “Whole Page” and leave a generous .5” margin on both the right and left sides of the landscape report. Personally, I prefer the latter because I like to keep the report centered, but it means I lose a little bit of real estate. Of course, if you ever run across a printer that is even greedier than mine, you’ll have to change your report width accordingly.

Knowledge is everything! Hopefully this bit of knowledge will keep you from making the same assumption I did which caused me a lot of grief and aggravation!