Character strings are not the only way to display a menu item. You can also use a bitmap. If you immediately recoiled at the thought of pictures of file folders, paste jars, and trash cans in a menu, don't think of pictures. Think instead of how useful menu bitmaps might be for a drawing program. Think of using different fonts and font sizes, line widths, hatch patterns, and colors in your menus.
The program we're going to examine is called GRAFMENU (”graphics menu“). The top-level menu is shown in Figure 9-8. The enlarged block letters are obtained from 40-by-16-pixel monochrome bitmap files created in SDKPAINT and saved as .BMP files; they could be pictures instead. Choosing FONT from the menu invokes a popup containing three options—Courier, Helvetica, and Times Roman—each displayed in its respective font (Figure 9-9). These bitmaps were created in the program using a technique involving a ”memory device context.“
Finally, when you pull down the system menu, you see that you have access to some ”help“ information, with the word ”Help“ perhaps mirroring the desperation of a new user (Figure 9-10). This 64-by-64-pixel monochrome bitmap was created in SDKPAINT.
The GRAFMENU program, including the four bitmaps created in SDKPAINT, is shown in Figure 9-11.
GRAFMENU.MAK
#------------------------
# GRAFMENU.MAK make file
#------------------------
grafmenu.exe : grafmenu.obj grafmenu.def grafmenu.res
link grafmenu, /align:16, NUL, /nod slibcew libw, grafmenu
rc grafmenu.res
grafmenu.obj : grafmenu.c grafmenu.h
cl -c -Gsw -Ow -W2 -Zp grafmenu.c
grafmenu.res : grafmenu.rc grafmenu.h \
editlabl.bmp filelabl.bmp fontlabl.bmp bighelp.bmp
rc -r grafmenu.rc
GRAFMENU.C
/*----------------------------------------------
GRAFMENU.C -- Demonstrates Bitmap Menu Items
(c) Charles Petzold, 1990
----------------------------------------------*/
#include <windows.h>
#include <string.h>
#include "grafmenu.h"
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
HBITMAP StretchBitmap (HBITMAP) ;
HBITMAP GetBitmapFont (int) ;
char szAppName [] = "GrafMenu" ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
HBITMAP hBitmapHelp, hBitmapFile, hBitmapEdit,
hBitmapFont, hBitmapPopFont [3] ;
HMENU hMenu, hMenuPopup ;
HWND hwnd ;
int i ;
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) ;
}
hMenu = CreateMenu () ;
hMenuPopup = LoadMenu (hInstance, "MenuFile") ;
hBitmapFile = StretchBitmap (LoadBitmap (hInstance, "BitmapFile")) ;
AppendMenu (hMenu, MF_BITMAP | MF_POPUP, hMenuPopup,
(LPSTR) (LONG) hBitmapFile) ;
hMenuPopup = LoadMenu (hInstance, "MenuEdit") ;
hBitmapEdit = StretchBitmap (LoadBitmap (hInstance, "BitmapEdit")) ;
AppendMenu (hMenu, MF_BITMAP | MF_POPUP, hMenuPopup,
(LPSTR) (LONG) hBitmapEdit) ;
hMenuPopup = CreateMenu () ;
for (i = 0 ; i < 3 ; i++)
{
hBitmapPopFont [i] = GetBitmapFont (i) ;
AppendMenu (hMenuPopup, MF_BITMAP, IDM_COUR + i,
(LPSTR) (LONG) hBitmapPopFont [i]) ;
}
hBitmapFont = StretchBitmap (LoadBitmap (hInstance, "BitmapFont")) ;
AppendMenu (hMenu, MF_BITMAP | MF_POPUP, hMenuPopup,
(LPSTR) (LONG) hBitmapFont) ;
hwnd = CreateWindow (szAppName, "Bitmap Menu Demonstration",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, hMenu, hInstance, NULL) ;
hMenu = GetSystemMenu (hwnd, FALSE) ;
hBitmapHelp = StretchBitmap (LoadBitmap (hInstance, "BitmapHelp")) ;
AppendMenu (hMenu, MF_SEPARATOR, NULL, NULL) ;
AppendMenu (hMenu, MF_BITMAP, IDM_HELP, (LPSTR) (LONG) hBitmapHelp) ;
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
DeleteObject (hBitmapHelp) ;
DeleteObject (hBitmapEdit) ;
DeleteObject (hBitmapFile) ;
DeleteObject (hBitmapFont) ;
for (i = 0 ; i < 3 ; i++)
DeleteObject (hBitmapPopFont [i]) ;
return msg.wParam ;
}
HBITMAP StretchBitmap (HBITMAP hBitmap1)
{
BITMAP bm1, bm2 ;
HBITMAP hBitmap2 ;
HDC hdc, hdcMem1, hdcMem2 ;
TEXTMETRIC tm ;
hdc = CreateIC ("DISPLAY", NULL, NULL, NULL) ;
GetTextMetrics (hdc, &tm) ;
hdcMem1 = CreateCompatibleDC (hdc) ;
hdcMem2 = CreateCompatibleDC (hdc) ;
DeleteDC (hdc) ;
GetObject (hBitmap1, sizeof (BITMAP), (LPSTR) &bm1) ;
bm2 = bm1 ;
bm2.bmWidth = (tm.tmAveCharWidth * bm2.bmWidth) / 4 ;
bm2.bmHeight = (tm.tmHeight * bm2.bmHeight) / 8 ;
bm2.bmWidthBytes = ((bm2.bmWidth + 15) / 16) * 2 ;
hBitmap2 = CreateBitmapIndirect (&bm2) ;
SelectObject (hdcMem1, hBitmap1) ;
SelectObject (hdcMem2, hBitmap2) ;
StretchBlt (hdcMem2, 0, 0, bm2.bmWidth, bm2.bmHeight,
hdcMem1, 0, 0, bm1.bmWidth, bm1.bmHeight, SRCCOPY) ;
DeleteDC (hdcMem1) ;
DeleteDC (hdcMem2) ;
DeleteObject (hBitmap1) ;
return hBitmap2 ;
}
HBITMAP GetBitmapFont (int i)
{
static struct
{
BYTE lfPitchAndFamily ;
BYTE lfFaceName [LF_FACESIZE] ;
char *szMenuText ;
}
lfSet [3] =
{
FIXED_PITCH | FF_MODERN, "Courier", "Courier",
VARIABLE_PITCH | FF_SWISS, "Helvetica", "Helvetica",
VARIABLE_PITCH | FF_ROMAN, "Tms Rmn", "Times Roman"
} ;
DWORD dwSize ;
HBITMAP hBitmap ;
HDC hdc, hdcMem ;
HFONT hFont ;
LOGFONT lf ;
hFont = GetStockObject (SYSTEM_FONT) ;
GetObject (hFont, sizeof (LOGFONT), (LPSTR) &lf) ;
lf.lfHeight *= 2 ;
lf.lfWidth *= 2 ;
lf.lfPitchAndFamily = lfSet[i].lfPitchAndFamily ;
strcpy (lf.lfFaceName, lfSet[i].lfFaceName) ;
hdc = CreateIC ("DISPLAY", NULL, NULL, NULL) ;
hdcMem = CreateCompatibleDC (hdc) ;
SelectObject (hdcMem, CreateFontIndirect (&lf)) ;
dwSize = GetTextExtent (hdcMem, lfSet[i].szMenuText,
strlen (lfSet[i].szMenuText)) ;
hBitmap = CreateBitmap (LOWORD (dwSize)-1, HIWORD (dwSize), 1, 1, NULL) ;
SelectObject (hdcMem, hBitmap) ;
TextOut (hdcMem, 0, 0, lfSet[i].szMenuText,
strlen (lfSet[i].szMenuText)) ;
DeleteObject (SelectObject (hdcMem, hFont)) ;
DeleteDC (hdcMem) ;
DeleteDC (hdc) ;
return hBitmap ;
}
long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
HMENU hMenu ;
static short nCurrentFont = IDM_COUR ;
switch (message)
{
case WM_CREATE :
CheckMenuItem (GetMenu (hwnd), nCurrentFont, MF_CHECKED) ;
return 0 ;
case WM_SYSCOMMAND :
switch (wParam)
{
case IDM_HELP :
MessageBox (hwnd, "Help not yet implemented.",
szAppName, MB_OK | MB_ICONEXCLAMATION) ;
return 0 ;
}
break ;
case WM_COMMAND :
switch (wParam)
{
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 ;
case IDM_COUR :
case IDM_HELV :
case IDM_TMSRMN :
hMenu = GetMenu (hwnd) ;
CheckMenuItem (hMenu, nCurrentFont, MF_UNCHECKED) ;
nCurrentFont = wParam ;
CheckMenuItem (hMenu, nCurrentFont, MF_CHECKED) ;
return 0 ;
}
break ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
GRAFMENU.RC
/*-----------------------------
GRAFMENU.RC resource script
-----------------------------*/
#include "grafmenu.h"
BitmapEdit BITMAP editlabl.bmp
BitmapFile BITMAP filelabl.bmp
BitmapFont BITMAP fontlabl.bmp
BitmapHelp BITMAP bighelp.bmpMenuFile MENU
{
MENUITEM "&New", IDM_NEW
MENUITEM "&Open...", IDM_OPEN
MENUITEM "&Save", IDM_SAVE
MENUITEM "Save &As...", IDM_SAVEAS
}
MenuEdit MENU
{
MENUITEM "&Undo", IDM_UNDO
MENUITEM SEPARATOR
MENUITEM "Cu&t", IDM_CUT
MENUITEM "&Copy", IDM_COPY
MENUITEM "&Paste", IDM_PASTE
MENUITEM "C&lear", IDM_CLEAR
}
GRAFMENU.H
/*------------------------
GRAFMENU.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_COUR 10
#define IDM_HELV 11
#define IDM_TMSRMN 12
#define IDM_HELP 13
EDITLABL.BMP
FILELABL.BMP
FONTLABL.BMP
BIGHELP.BMP
GRAFMENU.DEF
;-------------------------------------
; GRAFMENU.DEF module definition file
;-------------------------------------
NAME GRAFMENU
DESCRIPTION 'Demo of Bitmapped Menu Items (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
To examine the subject of bitmaps and menus in the detail it deserves, we'll need to cross the border into GDI territory—a full exploration of which awaits us in the next section of this book. The discussion here will serve as a preview of topics that we'll return to again in Chapter 11.