[View INPRISE Home Page][View Product List][Search This Web Site][View Available Downloads][Join Inprise Membership][Enter Discussion Area][Send Email To Webmaster]
INPRISE Online And ZD Journals Present:

C++Builder Developer's Journal


Implementing a recent-files list
By Kent Reisdorph

Most programs that use document files maintain a list of most-recently-used files. This list, often called an MRU list, is dynamically created by the application as the user works with document files.

VCL doesn't provide built-in support for an MRU list. So, in order to implement an MRU list in your C++Builder applications, you'll have to do it yourself. In this article, we'll show you how to create and maintain such a list. You'll use the Registry to store the list of files. Along the way, we'll introduce some of the features of the TMenu class.

A typical MRU list
While no standards committee governs the use of MRU lists, you'll see certain common features in most MRU lists. Let's take a quick look at the feature set for a typical list.

First, the list shouldn't be visible when you run the application for the first time. In other words, if there are no recently used files, then the list should be hidden. As files are opened, they'll appear in the list. Typically, an MRU list will have a maximum number of entries--generally five to ten. The list should be maintained on a first-in, first-out (FIFO) basis so the last file used is always at the top of the list. Once the list grows to the maximum size, the oldest file is removed to make room for the newest file.

Typically, the MRU list shows the complete path and filename of the document file. The list usually associates a hotkey with each menu item. For example, the hotkey for the first item is usually 1, the hotkey for the second item is 2, and so on. The MRU list should appear on the File menu, just above the Exit menu item.Figure A shows a typical list.

Figure A: A typical MRU list looks like this

Not every application uses this exact approach, but such a layout seems to be the most widely used. (Note that C++Builder uses a different scheme; it implements the MRU list on a pop-up menu called Reopen. I don't particularly like this non-standard approach, and I wouldn't write my own applications using this method.) Some applications place the MRU list at the very end of the File menu, which is a slight variation. In any case, the decision of where to put the list is up to you. Now that you know how the MRU list should look and act, you can get to work on the design stage.

Designing the MRU list
There are many ways to approach the creation of an MRU list. First, let's decide what ingredients we need. At a minimum, you'll require the following:

  • A way to show the MRU list when it's needed and hide it when it isn't
  • A way to detect when an MRU menu item is clicked
  • An event handler that performs some action when an MRU item is clicked
  • A routine to manage the list (adding new items and deleting old items)
  • A place to store the filename strings while the program is running
  • A more persistent place to store the filename strings between application instances

VCL easily handles the first three items via the TMenu class and the use of events. For string maintenance, you'll use a TStringList to store the list of filenames at runtime. Finally, you'll use the Registry for persistent storage of your MRU list. Let's break this process down into three pieces so it makes more sense.

Managing the menu
You can insert the items into the File menu in one of several ways. You could use TMenuItem's Insert method to insert the menu items into the File menu as needed. You could also use the API menu functions. There's an easier way, however--you'll create a menu separator and as many blank menu items as needed for your MRU list. Then you'll just hide the new menu items until you're ready to display them. You can set the Visible property of the menu items and separator to False at design time, then set it to True at runtime when you need to display them.

Begin by dropping a MainMenu component on a blank form. Then, double-click the MainMenu icon to start the C++Builder Menu Designer. To quickly insert a pre-built File menu into the main menu, use the Insert From Template option. Now, create a separator just above the Exit item separator (type a dash in the menu item's Caption property and press [Enter]) and change its Name property to MRUSeparator. Create five menu items under the separator and name them MRU1 through MRU5. You can leave the Caption property blank, since the menu item text will be supplied at runtime. Select all five blank menu items and set the OnClick event handler to MRUClick--doing so will allow all the menu items to use the same OnClick event handler. Set the Visible property for the separator and the blank menu items to False. Now, close the Menu Designer and test the menu. It should look like a regular File menu, since the MRU list is initially hidden.

But at what point do you set the Visible property to True? Once again, it's VCL to the rescue. You can create an OnClick handler for the top-level File menu. This OnClick event will give you a chance to modify the menu before it's displayed--a perfect time to show the necessary MRU menu items. You can't set up the event handler for the MRU click events at this point, because you haven't yet determined how you're going to store the filenames. Let's take a look at that issue now, then return later to the OnClick event handler.

Storing the list of files
You could use the Tag property of each menu item to store the filenames--an idea that has some merit, but also some drawbacks. Instead, you'll store the filenames in a separate TStringList object, which will be a member of your main form's class.

As an added benefit, the TStringList gives you a convenient way to implement the FIFO aspect of the MRU list. When the user opens a new file, you'll add the filename to the top of the list and delete the last item if necessary. For example,

    const int maxItems = 5;
    ...
    if (OpenDialog1->Execute()) {
    // Open a file, etc.
    // Add the filename to the MRU list.
    MruList->Insert(0, OpenDialog1->FileName);
    // Remove the last item if the list is full.
    if (MruList->Count == maxItems + 1)
    MruList->Delete(maxItems);
    }

is all the code required to maintain a FIFO list of filenames--slick and easy. Naturally, you'll create your string list in the form's OnCreate event handler and delete it in the OnDestroy event handler.

The OnClick event handler
Now that you know how to store the file list, let's back up and address the issue of the OnClick event handler for the MRU menu items. You need to translate the menu item clicked to an item in the string list. Since you know that the first MRU item is named MRU1, you can get the menu index of that menu item and figure out from there which MRU item was clicked, as follows:

    void __fastcall
    TForm1::MRUClick(TObject *Sender)
    {
    // cast Sender to a TMenuItem*
    TMenuItem* itemClicked =
    dynamic_cast(Sender);
    // cCalculate 0-based index from there
    int index =
    itemClicked->MenuIndex - MRU1->MenuIndex;
    // MruList[index] is the string we're after
    String FileName = MruList[index];
    // do something with FileName
    }

You can use similar logic to determine which of the MRU menu items to make visible. See Listing A for details.

Storing the strings in the Registry
You'll load the string list from the Registry when the form is created and write the string list to the Registry again when the form is destroyed. See Listing B for the code to save and restore the MRU list. Using the Registry to store the strings provides a near-foolproof method of keeping the MRU list around after the application has closed.

An example
Listings A and B contain a program that implements an MRU list. (You can download our sample files from www.zdjournals.com/cpb; click the Source Code hyperlink to reach the nov97.zip file.) The program contains a MainMenu component, a Memo component, an OpenDialog component, and a CheckBox component (the check box deletes the Registry key created by the program). The first time you run the program, the MRU list will be empty and hidden. You can use the File | Open... menu item to open any text file, which will be displayed in the Memo component.

As you open each file, its filename will be added to the MRU list. Close and restart the program, and you'll see that the MRU list is persistent between application instances. When you click on one of the MRU items, the file corresponding to that menu item will then be loaded in the Memo component.

Listing A: MRUUNIT.H


Listing B: MRUUNIT.CPP


Kent Reisdorph is a senior software engineer at TurboPower Software and a member of TeamB, Borland's volunteer online support group. He's the author of Teach Yourself C++Builder in 21 Days and Teach Yourself C++Builder in 14 Days. You can contact Kent at kentr@turbopower.com.
Back to Top
Back to 1997 Index of Articles

Copyright © 1998, Ziff-Davis Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of Ziff-Davis Inc. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis is prohibited.
Trademarks & Copyright © 1998 INPRISE Corporation.