Developing a Database Application:
The dBASE Plus Tutorial

Ken Mayer, Senior SQA Engineer, dBASE Inc.
Michael Nuwer, dBASE user

Phase VII
Creating The Menu

Goals and Objectives

The goals for Phase VII of this tutorial project are:

Additional Readings

What Is a Menu?

A Menu is the text interface that appears at the top of most Windows applications, and depending on the design, sometimes on forms that appear in the application.

The example application we are building uses a single menu attached to the application framework (_app.framewin), which is how we will also create our application. (This is because we are creating an MDI application -- if we were creating an SDI application, the menu might appear on each form.) While we do this there are decisions that affect the whole design of the application that must be considered.

For example, you could have an application that was SDI (Single Document Interface) -- which (normally) allows only one instance of any data form to be open at one time (although a developer could allow multiple instances of any one form). You could, instead, have an application that was MDI (Multiple Document Interface), which allows two or more instances of the same form to be open at one time and indeed allows multiple instances of the same form to be open at once. (It is possible to do a weird cross of MDI and SDI, which is how a lot of our applications work currently ... but let's not get into that here.)


The big differences between SDI and MDI (and this is a very quick over-view) are: Information provided by Gary White

This application will be an MDI application, which means that we need to remember that the form that currently has "focus" may change rapidly -- this will mean that as we create various aspects of the application, we will need to deal with some flexibility in our code.

The menu we design will have to have options for opening forms, generating reports, a menu to handle selecting which form to set focus to, and so on.

The Menu Designer

When you want to create a menu there is a special design surface. As with the other design surfaces in dBASE Plus, this is a "two-way-tool" -- in other words, the designer generates code and we can manipulate that code in the source editor and have it respected in the design surface. This is sometimes an easier way to fix any problems found in the code or simply to add or modify the existing code.

Menus are associated with forms (you must have a form to attach a menu to). In order to design a menu, let's go to the "Forms" tab of the navigator.

Double click on the third "Untitled" icon in this section of the navigator. This will bring up the menu designer.

This may not look like much, but it's pretty easy to use.

To put a menu option in, simply type the text you want to appear. If you want to have a hotkey that is activated with the <Alt> key and the letter for that menu (these are individual letters in menu text that are underlined, and calling their functionality is as simple as pressing the <Alt> key and the underlined letter, e.g., File) you need to preface that letter with an ampersand (&).

Let's create the "top" level of menu options for our application. These are the menu options that appear at the very top of the form, and if you click on them, will bring up a "sub-menu". The "top" level menu options are contained by the menubar object. The other menu options you will create will be contained by the menu option above them (or to the left of them).

Start by typing in the first position: &File and then press the <Tab> key on your keyboard. This moves you over to the right one position. Type: &Reports and <Tab>. Type: &Help. At this point, we're going to use a sneaky trick and have dBASE Plus do the work: go to the "Menu" menu option, and select 'Insert "Window" Menu'. dBASE Plus inserted this to the left of the current position, which is why we put the "Help" menu in before inserting the Window menu.

The option to insert the window menu adds a single line of code into the source of the menu for the constructor code that tells dBASE Plus to handle the MDI windows automatically. (See note about a bug in the Window menu and Windows 95/98 below.)

Save your work so far, by pressing <Ctrl>+S, and when asked for a name, enter "Tutorial" and click "Save".

The File Menu
Next we need to go back to the File menu and add the options we need there. To get back to the File menu, you can do it by either using the mouse and clicking on it, or using a "back-tab", which is simply <Shift>+<Tab>.

A consideration for your menu that may not seem obvious is that you should name each menu object (which is what we are creating right now by typing in text in the position we want to appear in the menu -- each of these is a menu object). If we do not name them, then dBASE Plus will name them something very non-intuitive, like "MENU44", "MENU45", etc. This makes it difficult, when examining the menu code (or if you get fancy, modifying the menu from code) to know which menu you are manipulating.

We are currently positioned on the "File" menu object, so go to the inspector, and name this "File" by finding the name property, and typing "File", and then pressing <Enter>.


Note: If you do not press the <Enter> key here and simply leave this item in the inspector, it will revert to the previous value. You can also use the up/down arrows to save your value, but if you just go straight back to the designer without saving what you entered, it will go away. This is a bit frustrating, but is "as designed". Get used to it -- when you change values in the inspector -- if the field shown is yellow, you must press the <Enter> or the up/down arrow keys for it to "stick" -- this is how it works in all design surfaces of dBASE Plus!

Click back on the design surface.

To add items in the menu under the word "File", simply use the down arrow. This will create a new menu object that is considered to be a sub menu of the File menu.

Type: &Open to give the prompt for this menu.

Name this menu object "Open" in the inspector.

Tab to the right from the "Open" menu, and note that we are given a new menu object to the right. We are going to list each of the forms that can be "opened" here, by entering them at this point. We will come back (as noted elsewhere) and add code that will fire when the user selects the form to open.

Do the following to add the new menu options that will appear under the "Open" menu:

You have just created a series of menu options that will only appear if the user selects the "Open" menu, and in the case of the "Lookup" menu, they will only see these two menu options if they select "Lookup". These are often called "nested" menus.

We need to add the next option, which is the "Close" option. So set focus back to the design surface (by clicking on it), click on the word "Open" in the "File" menu, and use the down arrow.

In this position, type: &Close. In the inspector, change the name of this menu option to "Close".

Use the down arrow again to add another menu option to the file menu. This time, however, we are going to put what is called a "separator" in -- this is a menu object that cannot get focus, and displays simply a line across the menu. It is used to separate different groups of menu objects from each other.

All that is necessary to create a separator is to go to the inspector, and select the separator property, and either double-click it, or use the combobox, and select "true". However, just to keep things straight, let's assign a name to this menu object in the inspector as well of "Separator1".

The last item for the file menu is the Exit option, which will be used to close the application. Use the down arrow and type: E&xit. Name this menu object "Exit" in the inspector.

You should see something like what is in the image below for your menu:

The Reports Menu
The reports menu needs the following sub-menu options.
Menu TextNameshortCutseparator
Supplier InformationSuppliernonefalse
Inventory SummaryInventorynonefalse
Customer StatementsStatementsnonefalse
noneSeparator2nonetrue
Customer Address LabelsLabelsnonefalse


Note: It is possible to use the same menu names because of the way the containers work here. The "Supplier" menu under the reports menu is not going to conflict with the "Supplier" menu under the files/open menu, because dBASE Plus sees them as being completely different entities. Example -- the file menu's path down to the supplier menu is:
      this.FILE.OPEN.SUPPLIER
Where the path to the one for the reports is:
      this.REPORTS.SUPPLIER
To dBASE Plus these are very different, and so we can name them the same.

The Window Menu
This will have only one menu option that is always available, and we will have other options added dynamically during the time the application executes. This last part will be done automatically because of how we added the "Window" menu option. In the meantime, the one option that is currently in the menu is:
Menu Text NameshortCutseparator
Close &AllCloseAllnonefalse

We're going to add some simple code to the onClick event of the "Close All" menu. Click on that menu, click on the inspector, and select the "Events" tab. Select onClick and enter the following codeblock:

   {;CLOSE FORMS}

Make sure you press <Enter> to save this value.

Note that if you accidentally pressed the tool button, you will find that the source editor appears with a "Function method" and "return" statement -- your cursor will appear between these on a blank line. You can remove this by going to the "Method" menu and selecting "Delete Method" -- this will remove this and you can go back to the Inspector.


Note: without getting into a lot of the details involved in writing codeblocks, the semi-colon at the beginning of a codeblock is required if your codeblock is a statement codeblock that has no parameters. You can also begin a codeblock with a pair of pipe characters (||). For more details on codeblocks see online help (keyword is "codeblock").

This code simply closes any open forms in the application. It's rather handy in that it's a shortcut method, useful if you have a bunch of open forms.


Bug: On a Windows NT computer, the "Windows" menu works exactly as expected. When an MDI form is opened, it automatically appears in the menu and if it is the active form, a checkmark appears by it in the list (assuming more than one MDI form is open, you will see a list the open forms.)

However, on a Windows 95 or 98 computer, for whatever reason, the Windows menu does not always get or display the proper window information. Do not despair, there is a fix below which is a simple change in a property of one of the custom forms ... by using this workaround, we can make the application work the same in NT or in Win 95/98.


The Help Menu
We're not really going to create help for our application (that's a topic that would take a LONG time to delve into), but we will add an option to bring up the "About" dialog. This dialog is simply going to provide some basic information about the application.
Menu Text NameshortCutseparator
&About TutorialAboutnonefalse

