win32第五天

本文深入探讨了Windows窗口的交互方式与事件处理机制,包括WM_PAINT、WM_KEYDOWN、WM_KEYUP、WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE、WM_LBUTTONDBLCLK、定时器消息等核心概念,以及如何通过这些消息实现窗口的动态更新、键盘与鼠标的响应、鼠标跟随功能,并结合定时器实现简单的动态效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WM_PAINT
    当窗口需要绘制的时候,会发送窗口处理函数。
窗口无效区域 
    被声明成需要重新绘制的区域。
void OnPaint(){
char *pzText="WM_PAINT\n";
WriteConsole(h_output,pzText,strlen(pzText),NULL,NULL);
}
BOOL InvalidateRect(
     HWND hWnd,  //窗口句柄
     CONST RECT* lpRect,  //区域的矩形坐标,如果指定为NULL,则表明全部需要重绘。
     BOOL bErase  //重绘前是否先擦除
);
在程序中,如果需要绘制窗口,调用函数声明窗口无效区域。
case WM_LBUTTONDOWN:InvalidateRect(hwnd,NULL,TRUE);break;当点击一次则鼠标窗口需要重新被绘制一次。


WM_PAINT参数
WPARAM - 不使用
LPARAM - 不使用


消息处理步骤
1 开始绘图处理
HDC BeginPaint(
HWND hwnd, //绘图窗口
LPPAINTSTRUCT lpPaint //绘图参数的BUFF
); 返回绘图设备句柄HDC
2 绘图
3 结束绘图处理
BOOL EndPaint(
HWND hWnd, //绘图窗口
CONST PAINTSTRUCT *lpPaint  //绘图参数的指针BeginPaint返回
);


先绘制一个小东西 :
PAINTSTRUCT ps;
HDC hDC=BeginPaint(hWnd,&ps);
TextOut(hDC,100,100,"HELLO",strlen("HELLO"));
EndPaint(hWnd,&ps);




键盘消息
1 键盘消息
WM_KEYDOWN - 按键被按下时产生
WM_KEYUP - 按键被放开时产生
WM_SYSKEYDOWN - 系统键按下时产生  比如ALT、F10
WM_SYSKEYUP - 系统键放开时产生
WM_CHAR - 字符消息
2 消息参数
按键消息:
        WPARAM - 按键的Virtual Key
LPARAM - 按键的参数,例如按下次数
WM_CHAR消息:
        WPARAM - 输入的字符
        LPARAM - 按键的相关参数
