Borland Online And The Cobb Group Present:


February, 1995 - Vol. 2 No. 2

Under the Hood of Owl 2.0 - Understanding how menu merging works

In the accompanying article, BCJ - Changing the menu bar dynamically we show how you can use TMenuDescr objects to set up and modify an application's menu bar. The TFrameWindow class does most of the work that's necessary to make this possible. To see how these classes change the menu bar, let's take a closer look at the TFrameWindow class's MergeMenu( ) member function and its companion member functions­­MoveSubMenus( ) and DeleteSubMenus( ).

If you want to see the actual source code that implements the menu merging, choose Open... from the File menu, enter

\BC4\SOURCE\OWL\FRAMEWIN.CPP

in the File Name entry field, and click OK. When the editor window for this file appears, right-click inside the window and choose Go To Line... from the pop-up menu. In the Go To Line Number dialog box, enter 817 in the Enter New Line Number entry field and click OK. At this point, you should see the TFrameWindow::MergeMenu( ) function in the editor window, as shown in Figure A.

Figure A - You'll find the source code for the MergeMenu( ) function at line 817 of the FRAMEWIN.CPP file.

Table A - The TFrameWindow::MergeMenu( ) function creates these four TMenu objects.
Variable Purpose
oldMenu contains a copy of the current menu bar (for recovery if we can't set the menu when we get to the end of this function)
newMenu an empty menu that builds the new menu bar
resMenu modifies the current menu bar via the current module pointer and resource ID (The DeleteSubMenus( ) function uses this menu to free unused submenu resources.)
childMenu contains the merging menu items

At the beginning of this function, the TFrameWindow::MergeMenu( ) function creates four local TMenu objects, as shown in Table A. Once the MergeMenu( ) function creates these TMenu objects, most of the menu-item shuffling occurs inside the

for (int i=0; i < TMenuDescr::NumGroups; i++)

loop statements.

Once you start peeking inside the for( ) loop, it can be difficult to follow the execution path. To make it easier for you to track the for( ) loop and how its function calls affect the TMenu objects, refer to the values, function calls, and resulting menus that appear in Figure B.


Figure B - Menu-item shuffling occurs inside the MergMenu() function's for() loop.




When the program first enters the for( ) loop (the Beginning State in Figure B), the resMenu object contains the current menu bar, the childMenu object contains the merging menu bar pop-up menus, and the newMenu object contains an empty menu bar. Now, let's look at how these TMenu objects change as we execute the for( ) loop.

You should be aware that the variable TMenuDescr::NumGroups is the last value in an enumeration nested in the TMenuDescr class. Since this enumeration defines six previous values (beginning with 0), NumGroups has an integral value of 6. Therefore, the for( ) loop will execute six times.

During the first pass through the for( ) loop, the childMenuDescr object's FileGroup entry (the first value in the array) has a value of 0. This causes the program to call the MoveSubMenus( ) function to move the File pop-up menu from the resMenu object to the newMenu object, as you can see in the second row of Figure B.

During the second pass, the childMenuDescr object's EditGroup entry (the second value in the array) has a value of 1. This forces the program to call the MoveSubMenus( ) function to merge one menu from the childMenu object (the Edit menu) into the newMenu object and then to call the DeleteSubMenus( ) function. (Since the second parameter is 0, this call does nothing.)

In the third pass, the childMenuDescr object's ContainerGroup entry has a value of -1. This forces the program to call the MoveSubMenus( ) function with the third parameter of -1 (which causes it to do nothing) and then to call the DeleteSubMenus( ) function to delete the Search pop-up menu.

In the fourth pass, the childMenuDescr object's ObjectGroup entry has a value of 1. This forces the program to call the MoveSubMenus( ) function to merge one menu from the childMenu object (the new Tool menu) into the newMenu object and then to call the DeleteSubMenus( ) function to delete the old version of the Tool pop-up menu.

During the fifth pass through the for( ) loop, the childMenuDescr object's Window-Group entry has a value of 0. This forces the program to call the MoveSubMenus( ) function with a third parameter of 0 (the value of the TMenuDescr object's WindowGroup entry), which does nothing.

During the sixth and final pass, the childMenuDescr object's HelpGroup entry (the sixth value in the array) has a value of 0. This causes the program to call the MoveSubMenus( ) function to move the Help pop-up menu from the resMenu object to the newMenu object.

After the for( ) loop prepares the newMenu object, the program calls the application object's PreProcessMenu( ) member function. This function allows the current Document Manager (if one exists) to respond to the menu bar change.

Finally, the program calls the TWindow class's SetMenu( ) member function­­which calls the Windows SetMenu( ) function­­to install the newMenu menu in the frame window. If the SetMenu member function call returns 0 (the function failed to set the menu), the program will destroy the newMenu object and return FALSE from the MergeMenu( ) function. If the SetMenu( ) function call succeeds, the program will destroy the oldMenu object instead and return TRUE from the MergeMenu( ) function.

Return to the Borland C++ Developer's Journal index

Subscribe to the Borland C++ Developer's Journal


Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.