Save It!
Press <Ctrl>+W to save your work and exit the designer.

Adding Code To the Menus: The Forms

The Forms
Earlier in this tutorial we created a number of forms. Now the question is how do we make them work with our application?

The way we do this is to attach them to the "Open" menu options of the application's menu.

To do this bring up the menu in the designer. (Right click on "Tutorial.mnu" in the navigator, and select "Design Menu" or click on the menu and press <Shift>+<F2>).

We're going to add some code to our menu so we are not repeating a set of programming statements for each form we need to open (we are using object oriented code techniques this way). To do this, click on the "Method" menu at the top of the screen, and select "New Method".

You will see that dBASE Plus has added the following to the source code of the menu:

   function Method
      
      return

Change the code to:

   function OpenForm( oForm )
     // set the top/left properties so the form isn't
     // *right* on top of the current one ...
     if type( "_app.framewin.currentForm" ) == "O"
        oForm.top  := _app.framewin.currentForm.top + 2
        oForm.left := _app.framewin.currentForm.left + 2
     else
        oForm.top  := 0
        oForm.left := 10
     endif
     oForm.open()
     oForm.setFocus()
   return

The code we added above is going to:

Click on the "Open" menu option, then on the "Customers" menu option. In the inspector go to the onClick event and click the tool button. This will put you in the source editor as we've seen for other parts of the product.

