An Unorthodox Approach to Menus

Now let's step a little off the beaten path. Instead of having drop-down menus in your program, how about creating multiple top-level menus without any popups and switching between the top-level menus using the SetMenu call? The NOPOPUPS program, shown in Figure 9-7, demonstrates how to do it. This program includes similar File and Edit items that MENUDEMO uses but displays them as alternate top-level menus.

NOPOPUPS.MAK

#------------------------

# NOPOPUPS.MAK make file

#------------------------

nopopups.exe : nopopups.obj nopopups.def nopopups.res

link nopopups, /align:16, NUL, /nod slibcew libw, nopopups

rc nopopups.res

nopopups.obj : nopopups.c nopopups.h

cl -c -Gsw -Ow -W2 -Zp nopopups.c

nopopups.res : nopopups.rc nopopups.h

rc -r nopopups.rc

NOPOPUPS.C

/*-------------------------------------------------

NOPOPUPS.C -- Demonstrates No-Popup Nested Menu

(c) Charles Petzold, 1990

-------------------------------------------------*/

#include <windows.h>

#include "nopopups.h"

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

{

static char szAppName [] = "NoPopUps" ;

HWND hwnd ;

MSG msg ;

WNDCLASS wndclass ;

if (!hPrevInstance)

{

wndclass.style = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc = WndProc ;

wndclass.cbClsExtra = 0 ;

wndclass.cbWndExtra = 0 ;

wndclass.hInstance = hInstance ;

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName = NULL ;

wndclass.lpszClassName = szAppName ;

RegisterClass (&wndclass) ;

}

hwnd = CreateWindow (szAppName, "No-Popup Nested Menu Demonstration",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, nCmdShow) ;

UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ; DispatchMessage (&msg) ;

}

return msg.wParam ;

}

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)

{

static HMENU hMenuMain, hMenuEdit, hMenuFile ;

HANDLE hInstance ;

switch (message)

{

case WM_CREATE :

hInstance = GetWindowWord (hwnd, GWW_HINSTANCE) ;

hMenuMain = LoadMenu (hInstance, "MenuMain") ;

hMenuFile = LoadMenu (hInstance, "MenuFile") ;

hMenuEdit = LoadMenu (hInstance, "MenuEdit") ;

SetMenu (hwnd, hMenuMain) ;

return 0 ;

case WM_COMMAND :

switch (wParam)

{

case IDM_MAIN :

SetMenu (hwnd, hMenuMain) ;

return 0 ;

case IDM_FILE :

SetMenu (hwnd, hMenuFile) ;

return 0 ;

case IDM_EDIT :

SetMenu (hwnd, hMenuEdit) ;

return 0 ;

case IDM_NEW :

case IDM_OPEN :

case IDM_SAVE :

case IDM_SAVEAS :

case IDM_UNDO :

case IDM_CUT :

case IDM_COPY :

case IDM_PASTE :

case IDM_CLEAR :

MessageBeep (0) ;

return 0 ;

}

break ; case WM_DESTROY :

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}

NOPOPUPS.RC

/*-----------------------------

NOPOPUPS.RC resource script

-----------------------------*/

#include "nopopups.h"

MenuMain MENU

{

MENUITEM "MAIN:", 0, INACTIVE

MENUITEM "&File...", IDM_FILE

MENUITEM "&Edit...", IDM_EDIT

}

MenuFile MENU

{

MENUITEM "FILE:", 0, INACTIVE

MENUITEM "&New", IDM_NEW

MENUITEM "&Open...", IDM_OPEN

MENUITEM "&Save", IDM_SAVE

MENUITEM "Save &As...", IDM_SAVEAS

MENUITEM "(&Main)", IDM_MAIN

}

MenuEdit MENU

{

MENUITEM "EDIT:", 0, INACTIVE

MENUITEM "&Undo", IDM_UNDO

MENUITEM "Cu&t", IDM_CUT

MENUITEM "&Copy", IDM_COPY

MENUITEM "&Paste", IDM_PASTE

MENUITEM "C&lear", IDM_CLEAR

MENUITEM "(&Main)", IDM_MAIN

}

NOPOPUPS.H

/*------------------------

NOPOPUPS.H header file

------------------------*/

#define IDM_NEW 1

#define IDM_OPEN 2

#define IDM_SAVE 3

#define IDM_SAVEAS 4

#define IDM_UNDO 5

#define IDM_CUT 6

#define IDM_COPY 7

#define IDM_PASTE 8

#define IDM_CLEAR 9

#define IDM_MAIN 10

#define IDM_EDIT 11

#define IDM_FILE 12

NOPOPUPS.DEF

;-------------------------------------

; NOPOPUPS.DEF module definition file

;-------------------------------------

NAME NOPOPUPS

DESCRIPTION 'Demonstration of No-Popup Menu (c) Charles Petzold, 1990'

EXETYPE WINDOWS

STUB 'WINSTUB.EXE'

CODE PRELOAD MOVEABLE DISCARDABLE

DATA PRELOAD MOVEABLE MULTIPLE

HEAPSIZE 1024

STACKSIZE 8192

EXPORTS WndProc

The resource script has three menus rather than one. When the window procedure processes the WM_CREATE message, Windows loads each of the menu resources into memory:

hMenuMain = LoadMenu (hInstance, "MenuMain") ;

hMenuFile = LoadMenu (hInstance, "MenuFile") ;

hMenuEdit = LoadMenu (hInstance, "MenuEdit") ;

Initially, the program displays the main menu:

SetMenu (hwnd, hMenuMain) ;

The main menu lists the three options using the character strings ”MAIN:“, ”File...^^, and ”Edit...^^ However, ”MAIN:“ is disabled, so it doesn't cause WM_COMMAND messages to be sent to the window procedure. The File and Edit menus begin ”FILE:“ and ”EDIT:“ to identify these as submenus. The last item in each menu is the character string ”(Main)“; this option indicates a return to the main menu. Switching among these three menus is simple:

case WM_COMMAND :

switch (wParam)

{

case IDM_MAIN :

SetMenu (hwnd, hMenuMain) ;

return 0 ;

case IDM_FILE :

SetMenu (hwnd, hMenuFile) ;

return 0 ;

case IDM_EDIT :

SetMenu (hwnd, hMenuEdit) ;

return 0 ;

[other program lines]

}

break ;