win32day05-鼠标消息/定时器消息/菜单
Posted 吴英强
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win32day05-鼠标消息/定时器消息/菜单相关的知识,希望对你有一定的参考价值。
鼠标消息
1 鼠标消息1) 基本鼠标消息
WM_LBUTTONDOWN 左键按下
WM_LBUTTONUP 左键抬起
WM_RBUTTONDOWN 右键按下
WM_RBUTTONUP 右键抬起
WM_MOUSEMOVE 鼠标移动
2) 双击消息
WM_LBUTTONDBLCLK 左键双击
WM_RBUTTONDBLCLK 右键双击
3) 滚轮消息
WM_MOUSEWHEEL 鼠标滚轮
2消息的参数
WPARAM -当前键盘和鼠标按键状态,例如K_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的倍数,可以为正负值.
正值: 滚轮向上滚动,一般窗口向上滚动
负值: 滚轮向下滚动,一般窗口向下滚动
// WinMouse.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "stdio.h"
HINSTANCE g_hInst = NULL;
HANDLE g_hStdOut = NULL;
int g_nXPos = 0;
int g_nYPos = 0;
int g_nX1Rect = 0;
int g_nY1Rect = 0;
int g_nX2Rect = 0;
int g_nY2Rect = 0;
void PrintLog( LPSTR pszLog )
WriteConsole( g_hStdOut,
pszLog, strlen(pszLog), NULL, NULL );
void OnPaint( HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam )
PAINTSTRUCT ps = 0 ;
HDC hDC = BeginPaint( hWnd, &ps );
CHAR szText[] = "Hello Mouse";
TextOut( hDC, g_nXPos, g_nYPos,
szText, strlen(szText) );
Rectangle( hDC, g_nX1Rect, g_nY1Rect,
g_nX2Rect, g_nY2Rect );
EndPaint( hWnd, &ps );
LRESULT CALLBACK WndProc( HWND hWnd,
UINT nMsg,
WPARAM wParam,
LPARAM lParam )
switch( nMsg )
case WM_PAINT:
OnPaint( hWnd, nMsg, wParam, lParam );
break;
case WM_LBUTTONDOWN:
PrintLog( "WM_LBUTTONDOWN\\n" );
g_nX1Rect = LOWORD( lParam );
g_nY1Rect = HIWORD( lParam );
break;
case WM_LBUTTONUP:
PrintLog( "WM_LBUTTONUP\\n" );
g_nX2Rect = LOWORD( lParam );
g_nY2Rect = HIWORD( lParam );
InvalidateRect( hWnd, NULL, TRUE );
break;
case WM_RBUTTONDOWN:
PrintLog( "WM_RBUTTONDOWN\\n" );
break;
case WM_RBUTTONUP:
PrintLog( "WM_RBUTTONUP\\n" );
break;
case WM_MOUSEMOVE:
int nX = LOWORD(lParam);
int nY = HIWORD(lParam);
POINT ptScreen = 0 ;
ptScreen.x = nX;
ptScreen.y = nY;
ClientToScreen( hWnd, &ptScreen );
CHAR szText[260] = 0 ;
sprintf( szText,
"WM_MOUSEMOVE: X=%d(%d),Y=%d(%d)\\n",
nX, ptScreen.x, nY, ptScreen.y );
PrintLog( szText );
if( wParam & MK_CONTROL )
PrintLog( "WM_MOUSEMOVE: MK_CONTROL\\n" );
if( wParam & MK_LBUTTON )
PrintLog( "WM_MOUSEMOVE: MK_LBUTTON\\n" );
g_nXPos = LOWORD(lParam);
g_nYPos = HIWORD(lParam);
InvalidateRect( hWnd, NULL, TRUE );
break;
case WM_LBUTTONDBLCLK:
PrintLog( "WM_LBUTTONDBLCLK\\n" );
break;
case WM_RBUTTONDBLCLK:
PrintLog( "WM_RBUTTONDBLCLK\\n" );
break;
case WM_MOUSEWHEEL:
short nDetla = HIWORD( wParam );
int nX = LOWORD( lParam );
int nY = HIWORD( lParam );
CHAR szText[260] = 0 ;
sprintf( szText,
"WM_MOUSEWHEEL: Detla=%d, X=%d,Y=%d\\n",
nDetla, nX, nY );
PrintLog( szText );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
return DefWindowProc( hWnd, nMsg,
wParam, lParam );
BOOL RegisterWnd( LPSTR pszClassName )
WNDCLASSEX wce = 0 ;
wce.cbSize = sizeof( wce );
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hbrBackground = HBRUSH(COLOR_WINDOW);
wce.hCursor = NULL;
wce.hIcon = NULL;
wce.hIconSm = NULL;
wce.hInstance = g_hInst;
wce.lpfnWndProc = WndProc;
wce.lpszClassName = pszClassName;
wce.lpszMenuName = NULL;
wce.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
ATOM nAtom = RegisterClassEx( &wce );
if( 0 == nAtom )
return FALSE;
return TRUE;
HWND CreateWnd( LPSTR pszClassName )
HWND hWnd = CreateWindowEx( 0,
pszClassName, "MyWnd",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL,
g_hInst, NULL );
return hWnd;
void DisplayWnd( HWND hWnd )
ShowWindow( hWnd, SW_SHOW );
UpdateWindow( hWnd );
void Message( )
MSG msg = 0 ;
while( GetMessage( &msg, NULL, 0, 0 ) )
TranslateMessage( &msg );
DispatchMessage( &msg );
void NewConsole( )
AllocConsole( );
g_hStdOut =
GetStdHandle( STD_OUTPUT_HANDLE );
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
NewConsole( );
g_hInst = hInstance;
RegisterWnd( "MyWnd" );
HWND hWnd = CreateWnd( "MyWnd" );
DisplayWnd( hWnd );
Message( );
return 0;
定时器消息
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 );
// WinTimer.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "stdio.h"
HINSTANCE g_hInst = NULL;
HANDLE g_hStdOut = NULL;
UINT g_nTimerID1 = 0;
void CALLBACK TimerProc1( HWND hWnd,
UINT nMsg,
UINT idEvent,
DWORD dwTime )
CHAR szText[] = "TimerProc1: Hello Timer\\n";
WriteConsole( g_hStdOut, szText,
strlen(szText), NULL, NULL );
void OnCreate( HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam )
//使用窗口处理函数,创建2个定时器
SetTimer( hWnd, 1000, 3 * 1000, NULL );
SetTimer( hWnd, 1001, 5 * 1000, NULL );
//使用窗口处理函数, 未指明定时器ID
g_nTimerID1 = SetTimer( hWnd, 0,
1 * 1000, NULL );
//使用TimerProc处理函数创建定时器
SetTimer( hWnd, 1002, 7 * 1000, TimerProc1 );
void OnTimer( HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam )
switch( wParam )
case 1000:
CHAR szText[] = "1000: Hello Timer\\n";
WriteConsole( g_hStdOut, szText,
strlen(szText), NULL, NULL );
break;
case 1001:
CHAR szText[] = "1001: Hello Timer\\n";
WriteConsole( g_hStdOut, szText,
strlen(szText), NULL, NULL );
break;
default:
CHAR szText[260] = 0;
sprintf( szText, "%d: Hello Timer\\n",
g_nTimerID1 );
WriteConsole( g_hStdOut, szText,
strlen(szText), NULL, NULL );
break;
LRESULT CALLBACK WndProc( HWND hWnd,
UINT nMsg,
WPARAM wParam,
LPARAM lParam )
switch( nMsg )
case WM_CREATE:
OnCreate( hWnd, nMsg, wParam, lParam );
break;
case WM_TIMER:
OnTimer( hWnd, nMsg, wParam, lParam );
break;
case WM_DESTROY:
KillTimer( hWnd, 1000 );
PostQuitMessage( 0 );
return 0;
return DefWindowProc( hWnd, nMsg,
wParam, lParam );
BOOL RegisterWnd( LPSTR pszClassName )
WNDCLASSEX wce = 0 ;
wce.cbSize = sizeof( wce );
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hbrBackground = HBRUSH(COLOR_WINDOW);
wce.hCursor = NULL;
wce.hIcon = NULL;
wce.hIconSm = NULL;
wce.hInstance = g_hInst;
wce.lpfnWndProc = WndProc;
wce.lpszClassName = pszClassName;
wce.lpszMenuName = NULL;
wce.style = CS_VREDRAW|CS_HREDRAW;
ATOM nAtom = RegisterClassEx( &wce );
if( 0 == nAtom )
return FALSE;
return TRUE;
HWND CreateWnd( LPSTR pszClassName )
HWND hWnd = CreateWindowEx( 0,
pszClassName, "MyWnd",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL,
g_hInst, 0 );
return hWnd;
void DisplayWnd( HWND hWnd )
ShowWindow( hWnd, SW_SHOW );
UpdateWindow( hWnd );
void Message( )
MSG msg = 0;
while ( GetMessage( &msg, NULL, 0, 0 ) )
TranslateMessage( &msg );
DispatchMessage( &msg );
void NewConsole( )
AllocConsole( );
g_hStdOut =
GetStdHandle( STD_OUTPUT_HANDLE );
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
NewConsole( );
g_hInst = hInstance;
RegisterWnd( "MYWND" );
HWND hWnd = CreateWnd( "MYWND" );
DisplayWnd( hWnd );
Message( );
return 0;
菜单
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 - 可以设置更多信息
// WinMenu.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "stdio.h"
HINSTANCE g_hInst = NULL;
HANDLE g_hStdOut = NULL;
BOOL g_bCheckCut = FALSE;
void OnCreate( HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam )
//创建主菜单
HMENU hMainMenu = CreateMenu( );
//创建子菜单
HMENU hFileMenu = CreatePopupMenu( );
//增加菜单项
AppendMenu( hFileMenu, MF_STRING|MF_CHECKED, 1001, "新建(&N)");
AppendMenu( hFileMenu, MF_SEPARATOR, 0, NULL );
AppendMenu( hFileMenu, MF_STRING, 1002, "退出(&X)");
AppendMenu( hMainMenu, MF_STRING|MF_POPUP,
(UINT)hFileMenu, "文件(&F)");
HMENU hEditMenu = CreatePopupMenu( );
AppendMenu( hEditMenu, MF_STRING, 1003, "剪切(&T)" );
AppendMenu( hEditMenu, MF_STRING, 1004, "拷贝(&C)" );
AppendMenu( hEditMenu, MF_STRING, 1005, "粘贴(&P)" );
AppendMenu( hMainMenu, MF_STRING|MF_POPUP,
(UINT)hEditMenu, "编辑(&E)");
HMENU hHelpMenu = CreatePopupMenu( );
AppendMenu( hHelpMenu, MF_STRING, 1006, "帮助(&H)" );
AppendMenu( hHelpMenu, MF_STRING, 1007, "关于(&A)" );
AppendMenu( hMainMenu, MF_STRING|MF_POPUP,
(UINT)hHelpMenu, "帮助(&H)");
//给窗口设置主菜单
SetMenu( hWnd, hMainMenu );
void OnCommand( HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam )
UINT nID = LOWORD( wParam );
CHAR szText[260] = 0;
sprintf( szText, "OnCommand: %d\\n",
nID );
WriteConsole( g_hStdOut, szText,
strlen(szText), NULL, NULL );
switch( nID )
case 1002:
PostQuitMessage( 0 );
break;
case 1003:
g_bCheckCut = !g_bCheckCut;
break;
void OnInitMenuPopup( HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam )
CHAR szText[260] = 0 ;
sprintf( szText,
"OnInitMenuPopup: WPARAM=%08X, LPARAM=%08X\\n",
wParam, lParam );
WriteConsole( g_hStdOut, szText,
strlen(szText), NULL, NULL );
HMENU hMenu = (HMENU)wParam;
if( TRUE == g_bCheckCut )
CheckMenuItem( hMenu, 1003,
MF_CHECKED|MF_BYCOMMAND );
else
CheckMenuItem( hMenu, 1003,
MF_UNCHECKED|MF_BYCOMMAND );
LRESULT CALLBACK WndProc( HWND hWnd,
UINT nMsg,
WPARAM wParam,
LPARAM lParam )
switch( nMsg )
case WM_CREATE:
OnCreate( hWnd, nMsg, wParam, lParam );
break;
case WM_COMMAND:
OnCommand( hWnd, nMsg, wParam, lParam );
break;
case WM_INITMENUPOPUP:
OnInitMenuPopup( hWnd, nMsg, wParam, lParam );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
return DefWindowProc( hWnd, nMsg,
wParam, lParam );
BOOL RegisterWnd( LPSTR pszClassName )
WNDCLASSEX wce = 0 ;
wce.cbSize = sizeof( wce );
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hbrBackground = HBRUSH(COLOR_WINDOW);
wce.hCursor = NULL;
wce.hIcon = NULL;
wce.hIconSm = NULL;
wce.hInstance = g_hInst;
wce.lpfnWndProc = WndProc;
wce.lpszClassName = pszClassName;
wce.lpszMenuName = NULL;
wce.style = CS_VREDRAW|CS_HREDRAW;
ATOM nAtom = RegisterClassEx( &wce );
if( 0 == nAtom )
return FALSE;
return TRUE;
HWND CreateWnd( LPSTR pszClassName )
HWND hWnd = CreateWindowEx( 0,
pszClassName, "MyWnd",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL,
g_hInst, 0 );
return hWnd;
void DisplayWnd( HWND hWnd )
ShowWindow( hWnd, SW_SHOW );
UpdateWindow( hWnd );
void Message( )
MSG msg = 0;
while ( GetMessage( &msg, NULL, 0, 0 ) )
TranslateMessage( &msg );
DispatchMessage( &msg );
void NewConsole( )
AllocConsole( );
g_hStdOut =
GetStdHandle( STD_OUTPUT_HANDLE );
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
NewConsole( );
g_hInst = hInstance;
RegisterWnd( "MYWND" );
HWND hWnd = CreateWnd( "MYWND" );
DisplayWnd( hWnd );
Message( );
return 0;
以上是关于win32day05-鼠标消息/定时器消息/菜单的主要内容,如果未能解决你的问题,请参考以下文章