Enter the following code:

   function CUSTOMERS_onClick
      // open the customer form:
      local f
      f = new CustomerForm()
      // call the code we created elsewhere
      // to actually open the form
      class::openForm( f )
   return

We need to do the same for the appropriate forms for each menu option. Change the statement "f = new CustomerForm()" to the correct form for each of them ... remember that copy and paste is a useful feature of Windows (rather than retyping the code).

While we are here we should add the code that will be used to close the currently active form.

   function CLOSE_onClick
      // close current form if there is one
      if type( "_app.framewin.currentForm" ) == "O"
         _app.framewin.currentForm.close()
      else
         msgbox( "The currently active form cannot be closed "+;
                 "with this option.","Can't do it!", 64 )
      endif
   return

Add the About Form
We need to add code to the menu to actually open this form. Since it is a modal dialog, we will have to open the procedure file, but otherwise the code is pretty basic. Bring the menu back up one more time in the designer.

Click on "Help" and then "About Tutorial". In the inspector, click on the onClick event, and the tool button. This will bring up the source editor, and enter the following:

   function ABOUT_onClick
   set procedure to about.wfm additive
   f = new aboutForm()
   f.readModal()
   close procedure about.wfm
   return

Save the menu and exit.

Attaching the Reports

We have three reports and one set of labels to hook to the menu. The Invoice report is called from the invoice form, so there is no menu item for this report.

Although a report can be rendered straight to a printer, we are going to render them in a preview form for on screen viewing. When you ran the Tutorial Setup archive, a file named Preview.wfm was copied to the tutorial's main folder. We will use this form to view our reports. If the application's user wishes to print the report the preview form has buttons for that purpose.

To attach the reports in the menu, select the report menu, and then the first menu item listed, which should be "Supplier Information". Select the onClick event for this, and the tool button, and enter the following code:

   set procedure to suppliers.rep additive
   fPreview = new PreviewForm()
   // to open with ReadModal()
   fPreview.bModal = true 
   fPreview.viewer.fileName := "suppliers.rep" 
   fPreview.Open()

Do the same for the inventory report:

   set procedure to inventory.rep additive
   fPreview = new PreviewForm()
   fPreview.bModal = true 
   fPreview.viewer.fileName := "inventory.rep" 
   fPreview.Open()

and finally for the labels:

   set procedure to customer.lab additive
   fPreview = new PreviewForm()
   fPreview.bModal = true 
   fPreview.viewer.fileName := "customer.lab" 
   fPreview.Open()

The "suppliers" report would look like the following using the preview form:

The statements report is a bit different than the other three reports on the menu. This report is not called directly from the menu, but rather, it is called by the getdates.wfm form. So the menu item will open the getdates.wfm dialog. This is a modal form so it's going to opened the same way we opened the About.wfm form.

   function STATEMENTS_onClick
      set procedure to getdates.wfm additive
      local f
      f = new getdatesForm()
      f.readModal()
      close procedure getdates.wfm
      return

Summary

You have just created the menu that will be used with the Tutorial application project. However this menu is not fully functional until we build a start-up program for the application and attach the menu to the window of the application. Remember, our application is MDI, which, among other things, means that the menu does not appear at the top of each form. Rather it will appear at the top to main application window. In the next section we will create a start program which among other things will attach our menu to the application window.

Let's move on to the next part of the tutorial.


Proceed to the next part of the tutorial: Creating The Start Program/Application
Go back to the tutorial menu

Last Modified: November 11, 2002

The Legal Stuff: This document is part of the dBASE Plus Tutorial created by Ken Mayer and Michael Nuwer. This material is copyright © 2002, by Ken Mayer and Michael Nuwer. dBASE Plus is copyrighted, trademarked, etc., by dBASE, Inc., the BDE (Borland Database Engine) and BDE Administrator are copyrighted, trademarked and all that by Borland, International. This document may not be posted elsewhere without the explicit permission of the authors, who retains all rights to the document.