To see how menus work, you can add one to the h-CustOrderWin3.w window. As it does with other objects, the AppBuilder can define most of the statements you need for your menu, using a special menu builder tool. Once you complete the menu, you can examine the syntax to confirm the exact ABL statements needed to do the job.

To define a menu bar for the sample window:

  1. Open h-CustOrderWin3.w and save a new version as h-CustOrderMenu.w.
  2. Click the Object Properties button for the window.

    Remember that if the window’s frame or some other object is selected, you can use the key CTRL+Click sequence to make the window the currently selected object in the AppBuilder.

  3. In the Object Properties dialog box, click the Menu Bar button .
  4. In the menu bar’s property sheet, call the Menu m_CustWin.

    You will add the following submenus to the menu:

    • Buttons — Duplicates what the radio set and the First, Next, Prev, and Last buttons do
    • Show — Duplicates the Show Warehouse Info toggle box
    • Help — Displays information about the window
  5. Define the first of these submenus by entering a Label of Buttons. When you tab out of that field, a default Object name of m_Buttons is provided for you:

    You can define all the levels of submenu and menu items together in this property sheet. To indicate the hierarchy, use the << and >> buttons to indent one item relative to the one above it.

  6. Click the Insert button to add three new menu items in the Buttons submenu.
  7. To indicate that they are menu items of the Buttons submenu, click the >> button to indent the first of the items. The others indent automatically.
  8. Give the three items labels of No &First/Last, No &Prev, and Allow &All, respectively. Accept the default object names provided for you.

    The ampersand in each label represents a menu mnemonic. The mnemonics let the user press a sequence of keys, each beginning with the ALT key, to select any menu item from the hierarchy. The ampersand precedes the mnemonic for each of these menu items. By default the top-level submenus are given mnemonics of their first letters, so when you are done the key sequence ALT+B, ALT+F selects the No First/Last menu item. When you press the ALT key the mnemonics are underlined to let you see what key sequences are available to you. (Showing the mnemonic underscores after the user presses ALT is the Microsoft standard and OpenEdge follows it.)

    If you define a menu mnemonic key combination that duplicates an accelerator, the accelerator takes precedence.

  9. Click the Rule button to insert a rule following these three items.
  10. Click the Insert button and define an item with a label of Navigation:

    This new item is a submenu. The menu bar property sheet is flexible enough to allow you to define the entire hierarchy from the top down. It determines that this is a submenu when you add further nested items to it. If you need to, you can click the Up and Down buttons to rearrange the order of items in the menu.

  11. Click Insert followed by the >> button to add an item nested under Navigation, with a label of First.
  12. Click the Key button to enter the dialog box that lets you define an accelerator key sequence for the menu item.
  13. Press the up arrow on the keyboard to register that as the accelerator key for the First button. Its keyboard name is displayed as CURSOR-UP:
  14. Click OK to accept this.
  15. Define three more menu items at this level with labels of Next, Prev, and Last. Give them the accelerator values right arrow (CURSOR-RIGHT), left arrow (CURSOR-LEFT), and down arrow (CURSOR-DOWN), respectively:

    The double indentation identifies Navigation as a new submenu with four items as menu items under it.

To provide trigger blocks to execute when these items are selected:

  1. From the design window, select Buttons > No First/Last, then select Window > Code Section Editor to bring up the trigger code for m_No_FirstLast.
  2. To duplicate the effect of the radio set button with the same label, copy its ASSIGN statement into the new trigger:
    DO:
      ASSIGN BtnFirst:SENSITIVE IN FRAME CustQuery = NO
      BtnLast:SENSITIVE IN FRAME CustQuery = NO.
    END.
  3. Make one change to the statement to qualify each button with the name of the frame it is in.

    Why is this necessary here and not in the trigger block for the radio set? Both the buttons and the radio set are in the frame called CustQuery, so the AVM identifies the frame for the buttons by default. The menu, however, is not part of the frame, but rather is owned by the window. For this reason the AVM requires that you identify the frame where the buttons are located.

    This is the CHOOSE trigger for the m_No_Prev item:

    DO:
      BtnPrev:SENSITIVE IN FRAME CustQuery = NO.
    END.
  4. The next code block is the trigger for the m_Allow_All item. So that you do not have to type IN FRAME CustQuery three times, make it the default frame for an entire DO block:
    DO:
      DO WITH FRAME CustQuery:
        ASSIGN BtnFirst:SENSITIVE = YES
        BtnLast:SENSITIVE = YES
        BtnPrev:SENSITIVE = YES.
      END.
    END.
  5. Define trigger actions for the four Navigation menu items. These triggers duplicate the actions of the CHOOSE triggers for the four buttons with the same labels. Often you will want some of your menu items to duplicate the action of toolbar buttons. In general, it is considered appropriate user interface design to provide a menu item for every toolbar button, such that the toolbar buttons duplicate the most frequently used menu items. One way to do this without duplicating code is to apply the CHOOSE event to the button from the menu item, as in this trigger block for the m_First menu item:
    DO:
      APPLY "CHOOSE" TO btnFirst IN FRAME CustQuery.
    END.
  6. Make similar changes to the m_Prev, m_Next and m_Last triggers to enable their actions for the same menu items as well.
  7. Run the window and try out all the buttons and accelerators, including the nested items under the Navigation submenu:

To complete your menu bar:

  1. Go back into its property sheet. You can do this by selecting any item in the menu in the design window and clicking the Object Properties button.
  2. Add a top-level submenu called Show, with a menu item of Warehouse Info. Check on the Toggle-box toggle box to make this a menu item that represents a logical value.
  3. Add a final top-level submenu called Help, with a menu item called Help About. The property sheet should look like this when you finish:

    The Warehouse Info item is selected to show that the toggle box is checked

  4. Define a trigger for the Warehouse Info item:
    DO:
      DO WITH FRAME CustQuery:
        IF SELF:CHECKED THEN
          ASSIGN lShowWarehouse:SCREEN-VALUE = "YES"
          cWorstWH:HIDDEN = NO
          cBestWH:HIDDEN = NO.
        ELSE
          ASSIGN lShowWarehouse:SCREEN-VALUE = "NO"
          cWorstWH:HIDDEN = YES
          cBestWH:HIDDEN = YES.
      END.  
    END.

    Because it is a toggle box item, it has a VALUE-CHANGED trigger rather than a CHOOSE trigger.

    This duplicates the code for the Warehouse Info toggle box in the window, but also sets the screen value of that toggle so that the two are kept in sync. Remember that the SELF keyword within a trigger block always refers to the object handle that invoked the trigger. The CHECKED attribute tells you whether the menu item is currently checked or not. Each time you select this menu item, the check box alternately appears and disappears, and the value of CHECKED reverses between true and false.

As with earlier triggers, you have to enclose all of this in a DO WITH FRAME CustQuery block to identify all these objects.