Are Your Bills Piling Up?
Neil J. Rubenking
Almost everyone carries some amount of consumer debt — if only a mortgage — and more and more of us carry credit-card debt. Carrying debt means paying interest — sometimes an appalling amount of it. This issue’s utility, PayEmOff, helps you devise a strategy for getting out of debt efficiently by minimizing the amount of interest you pay. By paying off high-interest cards first, you can save a significant amount of money; PayEmOff shows you exactly how much. In addition to analyzing your credit card debt, PayEmOff includes separate calculators for analyzing your mortgage and investments. These calculators can instantly show you the effect of changing the interest rate, payment amount, or number of months for investment or until payoff. And since dealing with debt is always stressful, you can configure the program to use whatever background images, colors, and fonts you find most soothing.
PayEmOff runs under Windows 95, Windows 98, Windows NT 4, and Windows 2000. The Delphi 5 source code is provided with the utility for those interested in seeing how it works. Note that PC Magazine programs are copyrighted and cannot be distributed, whether modified or unmodified. Use is subject to the terms and conditions of the license agreement distributed with the programs.
To install PayEmOff, run the supplied installation program INSTALL.EXE. To uninstall the program, use the Add/Remove Programs applet in the Windows Control Panel. To familiarize yourself with the program before entering your own credit card data, you can load the supplied data file sample.pmo.
The first things you’ll notice when you launch PayEmOff are the background image and the unusual font, which are used throughout the program (see Figure 1). PayEmOff lets you choose the background and font for each of its six principal windows — the main window and the Card wizard, Card analyzer, Payoff strategy, Mortgage calculator, and Investment calculator windows. By default, each window has a garden-themed image for its background and uses the Comic Sans MS font. To change these settings, choose Display Options from the Tools menu in the main window. The figures in the rest of this article show some of the fonts and backgrounds that are available.
The Display Options page contains six tabbed pages, one for each of PayEmOff’s principal windows (see Figure 2). Every tabbed page has the same controls: four options for the background, with each option represented by a button, and an additional button for selecting the font. A preview area to the right of the buttons lets you see how the font and the background look together.
Your display settings apply to the currently selected window. If you’d like to use the same style for all six windows, click the All like current button. Click the Restore defaults button to put all of the windows back to their default appearance.
The four buttons for controlling the background are No background, Solid color background, Built-in image, and Image on disk. Click the button labeled No background to use the standard system color. (This is the color of the 3D Objects item buried in the Display Properties dialog — which pops up if you choose Properties from the Windows desktop context menu — and is usually light gray.) Click the button labeled Solid color background to invoke a standard color-selection dialog. Select Built-in image to choose from PayEmOff’s many built-in garden images and background textures. The textures are sorted into light, medium, and dark. If you have an image of your own you’d like to use, click Image on disk to choose any .JPG or .BMP image.
Clicking the Set font button will invoke a font selection dialog. You can specify the typeface and font color, set a size from 8- to 12-point, and choose whether the font will be bold or italic. Some combinations of background and font color will be illegible; you can use the preview area to avoid these. Also, with some combinations of typeface, style, and size, the text may not fit properly in the window. In those cases you’ll have to choose a different font.
The No flicker checkbox is present only on the main window’s Display Options page. When the main window’s credit card list has an image for a background, resizing the columns can cause an annoying flicker on some computer systems. If you check the box, this flicker will be greatly reduced. The trade-off is that the background may be a bit scrambled while resizing is taking place.
Entering Your Data
Before you start entering data, try to locate the credit agreement for each card, along with some recent bills. For each card, choose Add from the Cards menu, or press the Add card toolbar button. This launches the Add Card Wizard (see Figure 3), which will take you through the process of entering a credit card’s data. You start with the name, which must be different for each card. If you enter a name that’s already in use, PayEmOff will append a number to make it unique, for example, Visa, Visa (1), Visa (2). Next you select an icon to represent the card (see Figure 4). PayEmOff provides four generic credit card icons plus another twelve that resemble popular credit card types. To make a selection, click the Icon button, or press Alt+I.
On the next two pages of the wizard, you’ll enter the balance and the annual percentage rate (APR). You can find the APR on a recent bill, but when perusing the bill, make sure you identify the correct number. A rate under 2 percent is the daily or monthly rate, not the annual rate. Also note that sometimes cards have different rates for different portions of the balance. In this case, use the highest rate.
The next page asks you to enter the minimum payment due. Credit card companies calculate this minimum as a percentage of the outstanding balance, usually from 2 to 3 percent. You can find this value in your credit agreement (if you can find your credit agreement). If you have the number, enter it and click Next. Otherwise, leave the field blank and click Next. If you don’t enter a value, the next page will ask you to enter the balance and minimum payment from four recent bills so PayEmOff can estimate this percentage. Try to choose bills with a minimum payment of $20 or more. The Next button will be enabled when you’ve filled in all the values. Click it, and PayEmOff will calculate the minimum percentage based on the data you entered.
The minimum payment does not continue to decrease indefinitely as the balance goes down; there’s a certain absolute minimum. If the percentage calculation yields a lower value, the credit card company uses this absolute minimum. Here again, you may be able to determine the absolute minimum from your credit agreement. If not, just guess; $15 is a common value.
On the last page of the Add Card Wizard, you’ll see a summary of the data entered. Verify that it’s all correct, and click Finish. The card will now appear in the main window’s list of credit cards (see Figure 5). If you need to change anything, just return to the Add Card Wizard by double-clicking the card in the list.
Analyze One Card
Select a credit card in the list, then choose Analyze from the Cards menu, or click the Analyze card toolbar button. This brings up a Card Analyzer window (see Figure 6) that shows the impact of five different payoff strategies. As you’ll see below, the results can vary based on the data in the three boxes at the top of the form, so you may want to experiment with the values in the boxes.
The five basic payoff strategies are minimum payment, minimum plus finance charges, minimum plus a fixed additional amount, a fixed monthly payment of any selected amount, and minimum plus new purchases. You can change the default values for the Additional payment amount and the Fixed payment (fixed monthly amount), which are entered at the top of the form. The Fixed payment defaults to the minimum due, rounded up to the nearest $10. If you plan to continue using the card, you also can enter the amount you expect to charge each month, on average.
When you click the Calc button, PayEmOff calculates the total amount you’ll pay with each payoff strategy, the total interest you’ll pay, and the amount of time needed to pay off the debt. If you change any of the three values at the top of the form, click the Calc button again to see the impact. If payoff using a particular strategy takes more than 100 years, the Duration column displays “err”.
You may be amazed at the difference in time and money the various strategies require. Since the minimum payment decreases as the balance decreases, the Minimum plan can take a very long time. If you keep adding new charges, it may be impossible to pay off the card in less than 100 years using the Minimum plan.
For detailed payment information, click the square button next to any of the plans (see Figure 7). PayEmOff will generate a report in HTML format, save it under the filename PayEmOff Card Analysis.HTM, and launch it in your browser. For each month from the current one until the card is paid off, the report will list the balance, amount paid, and finance charge. You can use the browser’s commands to print the report or save the report under a different name.
Whereas the Card Analyzer calculates strategies for a single card, the Payoff Strategy window (see Figure 8) calculates the best way to pay off all your cards. You can access this window as soon as you’ve entered more than one card. After you enter a number of cards, you can change the order in which they are displayed by highlighting a card and selecting Card up or Card down from the Cards pull-down menu, or the item’s context menu.
The Payoff Strategy window assumes you’re not continuing to use the cards, so there is no Average purchases field where you can enter an average charge amount, and no Min plus purchases plan. Two of the four remaining plans — Minimum and Minimum plus finance — have the same meaning in the Payoff Strategy window as in the Card Analyzer. For each card, you pay either the minimum or the minimum plus the finance charges. In the Payoff Strategy window, the two other options — Minimum plus additional and Fixed payment — have a slightly different meaning when considering all cards at once.
Under the Minimum plus additional plan, you pay the minimum on all but one card-the first card in the payoff order. That first card gets the full amount specified in the Additional payment box until it’s paid off, and then the additional amount goes to the next card in the payoff order.
The Fixed payment plan is similar. In the Fixed payment box you enter the total amount that will go to your credit cards each month. This defaults to the sum of the first minimum payments for all the cards, rounded up to the nearest $10. You cannot enter a lower value, but you can increase it. All cards but the first in the payoff order receive the minimum payment amount; the first receives the remainder of the fixed payment amount. When the first card is paid off, the remainder goes to the next in the payoff order.
The payoff order can make a big difference in both the amount of time required to retire the debt and money you will spend. There are five options: In displayed order, Highest APR first, Highest balance first, Lowest APR first, and Lowest balance first. In general, you’ll save the most money by paying the card with the highest APR first, but there may be reasons to try a different order. For example, you might want to pay off the card with the lowest balance first and then cancel that card.
As with the Card Analyzer, you’ll see that different strategies and amounts can have a large impact on the amount of time and money required to pay off your credit card debt. You can see the effect of different payment amounts or payoff orders by changing these values and clicking the Calc button again.
For details on the impact of a particular payoff strategy, click the square button next to it. If Milestones only is selected in the Report detail box, you’ll get a simple report indicating the month in which each card will be fully paid off and which card will next receive payment priority (see Figure 9). The report’s header indicates the strategy used and, if relevant, the payoff order. This report is saved under the filename PayEmOff Payoff Strategy.HTM and launched in your browser.
The Full details report includes every payment on every card from the current month until the final payoff. This report, stored using the filename PayEmOff Payoff Detail.HTM, can be quite large, and you won’t want to display it often. The report header indicates the strategy used and lists the cards in payoff order, associating each card with a number. The payments for each month are listed in a sub-table, with the card’s number in the first column and the amount of the payment in the second. With Internet Explorer, if you hover the mouse over a row in the sub-table, the card name will appear as a tooltip (see Figure 10). As with the other reports, you can print from your browser, or save the report under a different name.
Suppose you determine that by paying $100 more than the minimum on credit card debt each month you would pay everything off in 5 years rather than 50, and save $14,000 in interest payments. What if you invested that extra $100 instead? PayEmOff lets you try it! Select Investment calculator from the Tools menu or click its big dollar-sign button on the toolbar (see Figure 11).
To see how Investment calculator works, enter 0 for Initial deposit, a Monthly payment of 100, an Interest rate of 10 percent, and an Investment period of 60 months (5 years). When you’ve entered four of the five values in the top portion of the window, the equal-sign button next to the fifth will become enabled. Click that button (in this case, the Final value) to see what you’d have at the end of five years. By investing $100 a month at 10 percent for five years, you gain not quite $2000 in interest. By putting that same $100 a month toward reducing debt, you save $14,000.
The Investment Calculator can work out any of the five values based on the other four. If exactly four are filled in, the button next to the fifth will be enabled. If they’re all filled in, all five buttons will be enabled. For example, change the final value to $14,000 and click the button next to Interest rate. To reach $14,000 by investing $100 a month for 5 years, you’d need an interest rate over 30 percent!
Now try Mortgage Calculator (see Figure 12). Its toolbar button looks like a house with a dollar-sign inside. Fill in the fields for Principal amount, Mortgage duration in months (commonly 360) and Interest rate, and click the button next to Monthly payment to see what you’d have to pay. For example, a 30-year mortgage of $100,000 at 8 percent will require a monthly payment of about $734. Try entering the specifics of your own mortgage, and also enter the number of payments made thus far in the box at lower left. At the beginning, most of your payments go toward interest; little goes toward principal. You also can check the result of paying extra principal each month. Just enter the amount in the Extra principal field within the box on the lower right and click the associated button. Paying an extra $100 in the example $100,000 mortgage would reduce the interest paid by over $60,000 and reduce the mortgage duration to about 21 years.
PayEmOff doesn’t predict, to the penny, what each month’s payment on each credit card will be. That’s not the point. Because of grace periods, daily calculations, and other differing practices, the values calculated by PayEmOff will not match your credit card bills precisely. But PayEmOff’s calculations are close enough to serve the real purpose-estimating and comparing the impact of different payoff strategies.
Modern versions of Delphi include a powerful set of mathematical tools in the Math unit. PayEmOff relies on these for its investment and mortgage calculations. The program’s unusual degree of visual customization introduced some interesting programming puzzles. To provide the main window with a bitmap background, PayEmOff uses three custom-draw event handlers, as well as some specialized workarounds. The main menu’s customized fonts are accomplished through standard owner-draw routines, but getting the top-level items to display correctly required some serious exploration.
Delphi’s Math unit contains a variety of advanced mathematical functions such as hyperbolic trig, logarithmic, statistical, and financial functions. PayEmOff’s mortgage and investment calculators make use of the financial group. For convenience, PayEmOff wraps all of its mortgage and investment calculations in the functions MortCalc() and InvestCalc(), both defined in the dbtfuncs.pas unit. MortCalc() takes as its arguments the principal amount financed, monthly payment, interest rate, and number of months, along with a VAR string argument in which MortCalc()can return an error message, if necessary. Exactly one of the numeric arguments must be negative, and the function returns the value corresponding to the negative argument. To do so, it calls one of the Math-unit functions PresentValue(), Payment(), InterestRate(), or NumberOfPeriods(), depending on which value is needed.
When using the Math unit’s financial functions, it’s important to remember that amounts paid out must be expressed as negative numbers. The Payment() function returns a negative value, so MortCalc() must reverse the sign. For the other three functions, it reverses the sign of the payment argument. The PresentValue argument for each function represents the amount of the mortgage, and the FutureValue argument (the balance at the end of the mortgage period) is zero.
InvestCalc() works in much the same way. It receives as arguments the initial investment, monthly payment, interest rate, number of months, and final value. The initial investment or monthly payment may be zero, as long as they are not both zero. Here again, exactly one of the arguments must be negative, and the function returns the value corresponding to that argument by calling the Math unit function PresentValue(), Payment(), InterestRate(), NumberOfPeriods(), or FutureValue(). Since both the initial investment and the monthly payment are values paid out by the user, they are passed as negative values.
If the passed arguments aren’t valid, InvestCalc() returns an error message in its VAR String argument. For example, suppose the function is calculating the interest rate required to achieve a particular final value, but the sum of the initial investment and monthly payments is greater than the specified final value. That would require a negative interest rate. In such a case, InvestCalc() returns an error message in the VAR parameter S. The calling function must check for a non-empty value in this argument, and take appropriate action.
Displaying Background Images
All of PayEmOff’s windows (except the Display options window itself) have an option to display a tiled background image. For all but the main form, a simple OnPaint event handler calls the Draw method of the form’s Canvas property to draw the image, repeating for as many rows and columns as required to fill the client area.
The main form is a different story, because its client area is entirely filled by a TListView component. The background image is drawn in the TListView’s OnCustomDraw event handler. The OnCustomDrawItem and OnCustomDrawSubItem event handlers draw the item data without obscuring the background. Note that custom draw is not the same as owner draw; in fact, the TListView’s OwnerDraw property must be set to False. An owner draw TListView can only control the display of the individual items; the custom draw event handlers control the display of the background as well.
The OnCustomDraw event handler draws the specified image on the TListView’s Canvas in much the same way as the OnPaint handler does for the other forms. It sets the DefaultDraw argument to True. If DefaultDraw is False, the OnCustomDrawItem event handler will not be called.
When a TListView’s ViewStyle property is set to vsReport, as it is here, the OnCustomDrawItem handler is called to draw the icon and name for each item in the first column. In this case, the handler draws the icon corresponding to the item’s ImageIndex property, extracting the property from the TImageList defined in the TListView’s SmallImages property. Next the handler uses the API function SetBkMode() to set the canvas’s background mode to TRANSPARENT, so the background will show through behind the text. A call to the DrawTextEx() API function with the DT_CALCRECT flag fills the TRect variable R with the size of the rectangle needed to enclose the item’s Caption text. Another call to DrawTextEx() actually draws the text. The DT_ENDELLIPSIS flag causes DrawTextEx() to replace the end of the text with an ellipsis (…) if the text won’t fit in the specified area. Finally, if this is the selected item, the OnCustomDrawItem event handler inverts the rectangle occupied by the text (stored in the variable R) by setting the canvas’s CopyMode property to cmDstInvert and copying the contents of that rectangle to itself.
At this point, there’s a problem, possibly a logical flaw in the implementation of the TListView component. If the OnCustomDrawItem event handler sets its DefaultDraw argument to True, the default code for drawing a TListView item’s caption is invoked, obscuring the event handler’s careful work. But if DefaultDraw is set to False, the OnCustomDrawSubItem event handler never gets called. To work around this difficulty, the OnCustomDrawItem event handler sets DefaultDraw to False, then explicitly calls OnCustomDrawSubItem for each additional column.
The OnCustomDrawSubItem event handler draws the text for the columns after the first. It calls the item’s DisplayRect() method to get the rectangle defining the entire row, then checks the column widths and adjusts the rectangle’s Left and Right fields so the rectangle fits the subitem’s column. In its call to DrawTextEx(), the handler adds the DT_RIGHT flag, causing the text to be drawn right aligned in the specified rectangle.
Column Resizing Issues
There are other difficulties associated with a TListView that has an image background. When the user resizes the columns, the background is not automatically refreshed, and the TListView component does not trigger an event at the end of the resizing process. The Ctrl+NumPadPlus keystroke, which automatically sizes every column to fit its contents, also scrambles the background.
My first thought was to set the TListView’s ShowColumnHeaders property to False, thereby suppressing the headings, and add a separate THeaderControl. The THeaderControl component looks a lot like a TListView’s column headings, and provides events during resizing. I trapped the Ctrl+NumPadPlus keystroke to prevent it from reaching the TListView. However, the result wasn’t satisfactory. The columns didn’t snap to their new widths until resizing was complete, and double-clicking on the section divider to the right of a column did not automatically size the column to its contents.
In the end, I devised a way to get notification during column resizing. I added an OnIdle event handler to the TApplicationEvents component on the main form. The OnIdle handler is called once each time the program goes into an idle state-that is, when the program has processed all pending messages. OnIdle obtains the handle of the SysHeader32 control within the TListView and sends HDM_GETITEM messages to the control to get the width of each header section. If any of those widths don’t match the corresponding column width in the TListView, OnIdle adjusts the column width and calls the TListView’s Refresh method. This protects the background from getting scrambled by column resizing or Ctrl+NumPadPlus.
Refreshing the TListView repeatedly during resizing causes a flickering effect that’s more annoying on some systems than others. If the No flicker box is checked in Display options, the OnIdle event handler doesn’t refresh the TListView directly. Instead, it enables a TTimer component whose OnTimer event handler checks repeatedly to see whether the header is still being resized. As soon as the resizing ends, the TTimer refreshes the TListView and sets its own Enabled property to False. In this mode, the background may be displayed imperfectly during resizing, but it looks fine when resizing is complete.
Owner Draw Menus
Two things are necessary to create an owner draw menu in Delphi. The event handlers OnMeasureItem and OnDrawItem must be defined for the individual menu items, and their ultimate owner (a TMainMenu or TPopupMenu component) either must have its OwnerDraw property set to True, or must have a non-nil value for its Images property. The OnMeasureItem event handler reports the height and width of the area needed to draw the item, and the OnDrawItem event handler performs the actual drawing. In PayEmOff, these are represented by the methods AllMeasureItem and AllDrawItem.
AllMeasureItem uses the DrawTextEx() API function with its DT_CALCRECT flag to calculate the rectangle required to hold the menu item’s text. If the menu item has a shortcut, it appends a tab and the text representing the shortcut before making this measurement. Special handling is required for any menu items marked with the Default property. Normally these are displayed in boldface, but under PayEmOff the base font might be bold already. If that’s the case, it sets the font size one point larger for Default items. It returns the calculated height plus two pixels, and the calculated width plus 16 pixels (to leave room for a checkmark).
AllDrawItem handles drawing selected, unselected, disabled, and checked menu items. It doesn’t handle radio-button style menu items, nor does it display images based on the ImageIndex; however, it could easily be extended to do so if necessary. For a checked menu item, it use the Canvas.PolyLine() method to draw a simple checkmark. Using DrawTextEx(), it draws the menu’s caption aligned at the left of the available rectangle, and the menu’s shortcut key (if present) aligned at the right.
To draw a disabled menu item, it first draws the text using the clHighlight color, offset one pixel to the right and one pixel down from the base location. It calls the Windows API function SetBkMode() to set the background mode to TRANSPARENT. Then it sets the font color to clGrayText and draws the text at the base location. The result looks just like a standard disabled menu item, except that it uses the selected font.
Windows’ owner draw handling for menus theoretically permits you to define any height and width for menu items. However, in practice it won’t actually increase the height of the main menu bar. If PayEmOff used a standard main menu, the top-level menu items wouldn’t fit properly when using a large font. Instead, it uses a modern menu-style toolbar, like the menu in Internet Explorer 5.
Creating such a toolbar-menu is simple in Delphi. Add the toolbar to the form, set its Flat and ShowCaptions properties to True, and add a button for each top-level menu item. Set the button captions to match the captions of the existing TMainMenu, and set the MenuItem property for each button to the corresponding top-level menu item. Set the Grouped property for each button to True. Finally, clear the form’s Menu property.
That’s all you do for a normal toolbar-menu, but getting an owner draw one proved difficult. The toolbar-menu buttons themselves used the specified font, but the OnDrawItem and OnMeasureItem handlers for the menu items were never called. After much study and testing, I found the solution. Submenus assigned to a toolbar-menu are not treated as owner drawn even when the TMainMenu that owns them has OwnerDraw set to True. However, if the main menu’s Images property points to a TImageList, even an empty one, the submenus are treated as owner drawn.
One more problem cropped up in relation to changing the font used by the toolbar-menu. Apparently the size and location of the top-level menu items get stored internally, and this information is not automatically updated when the button’s size changes due to a font change. If the new size was substantially different, the buttons didn’t respond correctly to the mouse passing over them. To force the toolbar-menu to recalculate based on the changed font, I set each button’s AutoSize property to False, then back to True.
PayEmOff’s mathematics is fairly pedestrian, once you get past the Math unit functions. The real programming challenge lay in the pitfalls of implementing the thoroughly user-configurable display.
Neil J. Rubenking, the author of PayEmOff, is the Contributing Technical Editor to PC Magazine. Sheryl Canter is the editor of the Utilities column and a Contributing Editor of PC Magazine.
Copyright © 2004 Ziff Davis Media Inc. All Rights Reserved. Originally appearing in PC Magazine.