《Windows程式設計》讀書筆十 選單和其他資源
第十章 選單和資源
windows通過LoadIcon LoadCursor等函式來載入資源
圖示
滑鼠指標
字串
自定義資源
選單
鍵盤加速鍵
對話方塊
點陣圖
10.1 圖示,滑鼠指標,字串和自定義資源
10.1.1 向程式新增圖示
Tools->Options->Build->Export makefile when saving project file.
匯出mak檔案
注:該方法在VS2015中已經不可用。VS2015需要自己寫makefile或者使用makefile project來生成mak檔案,然後使用nmake編譯檔案。
nmake的配置方法參考
http://www.cnblogs.com/cvbnm/articles/1954872.html
原始碼
#include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("IconDemo"); HWND hwnd; MSG msg; WNDCLASS wndClass; //The window Class wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class. wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));//LoadIcon(NULL, IDI_APPLICATION); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = szAppName; //Register the Window Class to the Windows System. if (!RegisterClass(&wndClass)) { MessageBox(NULL, TEXT("This program require Windows NT!"), szAppName, MB_ICONERROR); return 0; } //This function will generate an WM_CREATE message. hwnd = CreateWindow(szAppName, //Window class name TEXT("Icon Demo"), //Window caption WS_OVERLAPPEDWINDOW, //Window Style CW_USEDEFAULT, //initial x position CW_USEDEFAULT, //initial y position CW_USEDEFAULT, //initial x size CW_USEDEFAULT, //initial y size NULL, //parent window handle NULL, //window menu handle hInstance, //program instance handle NULL); //creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); //This function will generate a WM_PAINT message. /* The message loop for this program. if received the WM_QUIT message, the function will return 0.*/ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //define the Window Procedure WndProc LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HICON hIcon; static int cxIcon, cyIcon, cxClient, cyClient; HDC hdc; HINSTANCE hInstance; PAINTSTRUCT ps; int x, y; switch (message) //get the message { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); cxIcon = GetSystemMetrics(SM_CXICON); cyIcon = GetSystemMetrics(SM_CYICON); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); for (y = 0; y < cyClient; y += cyIcon) for (x = 0; x < cxClient; x += cxIcon) DrawIcon(hdc, x, y, hIcon); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
這段程式碼不能夠直接編譯
還需要建立資原始檔,使用AddItem來增加icondemo.rc檔案,VS會自動建立Resource.h標頭檔案。
使用Resource Editor中的Add Resource 新增圖示資源
原書中的圖示是32x32的,在VS2015和Win7時代已經支援256x256的超大圖示了
同時將ICON的ID改為IDI_ICON
然後可以編譯程式了
執行結果
SM_CXICON 和SM_CYICON 為32x32
更小的圖示是 SM_CXSMSIZE 和 SM_CYSMSIZE
10.1.2 獲得圖示的控制代碼
hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
#define MAKEINTRESOURCE (i) (LPTSTR) ((DWORD)((WORD)(i)))
資源ID也可以直接使用字串
10.3.3 在應用程式中使用圖示
RegisterClassEx 使用 WNDCLASSEX結構
有額外欄位
ebSize 表示WNDCLASSEX結構大小
hIconSm 應該設定為小圖示的控制代碼。
因此你需要設定兩個圖示控制代碼, 一個標準一個是小
在程式執行時改變圖示,使用 SetClassLong函式實現。
SetClassLong(hwnd, GCL_HICON, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ALTICON));
不想儲存圖示控制代碼可以使用一下函式
DrawIcon(hdc, x, y, GetClassLong(hwnd, GCL_HICON));
hIcon 是特例 生成的控制代碼不需要手動銷燬,
10.1.4 使用自定義滑鼠指標
和圖示類似,在資源編輯器中新增指標
然後
wndclass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));
或者用文字名字來定義滑鼠指標
當滑鼠在基於此類建立的視窗上,自定義的滑鼠指標就會顯示出來。
更改子視窗的hCursor欄位
SetClassLong(hwndChild, GCL_HCURSOR, LoadCursor(hInstance, TEXT("childcursor"));
也可以使用SetCursor(hCursor); 來設定滑鼠指標
應該在WM_MOUSEMOVE時呼叫SetCursor 否則一旦移動滑鼠指標windows會重繪滑鼠指標
10.1.5 字串資源
使用資源管理器新建String Table
使用LoadString 來載入字串
LoadString(hInstance, id, szBuffer, iMaxLength); 支援c語言的格式設定符號
所有字串表都是以Unicode格式保持,LoadStringW直接載入Unicode文字, LoadStringA則會進行內碼表轉換
10.1.6 自定義資源
hResource = LoadResource(hInstance, FindResource(hInstance, MAKEINTRESOURCE(IDR_BINTYPE), TEXT("BINTYPE")));
需要訪問文字時
pData = LockResource(hResource);
使用完以後釋放
FreeResource(hResource);
一個使用圖示,字串和自定義資源的例子
poepoem.cpp
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[16], szCaption[64], szErrMsg[64];
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
hInst = hInstance;
LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName) / sizeof(TCHAR));
LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption) / sizeof(TCHAR));
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(hInstance, szAppName);//LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
//Support the ANSI encode.
LoadStringA(hInstance, IDS_APPNAME, (char*)szAppName, sizeof(szAppName));
LoadStringA(hInstance, IDS_ERRMSG, (char*)szErrMsg, sizeof(szErrMsg));
MessageBoxA(NULL, (char *)szErrMsg,
(char *)szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
szCaption, //Window caption
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static char* pText;
static HGLOBAL hResource;
static HWND hScroll;
static int iPosition, cxChar, cyChar, cyClient, iNumLines, xScroll;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
TEXTMETRIC tm;
int ilength;
switch (message) //get the message
{
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
xScroll = GetSystemMetrics(SM_CXVSCROLL);
hScroll = CreateWindow(TEXT("scrollbar"), NULL,
WS_CHILD | WS_VISIBLE | SBS_VERT,
0, 0, 0, 0,
hwnd, (HMENU)1, hInst, NULL);
hResource = LoadResource(hInst, FindResource(hInst, TEXT("AnnabelLee"),
TEXT("TEXT")));
pText = (char *)LockResource(hResource);
iNumLines = 0;
while (*pText != TEXT('\\') && *pText != TEXT('\0'))
{
if (*pText == TEXT('\n'))
iNumLines++;
pText = AnsiNext(pText);
}
//*pText = TEXT('\0');
SetScrollRange(hScroll, SB_CTL, 0, iNumLines, FALSE);
SetScrollPos(hScroll, SB_CTL, 0, FALSE);
return 0;
case WM_SIZE:
MoveWindow(hScroll, LOWORD(lParam) - xScroll, 0,
xScroll, cyClient = HIWORD(lParam), TRUE);
SetFocus(hwnd);
return 0;
case WM_SETFOCUS:
SetFocus(hScroll);
return 0;
case WM_VSCROLL:
switch (wParam)
{
case SB_TOP:
iPosition = 0;
break;
case SB_BOTTOM:
iPosition = iNumLines;
break;
case SB_LINEUP:
iPosition -= 1;
break;
case SB_LINEDOWN:
iPosition += 1;
break;
case SB_PAGEUP:
iPosition -= cyClient / cyChar;
break;
case SB_PAGEDOWN:
iPosition += cyClient / cyChar;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
iPosition = LOWORD(lParam);
break;
}
iPosition = max(0, min(iPosition, iNumLines));
if (iPosition != GetScrollPos(hScroll, SB_CTL))
{
SetScrollPos(hScroll, SB_CTL, iPosition, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
pText = (char*)LockResource(hResource);
GetClientRect(hwnd, &rect);
rect.left += cxChar;
rect.top += cyChar * (1 - iPosition);
DrawTextA(hdc, pText, -1, &rect, DT_EXTERNALLEADING);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
FreeResource(hResource);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
poepoem.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Chinese (Simplified, PRC) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
PoePoem ICON "POEPOEM.ICO"
/////////////////////////////////////////////////////////////////////////////
//
// TEXT
//
ANNABELLEE TEXT DISCARDABLE "poepoem.txt"
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_APPNAME "PoePoem"
IDS_CAPTION """Annabel Lee"" by Edgar Allan Poe"
IDS_ERRMSG "This program requires Windows NT!"
END
#endif // Chinese (Simplified, PRC) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by poepoem.rc
//
#define IDS_APPNAME 102
#define IDS_CAPTION 103
#define IDS_ERRMSG 104
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
執行結果
10.2.1和選單有關的概念
主選單or頂級選單
子選單or 下拉選單
彈出選單可以被選中,頂級選單不能被選中
選單可以被啟用,或禁用。 活動 ,非活動。
10.2.2 選單結構
每個選單有三個特徵定義。 選單顯示什麼, 文字或點陣圖
ID號或者指向選單的控制代碼
選單的屬性,是否禁用或選中
10.2.3 定義選單
使用&F windows會使用ALT+F 啟用選單
gray 選單變灰
enabled 文字變灰
checked 選單可選
Separator 選項會繪製一條水平的分割線
\t後面的文字會被放置在右邊足夠遠的新欄中
\a 會使後面的文字右對齊
指定ID值是windows在選單訊息傳送給視窗過程的數字。ID值在一個選單中應該是唯一的。
使用IDM_XXX 開頭
10.2.4 在程式中引用選單
wndClass.lpszMenuName = szAppName; //給選單指定一個和程式一樣的名字選單資源的ID
或者
hMenu = LoadMenu(hInstance, TEXT("MyMenu"));
或者
hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(ID_MENU));
作為CreateWindow的引數hMenu
CreateWindow中指定的選單會覆蓋視窗類中指定的任何選單。如果第九個引數為NULL 則基於視窗類中指定的選單建立視窗。
也可以在視窗建立後
SetMenu(hwnd, hMenu); 來設定選單
動態改變視窗
當視窗被銷燬時,附加到該視窗的任何選單也將被銷燬。而在程式結束前,任何沒有附加到視窗的選單應該通過DestoryMenu呼叫被顯示銷燬(DestroyIcon, DestroyCursor等 銷燬自己建立的其他資源控制代碼,自定義資源使用FreeResource)
10.2.5 選單和訊息
當用戶選擇選單windows會像視窗過程傳送幾個不同訊息。多數情況下,應用程式可以忽略大部分交給DefWindowProc處理
有一個訊息如下WM_INITMENU
wParam 主選單控制代碼
lParam 0
即使使用者選擇了第一項,wParam也是主選單的控制代碼。
WM_MENUSELECT 訊息。移動滑鼠時,這對實現狀態列非常有用
LOWORD(wParam) 所選的選單項, 選單ID或者彈出選單的索引
HIWORD(wParam) 所選的標記
lParam 鎖選選單項的控制代碼
選中標記可以是, MF_GRAYED, MF_DISABLED, MF_CHECKED, MF_BITMAP, MF_POPUP, MF_HELP, MF_SYSMENU 或MF_MOUSESELECT.
windows 要顯示彈出選單,會像視窗過程傳送一個帶有如下引數的WM_INITMENUPOPUP
wParam 彈出選單的控制代碼
LOWORD(lParam) 彈出選單的索引
HIWORD(lParam) 1代表系統選單,0代表其他選單
最重要的是WM_COMMAND
如果子選單和子視窗控制元件使用相同的ID
檢查lParam 對於視窗,該值是0
WM_SYSCOMMAND 類似於WM_COMMAND 不過他表示使用者從系統選單選擇了一個啟用的選單項
wParam 選單ID
lParam 0
如果WM_SYSCOMMAND是滑鼠單擊的結果,LOWORD(lParam) HIWORD(lParam)將包含滑鼠指標的x和y座標
系統選單
SC_SIZE, SC_MOVE SC_MINIMIZE SC_MAXIMIZE SC_NEXTWINDOW, SC_PREVWINDOW, SC_CLOSE< SC_VSCROLL, SC_HSCROLL, SC_ARRANGE,
SC_RESTORE, SC_TASKLIST.
WM_MENUCHAR 按下Alt和不對應於任何選單項的字元犍 或者 彈出選單時,使用者按了一個不對應任何彈出選單項的字元鍵
LOWORD(wParam) 字元碼
HIWORD(wParam) 選擇碼
lParam 選單控制代碼
選擇碼如下
0 沒有彈出選單顯示
MF_POPUP 彈出選單被顯示
MF_SYSMENU 系統彈出選單被顯示
一般程式會把改訊息傳給DefWindowProc, 然後DefWindowProc返回0, 使得windows發出嘟嘟聲。
10.2.6 範例程式
menudemo.cpp
#include <windows.h>
#include "resource.h"
#define ID_TIMER 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
TCHAR szAppName[] = TEXT("MenuDemo");
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
hInst = hInstance;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = szAppName;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("This program require Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
TEXT("Menu Demonstration"), //Window caption
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int idColor[5] = {WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,
DKGRAY_BRUSH, BLACK_BRUSH};
static int iSelection = IDM_BKGND_WHITE;
HMENU hMenu;
switch (message) //get the message
{
case WM_COMMAND:
hMenu = GetMenu(hwnd);
switch (LOWORD(wParam))
{
case IDM_FILE_NEW:
case IDM_FILE_OPEN:
case IDM_FILE_SAVE:
case IDM_FILE_SAVE_AS:
MessageBeep(0);
return 0;
case IDM_FILE_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
case IDM_EDIT_UNDO:
case IDM_EDIT_CUT:
case IDM_EDIT_COPY:
case IDM_EDIT_PASTE:
case IDM_EDIT_CLEAR:
MessageBeep(0);
return 0;
//The logic below assumes that IDM_WHITE through IDM_BLACK
//are consecutive numbers in the order show here.
case IDM_BKGND_WHITE:
case IDM_BKGND_LTGRAY:
case IDM_BKGND_GRAY:
case IDM_BKGND_DKGRAY:
case IDM_BKGND_BLACK:
CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);
iSelection = LOWORD(wParam);
CheckMenuItem(hMenu, iSelection, MF_CHECKED);
SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)
GetStockObject(idColor[LOWORD(wParam) - IDM_BKGND_WHITE]));
InvalidateRect(hwnd, NULL ,TRUE);
return 0;
case IDM_TIMER_START:
if (SetTimer(hwnd, ID_TIMER, 1000, NULL))
{
EnableMenuItem(hMenu, IDM_TIMER_START, MF_GRAYED);
EnableMenuItem(hMenu, IDM_TIMER_STOP, MF_ENABLED);
}
return 0;
case IDM_TIMER_STOP:
KillTimer(hwnd, ID_TIMER);
EnableMenuItem(hMenu, IDM_TIMER_START, MF_ENABLED);
EnableMenuItem(hMenu, IDM_TIMER_STOP, MF_GRAYED);
return 0;
case IDM_APP_HELP:
MessageBox(hwnd, TEXT("Help not yet implemented!"),
szAppName, MB_ICONEXCLAMATION | MB_OK);
return 0;
case IDM_APP_ABOUT:
MessageBox(hwnd, TEXT("Menu Demonstration Program\n")
TEXT("(c) Charles Petzold, 1998"),
szAppName, MB_ICONINFORMATION | MB_OK);
return 0;
}
break;
case WM_TIMER:
MessageBeep(0);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
menudemo.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
MENUDEMO MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New", ID_MENUITEM40020
MENUITEM "&Open", IDM_FILE_OPEN
MENUITEM "&Save", IDM_FILE_SAVE
MENUITEM "Save &As...", IDM_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_APP_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo", IDM_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "C&ut", IDM_EDIT_CUT
MENUITEM "&Copy", IDM_EDIT_COPY
MENUITEM "&Paste", IDM_EDIT_PASTE
MENUITEM "De&lete", IDM_EDIT_CLEAR
END
POPUP "&Background"
BEGIN
MENUITEM "&White", IDM_BKGND_WHITE, CHECKED
MENUITEM "&Light Gray", IDM_BKGND_LTGRAY
MENUITEM "&Gray", IDM_BKGND_GRAY
MENUITEM "&Dark Gray", IDM_BKGND_DKGRAY
MENUITEM "&Black", IDM_BKGND_BLACK
END
POPUP "&Timer"
BEGIN
MENUITEM "&Start", IDM_TIMER_START
MENUITEM "S&top", IDM_TIMER_STOP, GRAYED
END
POPUP "&Help"
BEGIN
MENUITEM "&Help...", IDM_APP_HELP
MENUITEM "&About MenuDemo...", IDM_APP_ABOUT
END
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by menudemo.rc
//
#define IDM_FILE_NEW 40001
#define IDM_FILE_OPEN 40002
#define IDM_FILE_SAVE 40003
#define IDM_FILE_SAVE_AS 40004
#define IDM_FILE_EXIT 40005
#define IDM_EDIT_UNDO 40006
#define IDM_EDIT_CUT 40007
#define IDM_EDIT_COPY 40008
#define IDM_Menu 40009
#define IDM_EDIT_CLEAR 40010
#define IDM_BKGND_WHITE 40011
#define IDM_BKGND_LTGRAY 40012
#define IDM_BKGND_GRAY 40013
#define IDM_BKGND_DKGRAY 40014
#define IDM_BKGND_BLACK 40015
#define IDM_TIMER_START 40016
#define IDM_TIMER_STOP 40017
#define IDM_APP_HELP 40018
#define IDM_APP_ABOUT 40019
#define IDM_EDIT_PASTE 40039
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40040
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
執行結果如下
10.2.7 選單設計中的規範
10.2.8 定義選單的繁瑣方式
可以不適用資源指令碼而使用CreateMenu和AppendMenu 動態建立選單。完成定以後可以把選單控制代碼傳遞給CreateWindow 或者使用SetMenu來設定視窗選單。
hMenu = CreateMenu();
對於頂級選單和彈出選單必須使用不同的控制代碼
hMenuPop = CreateMenu();
AppendMenu(hMenuPopup, MF_STRING, IDM_FILE_NEW, "&NEW");
...
AppendMenu(hMenu, MF_POPUP, hMenuPopup, "&File");
hMenuPop = CreateMenu();
...
具體例子參考截圖
第三種方法, 使用LoadMenuIndirect函式接受一個指向MENUITEMPLATE型別的結構指標,並返回一個指向選單的控制代碼。
10.2.9 浮動彈出選單
popmenu.cpp
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
HINSTANCE hInst;
TCHAR szAppName[] = TEXT("PopMenu");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
hInst = hInstance;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("This program require Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
TEXT("PopupMenu Demonstration"), //Window caption
WS_OVERLAPPEDWINDOW, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HMENU hMenu;
static int idColor[5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,
DKGRAY_BRUSH, BLACK_BRUSH };
static int iSelection = IDM_BKGND_WHITE;
POINT point;
switch (message) //get the message
{
case WM_CREATE:
hMenu = LoadMenu(hInst, szAppName);
hMenu = GetSubMenu(hMenu, 0);
return 0;
case WM_RBUTTONUP:
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
ClientToScreen(hwnd, &point);
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y,
0, hwnd, NULL);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_FILE_NEW:
case IDM_FILE_OPEN:
case IDM_FILE_SAVE:
case IDM_FILE_SAVE_AS:
MessageBeep(0);
return 0;
case IDM_APP_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
case IDM_EDIT_UNDO:
case IDM_EDIT_CUT:
case IDM_EDIT_COPY:
case IDM_EDIT_PASTE:
case IDM_EDIT_CLEAR:
MessageBeep(0);
return 0;
//The logic below assumes that IDM_WHITE through IDM_BLACK
//are consecutive numbers in the order show here.
case IDM_BKGND_WHITE:
case IDM_BKGND_LTGRAY:
case IDM_BKGND_GRAY:
case IDM_BKGND_DKGRAY:
case IDM_BKGND_BLACK:
CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);
iSelection = LOWORD(wParam);
CheckMenuItem(hMenu, iSelection, MF_CHECKED);
SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)
GetStockObject(idColor[LOWORD(wParam) - IDM_BKGND_WHITE]));
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case IDM_APP_HELP:
MessageBox(hwnd, TEXT("Help not yet implemented!"),
szAppName, MB_ICONEXCLAMATION | MB_OK);
return 0;
case IDM_APP_ABOUT:
MessageBox(hwnd, TEXT("Menu Demonstration Program\n")
TEXT("(c) Charles Petzold, 1998"),
szAppName, MB_ICONINFORMATION | MB_OK);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
popmenu.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
POPMENU MENU DISCARDABLE
BEGIN
POPUP "MyMenu"
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New", IDM_FILE_NEW
MENUITEM "&Open", IDM_FILE_OPEN
MENUITEM "&Save", IDM_FILE_SAVE
MENUITEM "Save &As", IDM_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_APP_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo", IDM_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "Cu&t", IDM_EDIT_CUT
MENUITEM "&Copy", IDM_EDIT_COPY
MENUITEM "&Paste", IDM_EDIT_PASTE
MENUITEM "De&lete", IDM_EDIT_CLEAR
END
POPUP "&Background"
BEGIN
MENUITEM "&White", IDM_BKGND_WHITE, CHECKED
MENUITEM "&Light Gray", IDM_BKGND_LTGRAY
MENUITEM "&Gray", IDM_BKGND_GRAY
MENUITEM "&Dark Gray", IDM_BKGND_DKGRAY
MENUITEM "&Black", IDM_BKGND_BLACK
END
POPUP "&Help"
BEGIN
MENUITEM "&Help...", IDM_APP_HELP
MENUITEM "&About PopMenu...", IDM_APP_ABOUT
END
END
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by PopMenu.rc
//
#define IDM_FILE_NEW 40001
#define IDM_FILE_OPEN 40002
#define IDM_FILE_SAVE 40003
#define IDM_FILE_SAVE_AS 40004
#define IDM_APP_EXIT 40005
#define IDM_EDIT_UNDO 40006
#define IDM_EDIT_CUT 40007
#define IDM_EDIT_COPY 40008
#define IDM_EDIT_PASTE 40009
#define IDM_EDIT_CLEAR 40010
#define IDM_BKGND_WHITE 40011
#define IDM_BKGND_LTGRAY 40012
#define IDM_BKGND_GRAY 40013
#define IDM_BKGND_DKGRAY 40014
#define IDM_BKGND_BLACK 40015
#define IDM_HELP_HELP 40016
#define IDM_APP_HELP 40016
#define IDM_APP_ABOUT 40017
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40018
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
執行結果
10.2.10 使用系統選單
包含WS_SYSMENU樣式建立視窗,在標題欄左邊會有一個系統該選單。
系統選單加入ID號必須小於0xF000. 否則會和windows標準命令的ID衝突
並且處理完WM_SYSCOMMAND訊息要把其他訊息傳遞給DefWindowProc
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
#define IDM_SYS_ABOUT 1
#define IDM_SYS_HELP 2
#define IDM_SYS_REMOVE 3
static TCHAR szAppName[] = TEXT("PoorMenu");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HMENU hMenu;
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("This program require Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
TEXT("The Poor-Person's Menu"), //Window caption
WS_OVERLAPPEDWINDOW, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
hMenu = GetSystemMenu(hwnd, FALSE);
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hMenu, MF_STRING, IDM_SYS_ABOUT, TEXT("About..."));
AppendMenu(hMenu, MF_STRING, IDM_SYS_HELP, TEXT("Help..."));
AppendMenu(hMenu, MF_STRING, IDM_SYS_REMOVE, TEXT("Remove Additions"));
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) //get the message
{
case WM_SYSCOMMAND:
switch (LOWORD(wParam))
{
case IDM_SYS_ABOUT:
MessageBox(hwnd, TEXT("Menu Demonstration Program\n")
TEXT("(c) Charles Petzold, 1998"),
szAppName, MB_ICONINFORMATION | MB_OK);
return 0;
case IDM_SYS_HELP:
MessageBox(hwnd, TEXT("Help not yet implemented!"),
szAppName, MB_ICONEXCLAMATION | MB_OK);
return 0;
case IDM_SYS_REMOVE:
GetSystemMenu(hwnd, TRUE);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
GetSystemMenu(hwnd, FALSE) 表明系統選單將要被修改
GetSystemMenu(hwnd, TRUE); 還原被修改的系統選單
10.2.11 改變選單
windows3.0 以前使用ChangeMenu
現在使用
AppendMenu 在選單末尾追加一個新選單項
DeleteMenu 從選單中刪除已存在選單項並銷燬他
InsertMenu 像選單中插入一個新選單
ModifyMenu 修改一個已經存在的選單項
RemoveMenu 從選單中去除一個已有的選單項
DeleteMenu 會銷燬該彈出選單而Remove不會。
10.2.12 其他選單命令
改變一個頂級選單以後,知道windows重繪選單才能顯示。
DrawMenuBar(hwnd) 強制重繪選單
hwnd為視窗控制代碼
hMenuPopup = GetSubMenu(hMenu, iPosition); //獲得彈出選單的控制代碼
iPosition為彈出選單在頂級選單中的索引
iCount = GetMenuItemCount(hMenu) //頂級選單或彈出選單中現有選單項的數目
id = GetMenuItemID(hMenuPopup, iPosition) // 獲得彈出選單中某個選單項的ID
CheckMenuItem(hMenu, id, iCheck); 在彈出選單中選擇和取消選擇某一選單項 MF_CHECKED 或 MF_UNCHECKED hMenu是頂級選單控制代碼
如果hMenu是彈出選單,那麼id可以使iPosition
CheckMenuItem(hMenu, iPosition, MF_CHECKED | MF_BYPOSITION); 使用索引而非ID
EnableMenuItem(hMenu, id, MF_ENABLED);
第三個引數可以是 MF_ENABLED, MF_DISABLED, MF_GRAYED. 如果在頂級選單上使用,並且改選單項還有子選單。那麼第三個引數必須使用MF_BYPOSITION
HiliteMenuItem MF_HILITE MF_UNHILITE 加亮顯示
iFlags = GetMenuString(hMenu, id, pString, iMaxCount, iFlag) iFlag 可以使MF_BYCOMMAND 或者MF_BYPOSITION //獲得選單項的string
iFlags = GetMenuState(hMenu, id, iFlag) iFlag 是 MF_COMMAND 或者MF_BYPOSITION。 iFlags是當前標識的組合值
可能是 MF_CHECKED, MF_SIABLED, MF_GRAYED, MF_MENUBREAK, MF_MENUUNBREAK, MF_SEPARATOR
Destory(hMenu) 銷燬選單,使得該選單控制代碼無效
10.2.13選單的另類用法
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("NoPopUps");
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("This program require Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
TEXT("No-Popup Nested Menu Demonstration"), //Window caption
WS_OVERLAPPEDWINDOW, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HMENU hMenuMain, hMenuEdit, hMenuFile;
HINSTANCE hInstance;
switch (message) //get the message
{
case WM_CREATE:
hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
hMenuMain = LoadMenu(hInstance, TEXT("MenuMain"));
hMenuFile = LoadMenu(hInstance, TEXT("MenuFile"));
hMenuEdit = LoadMenu(hInstance, TEXT("MenuEdit"));
SetMenu(hwnd, hMenuMain);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_MAIN:
SetMenu(hwnd, hMenuMain);
return 0;
case IDM_FILE:
SetMenu(hwnd, hMenuFile);
return 0;
case IDM_EDIT:
SetMenu(hwnd, hMenuEdit);
case IDM_FILE_NEW:
case IDM_FILE_OPEN:
case IDM_FILE_SAVE:
case IDM_FILE_SAVE_AS:
case IDM_EDIT_UNDO:
case IDM_EDIT_CUT:
case IDM_EDIT_COPY:
case IDM_EDIT_PASTE:
case IDM_EDIT_CLEAR:
MessageBeep(0);
return 0;
}
break;
case WM_DESTROY:
SetMenu(hwnd, hMenuMain);
DestroyMenu(hMenuFile);
DestroyMenu(hMenuEdit);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
NOPOPUPS.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Chinese (Simplified, PRC) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
MENUMAIN MENU
BEGIN
MENUITEM "MAIN:", 0, INACTIVE
MENUITEM "&File...", IDM_FILE
MENUITEM "&Edit...", IDM_EDIT
END
MENUFILE MENU
BEGIN
MENUITEM "FILE:", 0, INACTIVE
MENUITEM "&New", IDM_FILE_NEW
MENUITEM "&Open...", IDM_FILE_OPEN
MENUITEM "&Save", IDM_FILE_SAVE
MENUITEM "Save &As", IDM_FILE_SAVE_AS
MENUITEM "(&Main)", IDM_MAIN
END
MENUEDIT MENU
BEGIN
MENUITEM "EDIT:", ID_EDIT, INACTIVE
MENUITEM "&Undo", IDM_EDIT_UNDO
MENUITEM "Cu&t", IDM_EDIT_CUT
MENUITEM "&Copy", IDM_EDIT_COPY
MENUITEM "&Paste", IDM_EDIT_PASTE
MENUITEM "De&lete", IDM_EDIT_CLEAR
MENUITEM "(&Main)", IDM_MAIN
END
#endif // Chinese (Simplified, PRC) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by nopopups.rc
//
#define IDM_FILE 40001
#define IDM_EDIT 40002
#define IDM_FILE_NEW 40003
#define IDM_FILE_OPEN 40004
#define IDM_FILE_SAVE 40005
#define IDM_FILE_SAVE_AS 40006
#define IDM_MAIN 40007
#define IDM_EDIT_UNDO 40008
#define IDM_EDIT_CUT 40009
#define IDM_EDIT_COPY 40010
#define IDM_EDIT_PASTE 40011
#define IDM_EDIT_CLEAR 40012
#define ID_EDIT 40013
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40014
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
執行結果
10.3 鍵盤加速
可以生成WM_COMMAND 或者有時候是 WM_SYSCOMMAND
10.3.1 為什麼你應該使用鍵盤加速鍵
windows會把WM_COMMAND訊息傳送給在windows函式TranslateAccelerator中指定的視窗過程,多視窗程式設計中非常重要
10.3.2 指定加速鍵的一些原則
常見加速鍵 F1 幫助, F4~F6 用在多文件介面
10.3.3 加速鍵表
作為一種資源載入 每個加速鍵有一個ID和一個擊鍵組合
可以使虛擬程式碼或者ascii字元與shift, ctrl 或alt的組合。
Tab字元能把文字和加速犍分開,這樣加速鍵會排在第二列。
可以使用文字在選單項後面說明 例如 (Shift+F6)
10.3.4 載入加速鍵列表
使用LoadAccelerators 載入
HANDLE hAccel;
hAccel = LoadAccelerators(hInstance, TEXT("MyAccelerators"));
也可以使用 MAKEINTRESOURCE 使用ID, 或者使用 #數字
10.3.5 鍵盤按鍵
修改訊息迴圈
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hwnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
TranslateAccelerator 會優先判斷是否有加速鍵訊息,然後發給對於的視窗過程
當該返回返回0,說明訊息已經被翻譯過,不需要再處理。繼續嚇一條訊息
模態對話方塊或訊息框有輸入焦點時,TranslateAccelerator不翻譯鍵盤訊息,因為這些視窗的訊息不通過程式的訊息迴圈。
有些時候應用程式另一視窗擁有輸入焦點時,你不想翻譯鍵盤訊息。如何處理該情況參考11章
10.3.6 接受加速鍵訊息
對應系統選單項傳送 WM_SYSCOMMAND
否則傳送WM_COMMAND
WM_COMMAND 訊息
如果加速鍵對應某個選單項,視窗過程還會接收到WM_INITMENU WM_INITMENUPOPUP 和 WM_MENUSELECT
在處理WM_INITMENUPOPUP時,可以啟用或禁用彈出選單的選單項
當一個選單項變灰,加速鍵不會對其傳送WM_COMMAND 或者WM_SYSOMMAND
如果視窗最小化,對映到系統選單的鍵盤加速鍵會對視窗傳送WM_SYSCOMMAND
沒對映到系統選單項的加速鍵,TranslateAccelerator也會想視窗過程傳送WM_COMMAND訊息
10.3.7 帶有選單項的POPPAD
#include <windows.h>
#include "resource.h"
#define ID_EDIT 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
TCHAR szAppName[] = TEXT("PopPad2");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
//static TCHAR szAppName[] = TEXT("Colors1");
HACCEL hAccel;
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(hInstance, szAppName);// LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = CreateSolidBrush(0);//(HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = szAppName;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("This program require Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
szAppName, //Window caption
WS_OVERLAPPEDWINDOW, //Window Style
GetSystemMetrics(SM_CXSCREEN) / 4, //initial x position
GetSystemMetrics(SM_CYSCREEN) / 4, //initial y position
GetSystemMetrics(SM_CXSCREEN) / 2, //initial x size
GetSystemMetrics(SM_CYSCREEN) / 2, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
hAccel = LoadAccelerators(hInstance, szAppName);
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hwnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
int AskConfirmation(HWND hwnd)
{
return MessageBox(hwnd, TEXT("Really want to close PopPad2?"),
szAppName, MB_YESNO | MB_ICONQUESTION);
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndEdit;
int iSelect, iEnable;
switch (message) //get the message
{
case WM_CREATE:
hwndEdit = CreateWindow(TEXT("edit"), NULL,
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
WS_BORDER | ES_LEFT | ES_MULTILINE |
ES_AUTOHSCROLL | ES_AUTOVSCROLL,
0, 0, 0, 0,
hwnd, (HMENU)ID_EDIT,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
return 0;
case WM_SETFOCUS:
SetFocus(hwndEdit);
return 0;
case WM_SIZE:
MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
return 0;
case WM_INITMENUPOPUP:
if (lParam == 1)
{
EnableMenuItem((HMENU)wParam, IDM_EDIT_UNDO,
SendMessage(hwndEdit, EM_CANUNDO, 0, 0) ?
MF_ENABLED : MF_GRAYED);
EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE,
IsClipboardFormatAvailable(CF_TEXT) ?
MF_ENABLED : MF_GRAYED);
iSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0);
if (HIWORD(iSelect) == LOWORD(iSelect))
iEnable = MF_GRAYED;
else
iEnable = MF_ENABLED;
EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, iEnable);
EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, iEnable);
EnableMenuItem((HMENU)wParam, IDM_EDIT_CLEAR, iEnable);
}
case WM_COMMAND:
if (lParam)
{
if (LOWORD(wParam) == ID_EDIT)
if (HIWORD(wParam) == EN_ERRSPACE ||
HIWORD(wParam) == EN_MAXTEXT)
MessageBox(hwnd, TEXT("Edit control out of spae."),
szAppName, MB_OK | MB_ICONSTOP);
}
else switch (LOWORD(wParam))
{
case IDM_FILE_NEW:
case IDM_FILE_OPEN:
case IDM_FILE_SAVE:
case IDM_FILE_SAVE_AS:
case IDM_FILE_PRINT:
MessageBeep(0);
return 0;
case IDM_APP_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
case IDM_EDIT_UNDO:
SendMessage(hwndEdit, WM_UNDO, 0, 0);
return 0;
case IDM_EDIT_CUT:
SendMessage(hwndEdit, WM_CUT, 0, 0);
return 0;
case IDM_EDIT_COPY:
SendMessage(hwndEdit, WM_COPY, 0, 0);
return 0;
case IDM_EDIT_PASTE:
SendMessage(hwndEdit, WM_PASTE, 0, 0);
return 0;
case IDM_EDIT_CLEAR:
SendMessage(hwndEdit, WM_CLEAR, 0, 0);
return 0;
case IDM_EDIT_SELECT_ALL:
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
return 0;
case IDM_HELP_HELP:
MessageBox(hwnd, TEXT("Help not yet implemented!"),
szAppName, MB_ICONEXCLAMATION | MB_OK);
return 0;
case IDM_APP_ABOUT:
MessageBox(hwnd, TEXT("Menu Demonstration Program\n")
TEXT("(c) Charles Petzold, 1998"),
szAppName, MB_ICONINFORMATION | MB_OK);
return 0;
}
return 0;
case WM_CLOSE:
if (IDYES == AskConfirmation(hwnd))
DestroyWindow(hwnd);
return 0;
case WM_QUERYENDSESSION:
if (IDYES == AskConfirmation(hwnd))
return 1;
else
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
POPPAD.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Chinese (Simplified, PRC) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
POPPAD2 MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New", IDM_FILE_NEW
MENUITEM "&Open...", IDM_FILE_OPEN
MENUITEM "&Save", IDM_FILE_SAVE
MENUITEM "Save &As...", IDM_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "&Print", IDM_FILE_PRINT
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_APP_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo\tCtrl+Z", IDM_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT
MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY
MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE
MENUITEM "De&lete\tDel", IDM_EDIT_CLEAR
MENUITEM SEPARATOR
MENUITEM "&Select All", IDM_EDIT_SELECT_ALL
END
POPUP "&Help"
BEGIN
MENUITEM "&Help...", IDM_HELP_HELP
MENUITEM "&About PopPad2...", IDM_APP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
POPPAD2 ACCELERATORS
BEGIN
VK_DELETE, IDM_EDIT_CLEAR, VIRTKEY, NOINVERT
"^C", IDM_EDIT_COPY, ASCII, NOINVERT
"^X", IDM_EDIT_CUT, ASCII, NOINVERT
VK_DELETE, IDM_EDIT_CUT, VIRTKEY, SHIFT, NOINVERT
"^V", IDM_EDIT_PASTE, ASCII, NOINVERT
VK_INSERT, IDM_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
VK_INSERT, IDM_EDIT_PASTE, VIRTKEY, SHIFT, NOINVERT
"^Z", IDM_EDIT_UNDO, ASCII, NOINVERT
VK_BACK, IDM_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
VK_F1, IDM_HELP_HELP, VIRTKEY, NOINVERT
"^A", IDM_EDIT_SELECT_ALL, ASCII, NOINVERT
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
POPPAD2 ICON "POPPAD2.ICO"
#endif // Chinese (Simplified, PRC) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by poppad.rc
//
#define IDM_FILE_NEW 40001
#define IDM_FILE_OPEN 40002
#define IDM_FILE_SAVE 40003
#define IDM_FILE_SAVE_AS 40004
#define IDM_FILE_PRINT 40005
#define IDM_APP_EXIT 40006
#define IDM_EDIT_UNDO 40007
#define IDM_EDIT_CUT 40008
#define IDM_EDIT_COPY 40009
#define IDM_EDIT_PASTE 40010
#define IDM_EDIT_CLEAR 40011
#define IDM_EDIT_SELECT_ALL 40012
#define IDM_HELP_HELP 40013
#define IDM_APP_ABOUT 40014
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40028
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
10.3.8 啟動選單項
判斷是否可以做undo
EnableMenuItem((HMENU)wParam, IDM_EDIT_UNDO,
SendMessage(hwndEdit, EM_CANUNDO, 0, 0) ?
MF_ENABLED : MF_GRAYED);
判斷是否可以做Paste
EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE,
IsClipboardFormatAvailable(CF_TEXT) ?
MF_ENABLED : MF_GRAYED);
判斷編輯框有文字被選中
iSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0);
if (HIWORD(iSele