一 鼠標消息
1 鼠標消息
1) 基本鼠標消息
WM_LBUTTONDOWN 左鍵按下
WM_LBUTTONUP 左鍵擡起
WM_RBUTTONDOWN 右鍵按下
WM_RBUTTONUP 右鍵擡起
WM_MOUSEMOVE 鼠標移動
2) 雙擊消息
WM_LBUTTONDBLCLK 左鍵雙擊
WM_RBUTTONDBLCLK 右鍵雙擊
3) 滾輪消息
WM_MOUSEWHEEL 鼠標滾輪
2 消息的參數
WPARAM - 當前鍵盤和鼠標按鍵狀態,例如MK_CONTROL/
MK_SHIFT,MK_LBUTTON等
LPARAM - 當前鼠標的座標,座標的原點是窗口
客戶區的左上角.
X座標 - LOWORD(lParam),低16位
Y座標 - HIWORD(lParam),高16位
參數具體內容和具體鼠標消息有稍微不同.
3 消息的使用
3.1 基本鼠標消息,只需在窗口處理函數增加
消息處理即可. 當消息來臨,獲取鼠標和按鍵
狀態.例如:
case WM_MOUSEMOVE:
{
int nX = LOWORD(lParam);
int nY = HIWORD(lParam);
}
附:座標轉換的函數 ClientToScreen
可以將鼠標座標轉換爲屏幕的座標.
3.2 雙擊消息
3.2.1 窗口註冊要增加 CS_DBLCLKS 類型
wce.style = CS_DBLCLKS|...;
3.2.2 在窗口處理函數中增加消息處理
3.2.3 產生過程,例如:WM_LBUTTONDBLCLK
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
連續兩次LBUTTONDOWN的時間間隔小於
預定的雙擊時間間隔,就會產生
LBUTTONDBLCLK消息.
雙擊時間間隔可以通過控制面板調整.
3.3 滾輪消息
3.3.1 由於WM_MOUSEWHEEL需要Winnt4.0以上
版本支持,所以需要包含在windows.h的頭
文件前,增加 _WIN32_WINNT 宏定義,
#define _WIN32_WINNT 0x0400
3.3.2 在窗口處理函數中增加消息處理
3.3.3 參數
LPARAM 與其它鼠標消息類同
WPARAM - LOWORD(WPARAM) 表示按鍵狀態
HIWORD(WPARAM) 滾輪滾動幅度,
120的倍數,可以爲正負值.
正值: 滾輪向上滾動, 一般窗口向上滾動
負值: 滾輪向下滾動, 一般窗口向下滾動
二 定時器消息
1 定時器消息 WM_TIMER
按照定時器設置時間段,自動向窗口發送一個
定時器消息WM_TIMER. 優先級比較低.
定時器精度比較低,毫秒級別.消息產生時間
也精度比較低.
2 消息和函數
2.1 WM_TIMER - 消息ID
wParam: 定時器的ID
lParam: 定時器的處理函數
2.2 SetTimer - 設置一個定時器
UINT SetTimer(
HWND hWnd, //窗口的句柄,可以爲NULL
UINT nIDEvent,//定時器的ID,0爲不預設ID
UINT uElapse,//定時器時間間隔,毫秒級別
TIMERPROC lpTimerFunc );//定時器的處理函數,可以爲NULL
返回一個創建好的定時器ID
2.3 KillTimer - 結束一個定時器
BOOL KillTimer(
HWND hWnd,//窗口句柄
UINT uIDEvent );//定時器ID
2.4 TimerProc - 定時器處理函數
VOID CALLBACK TimerProc(
HWND hwnd, //窗口句柄
UINT uMsg, //WM_TIMER消息ID
UINT idEvent,//定時器ID
DWORD dwTime );//當前系統時間
3 使用方式
3.1 創建定時器 SetTimer
3.1.1 指定窗口句柄HWND,那麼 TIMERPROC 參數
可以爲空,那麼WM_TIMER消息將會發送給指定
窗口. 如果未指定, TIMERPROC不能空, 必須
指定定時器處理程序.
3.1.2 如果指定定時器ID,SetTimer會按照這個
ID創建定時器, 如果未指定,會返回一個創建
定時器ID.
nTimerID = SetTimer( NULL, 0, 7 * 1000,
TimerProc1 );
3.2 處理消息
可以根據消息傳入定時器ID號,分別處理.
3.3 結束定時器
在不使用時, KillTimer結束定時器.
KillTimer( hWnd, 1000 );
三 菜單
1 菜單基礎
菜單 - 每個菜單會有一個HMENU句柄
菜單項 - 每個菜單項會有一個ID號,可以
根據這個ID執行不同的操作
2 菜單的使用
2.1 菜單創建
2.1.1 CreateMenu - MENU 菜單
2.1.2 CreatePopupMenu -
POPUPMENU 彈出式菜單
2.1.3 AppenedMenu - 增加菜單項
BOOL AppendMenu(
HMENU hMenu, //菜單句柄
UINT uFlags, //菜單項標示
UINT uIDNewItem, //菜單項的ID或者子菜單句柄
LPCTSTR lpNewItem ); //菜單項的名稱
uFlags:
MF_STRING - lpNewItem是一個字符串
MF_POPUP - uIDNewItem是一個子菜單句柄
MF_SEPARATOR - 增加分隔項
MF_CHECKED/MF_UNCHECKED -
設置和取消菜單項的對勾
MF_DISABLED/MF_ENABLE - 菜單項禁止和
允許狀態
2.2 菜單的命令響應
2.2.1 WM_COMMAND消息
當用戶點擊菜單、按鈕控件等時,系統會向
窗口發送WM_COAMMD消息。
WPARAM:HIWORD - 通知消息標識
LOWORD - 菜單項的ID號
LPARAM:控件的句柄
2.2.2 命令處理
根據菜單項的ID號作相應處理。
2.3 菜單項的狀態
2.3.1 WM_INITMENUPOPUP消息
當用戶點擊菜單,顯示彈出菜單之前,系統
會向窗口發送WM_INITMENUPOPUP消息。
WPARAM:是菜單句柄
LPARAM:LOWORD - 菜單位置
HIWORD - 是否是系統菜單
2.3.2 命令處理
根據WPARAM的菜單句柄,使用MenuAPI函數,
修改菜單狀態。
CheckMenuItem - 選擇
EnableMenuItem - 允許和禁止
SetMenuItemInfo - 可以設置更多信息
代碼:
// WinMessage.cpp : 定義應用程序的入口點。
//
#include "stdafx.h"
#include "WinMessage.h"
#define MAX_LOADSTRING 100
#define WM_FirstMsg WM_USER + 1
#define WM_SecondMsg WM_USER + 2
// 全局變量:
HINSTANCE hInst; // 當前實例
TCHAR szTitle[MAX_LOADSTRING]; // 標題欄文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口類名
HWND g_button;
HANDLE g_consHandle;
// 此代碼模塊中包含的函數的前向聲明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
void newConsole()
{
AllocConsole();
g_consHandle = GetStdHandle(STD_OUTPUT_HANDLE);
CHAR p[] = "debug message .....";
WriteConsole(g_consHandle,p,strlen(p),NULL,NULL);
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代碼。
MSG msg;
HACCEL hAccelTable;
newConsole();
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WINMESSAGE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 執行應用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINMESSAGE));
// 主消息循環:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函數: MyRegisterClass()
//
// 目的: 註冊窗口類。
//
// 註釋:
//
// 僅當希望
// 此代碼與添加到 Windows 95 中的“RegisterClassEx”
// 函數之前的 Win32 系統兼容時,才需要此函數及其用法。調用此函數十分重要,
// 這樣應用程序就可以獲得關聯的
// “格式正確的”小圖標。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINMESSAGE));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINMESSAGE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 函數: InitInstance(HINSTANCE, int)
//
// 目的: 保存實例句柄並創建主窗口
//
// 註釋:
//
// 在此函數中,我們在全局變量中保存實例句柄並
// 創建和顯示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 將實例句柄存儲在全局變量中
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
VOID CALLBACK TimerProc1(
HWND hwnd, // handle to window
UINT uMsg, // WM_TIMER message
UINT_PTR idEvent, // timer identifier
DWORD dwTime // current system time
)
{
char str[30];
sprintf_s(str,"TimerProc1\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
}
HMENU hPopMenu ;
void OnCreate(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
LPCREATESTRUCT pCreate = (LPCREATESTRUCT)lParam;
//MessageBox(NULL,pCreate->lpszName,_T("onCreate"),MB_OK);
//CreateWindowEx(WS_EX_STATICEDGE,_T("BUTTON"),_T("my button"),WS_CHILD ,20,20,20,20,hWnd,NULL,hInst,0);
HWND m_hwnd = CreateWindow(_T("BUTTON"),_T("my button"),WS_CHILD ,10,0,70,20,hWnd,NULL,hInst,0);
SetTimer(hWnd,1,1000,NULL);//有hwnd,
SetTimer(NULL,2,1000,TimerProc1);
//創建主菜單
HMENU hMenu = CreateMenu();
//創建子菜單
hPopMenu = CreatePopupMenu();
AppendMenu(hPopMenu,MF_STRING,1001,"修改");
AppendMenu(hPopMenu,MF_SEPARATOR,0,NULL);
AppendMenu(hPopMenu,MF_STRING,1002,"編輯");
AppendMenu(hPopMenu,MF_STRING,1003,"刪除");
AppendMenu(hMenu,MF_STRING,1011,"新建");
AppendMenu(hMenu,MF_STRING|MF_POPUP,(UINT)hPopMenu,"文件(&F)"); //加了(&F)自動使用快捷鍵alt + F
//創建子菜單
HMENU hPopMenu1 = CreatePopupMenu();
AppendMenu(hPopMenu,MF_STRING,1004,"hell");
AppendMenu(hPopMenu,MF_STRING,1005,"aa");
AppendMenu(hMenu,MF_STRING|MF_POPUP|MF_CHECKED,(UINT)hPopMenu1,"移動");
//設置主菜單
SetMenu(hWnd,hMenu);
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
SendMessage(hWnd,WM_FirstMsg,0,0);
//PostMessage(hWnd,WM_FirstMsg,0,0);
g_button = m_hwnd;
}
void OnSize(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
int width = LOWORD(lParam);
int height = HIWORD(lParam);
CHAR buf[256] = {0};
sprintf_s(buf,"width:%d,height:%d",width,height);
if(g_button != NULL)
{
MoveWindow(g_button,(width-70)/2,(height-20)/2,70,20,TRUE);
}
//printf(buf);
}
void OnSysCommand(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(wParam)
{
case SC_CLOSE:
MessageBox(hWnd,_T("是否將窗口關閉?"),_T(""),MB_YESNO);
PostQuitMessage(0);
//else return FALSE;
break;
}
//return TRUE;
}
//
// 函數: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 處理主窗口的消息。
//
// WM_COMMAND - 處理應用程序菜單
// WM_PAINT - 繪製主窗口
// WM_DESTROY - 發送退出消息並返回
//
//
int x,y;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
char str[40];
HDC hdc;
BOOL f = FALSE;
POINT p;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜單選擇:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意繪圖代碼...
//TextOut(hdc,x,y,"hello",strlen(
// "hello"));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
KillTimer(hWnd,1);
KillTimer(hWnd,2);
PostQuitMessage(0);
break;
case WM_CREATE:
OnCreate(hWnd,message,wParam,lParam);
break;
case WM_SIZE:
OnSize(hWnd,message,wParam,lParam);
break;
case WM_SYSCOMMAND:
OnSysCommand(hWnd,message,wParam,lParam);
break;
case WM_FirstMsg:
//MessageBox(hWnd,_T("firsstMsg"),_T(""),0);
break;
case WM_LBUTTONDOWN:
sprintf_s(str,"WM_LBUTTONDOWN\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
break;
case WM_RBUTTONDOWN:
sprintf_s(str,"WM_RBUTTONDOWN\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
TrackPopupMenu(hPopMenu,MF_POPUP,x,y,0,hWnd,NULL);
break;
case WM_MBUTTONDOWN:
sprintf_s(str,"WM_MBUTTONDOWN\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
break;
case WM_MOUSEMOVE:
if(wParam & MK_CONTROL)
{
sprintf_s(str,"MK_CONTROL\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
}
x = LOWORD(lParam);
y = HIWORD(lParam);
InvalidateRect(hWnd,NULL,TRUE);
p.x = x;
p.y = y;
ClientToScreen(hWnd,&p);
sprintf_s(str,"WM_MOUSEMOVE,X =%dY =%d\n",p.x,p.y);
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
break;
case WM_LBUTTONDBLCLK:
sprintf_s(str,"WM_LBUTTONDBLCLK\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
break;
case WM_MOUSEWHEEL:
sprintf_s(str,"WM_MOUSERWHEEL\n");
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
break;
case WM_TIMER:
sprintf_s(str,"WM_TIMER%d\n",wParam);
WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “關於”框的消息處理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}