void OnKeyDown(HWND hWnd,WPARAM wParam){
LONG virtueKey=wParam;
char szText[256];
sprintf(szText,"WM_KEYDOWN:%0x\n",virtueKey);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
void OnKeyUp(HWND hWnd,WPARAM wParam){
LONG virtueKey=wParam;
char szText[256];
sprintf(szText,"WM_KEYUP:%0x\n",virtueKey);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
通过上述代码可了解到a的虚拟键码为41,其它字母依次递增。大小写都一样。
功能实现:窗口上有一个单词,按向上方向键这个单词向上,按向左它向左,按向右它向右。
//控制字母移动
switch(virtueKey){
case VK_UP:
yPos--;
InvalidateRect(hWnd,NULL,TRUE);
break;
case VK_DOWN:
yPos++;
InvalidateRect(hWnd,NULL,TRUE);
break;
case VK_LEFT:
xPos--;
InvalidateRect(hWnd,NULL,TRUE);
break;
case VK_RIGHT:
xPos++;
InvalidateRect(hWnd,NULL,TRUE);
break;
}
消息的使用
1 KEYDOWN可以重复出现,KEYUP只能在按键松开时出现1次
2 TranslateMessage在转换WM_KEYDODN消息时,对于可见字符可以产生WM_CHAR,不可见字符无此消息。
3 WM_KEYWODN/UP的wParam是表示的按键,WM_CHAR的wParam是表示输入的字符。
TranslateMessage(&nMsg){
if(nMsg.message!=WM_KEYDOWN)
{
return;
}
通过nMsg.wParam可以判断是否为可见字符的按键。
if(不是可见字符的按键)
return;
判断Caps Lock按键是否打开,根据Caps Lock按键的状态将虚拟键码转换为AscII字符编码。
PostMessage(nMsg.hWnd,WM_CHAR,Asii编码)


}




鼠标消息
1 基本鼠标消息
WM_LBUTTONDOWN - 鼠标左键按下
WM_LBUTTONUP - 鼠标左键抬起
WM_RBUTTONDOWN - 鼠标右键按下
WM_RBUTTONUP - 鼠标右键抬起
WM_MOUSEMOVE - 鼠标移动消息
2 双击消息
WM_LBUTTONDBLCLK - 鼠标左键双击
WM_RBUTTONDBLCLK - 鼠标右键双击
3 滚轮消息
WM_MOUSEWHEEL - 鼠标滚轮消息
基本鼠标消息
消息参数
WPARAM - 其他按键的状态,例如Ctrl/Shift等
LPARAM - 鼠标的位置,窗口客户区坐标系。
LOWORD X坐标位置
HIWORD Y坐标位置
鼠标消息使用
一般情况鼠标按下/抬起成对出现。在鼠标移动过程中,会根据移动速度产生一系列的WM_MOUSEMOVE消息。
双击鼠标消息
消息参数
WPARAM - 其他按键的状态,例如Ctrl/Shift等
LPARAM - 鼠标的位置,窗口客户区坐标系。
LOWORD X坐标位置
HIWORD Y坐标位置
使用时需要在注册窗口类的时候添加CS_DBLCLKS 风格。
消息产生顺序
    以WM_LBUTTONDBLCLK为例:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
鼠标消息使用代码
void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam){
char szText[256];
sprintf(szText,"LButtonDown:x=%d,y=%d,按键状态=%0x\n",LOWORD(lParam),HIWORD(lParam),wParam);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam){
char szText[256];
sprintf(szText,"LButtonUp:x=%d,y=%d,按键状态=%0x\n",LOWORD(lParam),HIWORD(lParam),wParam);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
功能实现:同样一个字符串,鼠标到哪它到哪,鼠标跟随
void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam){
 xPos=LOWORD(lParam);
 yPos=HIWORD(lParam);
InvalidateRect(hWnd,NULL,TRUE);
}
void OnPaint(HWND hWnd){
PAINTSTRUCT ps;
HDC hDC=BeginPaint(hWnd,&ps);
TextOut(hDC,xPos,yPos,"hello,string",strlen("hello,string"));
EndPaint(hWnd,&ps);
}
双击消息代码(窗口类风格中添加:CS_DBLCLKS )
void OnLButtonDBLCLK(HWND hWnd,WPARAM wParam,LPARAM lParam){
char szText[256];
strcpy(szText,"onlbuttondbclk");
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
鼠标滚轮 WM_MOUSEWHEEL
消息参数
WPARAM:
LOWORD - 其他按键的状态
HIWORD - 滚轮的偏移量,是120的倍数,通过正负值表示表示滚动方向。
正:向前滚动
负:向后滚动
LPARAM:鼠标当前的位置,屏幕坐标系
LOWORD - X坐标
HIWORD - Y坐标
使用
通过偏移量,获取滚动的方向和倍数。
鼠标滚动代码如下:
关于OnMouseMove找不到标识的解决办法:
打开StdAfx.h,或在文件第一行添加
#define _WIN32_WINNT 0X400


定时器消息
1 定时器消息
可以在程序中设置定时器,当到达时间
间隔时,定时器会向程序发送一个
WM_TIMER消息。
定时器的精度是毫秒,但是准确度很低。
例如设置时间间隔为1000ms,但是会在
非1000毫秒到达。
2 消息的参数
WPARAM - 定时器ID
LPARAM - 定时器处理函数的指针
3.1 创建定时器
UINT_SetTimer(
HWND hWnd,//定时器窗口句柄
UINT nIDEvent, //定时器ID
UINT uElapse,//时间间隔
TIMERPROC lpTimerFunc //定时器处理函数指针
);创建成功,返回非0。
使用窗口处理函数,做为定时器处理函数,lpTimerFunc为NULL
使用定时器处理函数处理定时器消息。
3.2 消息处理  WM_TIMER
3.3 关闭定时器
BOOL KillTimer(
HWND hWnd,//定时器窗口句柄
UINT uIDEvent //定时器ID
);
附:GetClientRect 获取窗口客户区大小
void OnCreate(HWND hWnd){
SetTimer(hWnd,1,1000,NULL);
SetTimer(hWnd,2,2000,NULL);
}
void OonTimer(HWND hWnd,WPARAM wParam){
CHAR szText[256];
sprintf(szText,"timer:id=%d\n",wParam);
WriteConsole(h_output,szText,strlen(szText),NuLL,NULL);
}
如果要自己定义时间处理函数:必须如下
void CALLBACK TimerProc(
  HWND hwnd, 
  UINT uMsg, 
  UINT idEvent, 
  DWORD dwTime 
); 
练习:小球在窗口中弹
GetClientRect--获取窗口客户区的边界
不得不佩服自己的能力,自己可以在半小时内搞定这个代码,太了不起了,有一个就是InvalidateRect这个函数给记错了耽误了很多时间,不过自己的逻辑太厉害。
#define _WIN32_WINNT 0X400
#include "windows.h"
#include<stdio.h>


HINSTANCE g_hInstance;//应用程序实例句柄
HANDLE h_output;//标准输出句柄
int xPos=100;
int yPos=100;
int xPos2=10;
int yPos2=10;
void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam){
char szText[256];
sprintf(szText,"LButtonDown:x=%d,y=%d,按键状态=%0x\n",LOWORD(lParam),HIWORD(lParam),wParam);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam){
char szText[256];
sprintf(szText,"LButtonUp:x=%d,y=%d,按键状态=%0x\n",LOWORD(lParam),HIWORD(lParam),wParam);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam){
 xPos=LOWORD(lParam);
 yPos=HIWORD(lParam);
InvalidateRect(hWnd,NULL,TRUE);
}
void OnPaint(HWND hWnd){
PAINTSTRUCT ps;
HDC hDC=BeginPaint(hWnd,&ps);
TextOut(hDC,xPos,yPos,"hello,string",strlen("hello,string"));
Ellipse(hDC,xPos,yPos,xPos+50,yPos+50);
EndPaint(hWnd,&ps);
}
void OnLButtonDBLCLK(HWND hWnd,WPARAM wParam,LPARAM lParam){
char szText[256];
strcpy(szText,"onlbuttondbclk");
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
void OnMouseWheel(HWND hWnd,WPARAM wParam){
char szText[256];
int length=HIWORD(wParam);
sprintf(szText,"滚动消息%d\n",length);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}
void OnTimer(HWND hWnd,WPARAM wParam,LPARAM lParam){
RECT rc;
int x=xPos;
int y=yPos;
GetClientRect(hWnd,&rc);
InvalidateRect(hWnd,NULL,TRUE);
if(xPos+50>=rc.right&&yPos2<yPos){
xPos--;yPos++;
}
else if(xPos<=rc.left&&yPos2<yPos){
xPos++;yPos++;
}
else if(xPos<=rc.left&&yPos2>yPos){
xPos++;yPos--;
}
else if(xPos+50>=rc.right&&yPos2>yPos){
xPos--;yPos--;
}
else if(yPos+50>=rc.bottom&&xPos2<xPos){
yPos--;xPos++;
}
else if(yPos+50>=rc.bottom&&xPos2>xPos){
yPos--;xPos--;
}
else if(yPos<=rc.top&&xPos2<xPos){
xPos++;yPos++;
}
else if(yPos<=rc.top&&xPos2>xPos){
xPos--;yPos++;
}
 if(xPos2<xPos&&yPos2<yPos){
xPos++,yPos++;
WriteConsole(h_output,"abc",4,NULL,NULL);
}
 if(xPos2<xPos&&yPos2>yPos){
xPos++,yPos--;
}
 if(xPos2>xPos&&yPos2<yPos){
xPos--,yPos++;
}
if(xPos2>xPos&&yPos2>yPos){
xPos--,yPos--;
}
xPos2=x;
yPos2=y;

}
void OnCreate(HWND hWnd){
SetTimer(hWnd,1,1,NULL);
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){
switch(uMsg){
case WM_TIMER:
OnTimer(hWnd,wParam,lParam);
break;
case WM_CREATE:
OnCreate(hWnd);
break;
//case WM_MOUSEWHEEL:
// OnMouseWheel(hWnd,wParam);
// break;
//case WM_LBUTTONDBLCLK:
// OnLButtonDBLCLK(hWnd,wParam,lParam);
// break;
//case WM_MOUSEMOVE:
// OnMouseMove(hWnd,wParam,lParam);
// break;
case WM_PAINT:
OnPaint(hWnd);
break;
//case WM_LBUTTONDOWN:
// OnLButtonDown(hWnd,wParam,lParam);
// break;
//case WM_LBUTTONUP:
// OnLButtonUp(hWnd,wParam,lParam);
// break;
case WM_DESTROY:
PostQuitMessage(0);break;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);


}


BOOL Register(LPSTR lpClassName,WNDPROC wndproc){
WNDCLASSEX wce;
ATOM nAtom;
wce.cbSize=sizeof(wce);
wce.cbClsExtra=0;
wce.cbWndExtra=0;
wce.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wce.hCursor=NULL;
wce.hIcon=NULL;
wce.hIconSm=NULL;
wce.hInstance=g_hInstance;
wce.lpfnWndProc=wndproc;
wce.lpszMenuName=NULL;
wce.lpszClassName=lpClassName;
wce.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
nAtom=RegisterClassEx(&wce);
if(nAtom==0)
return FALSE;
return TRUE;
}


HWND Create(LPSTR lpClassName,LPSTR lpWndName){
HWND hWnd=CreateWindowEx(0,lpClassName,lpWndName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,g_hInstance,NULL);
return hWnd;
}


void Display(HWND hWnd){
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}


void Message(){
MSG nMsg;
while(GetMessage(&nMsg,NULL,0,0)){
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}


int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int nCmdShow){
HWND hWnd;
g_hInstance=hInstance;
AllocConsole();
h_output=GetStdHandle(STD_OUTPUT_HANDLE);
if(!Register("Main",WndProc)){
MessageBox(NULL,"注册失败","Error",MB_OK);
}
hWnd=Create("Main","error");
Display(hWnd);
Message();
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值