win 32 消息机制

消息机制

  • 产生消息
  • 传递消息
  • 处理消息

上述的过程被称为消息机制

    // 主消息循环: 
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

产生消息

把用户事件转变为消息

MSG msg;
//消息的结构体组成
typedef struct tagMSG {
    HWND        hwnd;     //窗口句柄
    UINT        message;  //消息ID,到底是什么消息
    WPARAM      wParam;   //消息辅助参数
    LPARAM      lParam;   //消息辅助参数
    DWORD       time;     //消息产生的时间
    POINT       pt;       //消息产生是鼠标所在的位置
    } MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

传递消息

传递消息除了windows传递给应用程序之外,还需要应用程序主动去接。

windows为每一个正在运行的应用程序维护一个消息队列,所以应用程序只需要和自己对应的消息队列去接。

GetMessage()函数,从应用程序的消息队列去得到消息,该函数为阻塞函数,如果没有消息一直阻塞,有消息,又分两种情况

  1. 消息是WM_QUIT(退出)消息,函数返回false;
  2. 非WM_QUIT(退出)消息,函数返回true
GetMessageW(
    _Out_ LPMSG lpMsg,        //收到的消息放入msg中
    _In_opt_ HWND hWnd,       //得到的消息是哪个窗口的,如果是给主窗口的,给nullptr
    _In_ UINT wMsgFilterMin,  //消息过滤,指第一个消息
    _In_ UINT wMsgFilterMax); //消息过滤,指最后一个消息 
//消息过滤给0表示任何消息都接收

MSG msg;
//实例演示
while (GetMessage(&msg, nullptr, 0, 0))
    {
    	//	Translate 翻译 Accelerator快捷键
    	//如果不是快捷键消息
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg); //翻译消息
            DispatchMessage(&msg);  //投递消息,窗口主程序将消息投递给消息处理函数
        }
    }

PeekMessage()函数,从应用程序的消息队列去得到消息,该函数为非阻塞函数,分两种情况

  1. 有消息返回true
  2. 没消息返回false
PeekMessage(
    _Out_ LPMSG lpMsg,       //收到的消息放入msg中
    _In_opt_ HWND hWnd,      //得到的消息是哪个窗口的,如果是给主窗口的,给nullptr
    _In_ UINT wMsgFilterMin, //消息过滤,指第一个消息
    _In_ UINT wMsgFilterMax, //消息过滤,指最后一个消息 
    _In_ UINT wRemoveMsg);   //取完消息是否移除消息

MSG msg;

//实例演示
ZeroMemory(&msg,sizeof(msg));//内存清零,类似memset
while(msg,message != WM_QUIT)
{
    //如果有消息 PM_REMOVE 表示移除消息 NO_REMOVE 表示不移除消息
    if(PeekMessage(&msg, nullptr, 0, 0,PM_REMOVE))
    {
        //如果不是快捷键消息
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg); //翻译消息
            DispatchMessage(&msg);  //投递消息,窗口主程序将消息投递给消息处理函数
        }
    }
}

SendMessage()函数,投递消息函数

相当于插队,直接把消息发送给当前窗口的消息处理函数WndProc

SendMessage(
    _In_ HWND hWnd,     //投递给哪个窗口消息,如果是不同的窗口,就需要知道对应的窗口句柄
    _In_ UINT Msg,      //投递的是什么样的消息
    _Pre_maybenull_ _Post_valid_ WPARAM wParam, //辅助信息
    _Pre_maybenull_ _Post_valid_ LPARAM lParam);//辅助信息
//相当于插队,直接把消息发送给当前窗口的消息处理函数WndProc,优先处理SendMessage投递的消息。

case WM_KEYDOWN:
{
    //投递消息
    SendMessage(hWnd,WM_LBUTTONDOWN,0,0);
    static int j=0;
    //获取窗口dc
    hdc=GetDC(hWnd);
    TextOut(hdc,0,j,_T("按键按下"),4);
    //释放DC
    ReleaseDC(hWnd,hdc);
    j+=20;
}

PostMessage()函数,投递消息函数

排队,把消息发送到当前窗口的消息处理队列,依次处理

PostMessage(
    _In_opt_ HWND hWnd,   //投递给哪个窗口消息,如果是不同的窗口,就需要知道对应的窗口句柄
    _In_ UINT Msg,        //投递的是什么样的消息
    _In_ WPARAM wParam,   //辅助信息
    _In_ LPARAM lParam);  //辅助信息

//排队,把消息发送到当前窗口的消息处理队列,依次处理,即当前消息处理完成后才会处理PostMessage投递的消息
case WM_KEYDOWN:
{
    //投递消息
    PostMessage(hWnd,WM_LBUTTONDOWN,0,0);
    static int j=0;
    //获取窗口dc
    hdc=GetDC(hWnd);
    TextOut(hdc,0,j,_T("按键按下"),4);
    //释放DC
    ReleaseDC(hWnd,hdc);
    j+=20;
}


处理消息

windows的消息处理函数

WndProc(HWND hWnd,     //接受消息的窗口
        UINT message,  //接受到的消息
        WPARAM wParam, //辅助信息
        LPARAM lParam) //辅助信息
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
            //命令消息,菜单项的id都会在这里
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 分析菜单选择: 
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
             //点击退出
            case IDM_EXIT:
                    //销毁窗口DestroyWindow(hWnd);
                DestroyWindow(hWnd);
                break;
            default:
                    //默认的窗口处理函数DefWindowProc
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    //gdi绘制消息
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            EndPaint(hWnd, &ps);
        }
        break;
    //销毁消息
    case WM_DESTROY:
        PostQuitMessage(0);//post一个WM_QUIT消息
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

重要消息

windows的消息,WM开头,以下介绍一些常见的中重要消息。

**WM_CREATE 创建消息 **

创建窗口消息,理解为构造,这个消息是窗口已经产生,在显示之前响应,这个消息由CreateWindow产生

//WndProc消息处理函数中
switch (message)
{
            //命令消息,菜单项的id都会在这里
    case WM_CREATE:
    {
        //通常在这做资源加载,或者数据的初始化
        MessageBox(hWnd,_"我在窗口之前",0,0);
    }
        break;
}

**WM_DESTORY 销毁消息 **

销毁消息,理解为析构,可以由DestroyWindow(hWnd);函数来产生。

//WndProc消息处理函数中
switch (message)
{
            //命令消息,菜单项的id都会在这里
    case WM_CREATE:
    {
        //通常在这做资源加载,或者数据的初始化
        MessageBox(hWnd,_"我在窗口之前",0,0);
    }
        break;
        //销毁消息
    case WM_DESTORY:
    {
        //通常在这做资源加载,或者数据的初始化
        MessageBox(hWnd,_"我在窗口之前",0,0);
    } 
        break;
}

WM_ACTIVATE 激活消息

窗口激活消息

//WndProc消息处理函数中
switch (message)
{
            //命令消息,菜单项的id都会在这里
    case WM_CREATE:
    {
        //通常在这做资源加载,或者数据的初始化
        MessageBox(hWnd,_T("我在窗口之前"),0,0);
    }
        break;
        //销毁消息
    case WM_DESTORY:
    {
        //通常在这做资源释放
        MessageBox(hWnd,_T("你将关闭窗口"),0,0);
    } 
        break;
    case WM_ACTIVATE:
    {
        //窗口没激活之前,可以用此消息减少当前窗口的资源占用
        switch(wParam) //匹配wParam辅助消息
        {
            case WA_CLICKACTIVE:  //鼠标激活
                break;
            case WA_ACTIVE:      //非鼠标激活 
                break;
            case WA_INACTIVE:    //取消激活,窗口不处于激活状态
                break;
        }
    } 
        break;
}

WM_KEYDOWN 按键按下消息

WM_KEYUP 按键抬起消息

按键的值 虚拟键值,存放在wParam中,无符号的int;

在ASCII码表中就有的值就不再额外设定虚拟键值,会依照ASCII码表,不存在的才有虚拟键值;

虚拟键值都是以VK开头

VK_KEYDOWN响应的只是按键按下消息,如果有上档键Shift是不会响应的,只响应大写的字符

WM_CHAR 字符消息

主消息循环中,翻译消息

TranslateMessage(&msg);

如果有WM_KEYDOWN消息进入,会post出一个WM_CHAR消息

字符消息可以响应大小写字母以及上档键shift

当按键连续按下的时候,window会做一个判断是否是连续按键

//WndProc消息处理函数中
switch (message)
{
        //字符消息
    case WM_CHAR: 
    {
         //字符的消息,也存放在wParam中,无符号的int
         switch(wParam)
         {
             case 'a':
                 MessageBox(hWnd,_T("a键按下"),0,0);
                 break;
                 //通过shift来输入大写
             case 'B':  
                 MessageBox(hWnd,_T("shift+B键按下"),0,0);
                 break;
                 //特殊字符的获取
             case '*':
                 MessageBox(hWnd,_T("shift+8键按下"),0,0);
                 break;
         }
    }
        //按键按下
    case WM_KEYDOWN:
    {
        //按键的值 虚拟键值,存放在wParam中,无符号的int
         switch(wParam)
         {
             case VK_LEFT:
                 {
                     MessageBox(hWnd,_T("方向键左键按下"),0,0);
                 }
                 break;
             case VK_F1:
                 MessageBox(hWnd,_T("F1键按下"),0,0);
                 break;
             //匹配ASCII码表中的字符 //只响应大写的字符
             case 'A':
                 {
                      MessageBox(hWnd,_T("A键按下"),0,0);
                 }
                 break;
             //响应的只是按键按下消息,如果有上档键Shift是不会响应的
         }
    }
        break;
    //按键抬起,同KEYDOWN,只有按键按下才会有按键抬起消息
    case WM_KEYUP:
    {
       
        
    } 
        break;
}

WM_SYSKEYDOWN 系统按键

WM_SYSKEYUP 系统按键

  • 只有alt或F10叫系统按键
  • alt+其他组合键
//WndProc消息处理函数中
switch (message)
{
        //系统按键按下,WM_SYSKEYUP系统按键抬起同按下消息
    case WM_SYSKEYDOWN: 
    {
         //系统按键的消息,也存放在wParam中,无符号的int
         switch(wParam)
         {
                 //alt键按下
             case VK_MENU:
                 MessageBox(hWnd,_T("alt键按下"),0,0);
                 break;
                 //F10键按下
             case VK_F10:  
                 MessageBox(hWnd,_T("F10键按下"),0,0);
                 break;
                 //组合按键的获取
             case 'S':
                 MessageBox(hWnd,_T("alt+S键按下"),0,0);
                 break;
         }
    }
}

WM_SYSCOMMAND 系统命令消息

WM_COMMAND 系统命令消息

//WndProc消息处理函数中
switch (message)
{
        //系统命令消息 //拦截了系统的消息
    case WM_SYSCOMMAND: 
    {
         //系统命令的消息,也存放在wParam中,无符号的int
         switch(wParam)
         {
                 //拦截系统关闭的消息
             case SC_CLOSE:
                 MessageBox(hWnd,_T("系统消息被拦截"),0,0);
                 break;
         }
    }
}

鼠标消息

WM_MOUSEFIRST
WM_MOUSEMOVE 鼠标移动
WM_LBUTTONDOWN 鼠标左键按下
WM_LBUTTONUP 鼠标左键抬起
WM_LBUTTONDBLCLK 鼠标左键双击
WM_RBUTTONDOWN 鼠标右键按下
WM_RBUTTONUP 鼠标右键抬起
WM_RBUTTONDBLCLK 鼠标右键双击
WM_MBUTTONDOWN 鼠标中键按下
WM_MBUTTONUP 鼠标中键抬起
WM_MBUTTONDBLCLK 鼠标中键双击

鼠标的坐标信息都保存在lParam

//WndProc消息处理函数中
switch (message)
{
    //鼠标的左键按下
    case WM_LBUTTONDOWN: 
    {
        //x取低位2字节
		int x = LOWORD(lParam);
        //y取高两位2字节
        int y = HIWORD(lParam);
        TCHAR arr[128] = {};
        _stprintf_s(arr,128,_T("X=%d Y=%d"),x,y);
        hdc = GetDC(hWnd);
        //鼠标位置信息窗口0,0位置输出
        TextOut(hdc,0,0,arr,_tcslen(arr));
        ReleaseDC(hWnd,hdc);
    }
        break;
    //鼠标移动消息
	case WM_MOUSEMOVE:
	{
		        //x取低位2字节
		int x = LOWORD(lParam);
        //y取高两位2字节
        int y = HIWORD(lParam);
        TCHAR arr[128] = {};
        _stprintf_s(arr,128,_T("X=%d Y=%d"),x,y);
        hdc = GetDC(hWnd);
        //鼠标位置信息窗口0,0位置输出
        TextOut(hdc,0,0,arr,_tcslen(arr));
        ReleaseDC(hWnd,hdc);
	}
        break;
}

一个简单的绘制实例

//全局变量
bool isDown = false;
int BeginX;
int BeginY;
//WndProc消息处理函数中
switch (message)
{
    //鼠标的左键按下
    case WM_LBUTTONDOWN: 
    {
        //获取鼠标的位置
        BeginX = LOWORD(lParam);
        BeginY = HIWORD(lParam);
		isDown = true;
    }
        break;
    //鼠标的左键抬起
    case WM_LBUTTONUP: 
    {
		isDown = false;
    }
        break;
    //鼠标移动消息
	case WM_MOUSEMOVE:
	{
		if(isDown)
        {
            //移动时获取鼠标的xy信息
            int x = LOWORD(lParam);
            int y = HIWORD(lParam);
            hdc = GetDC(hWnd);
            //划线的时候把起点移动到某个位置
            MoveToEx(hdc,BeginX,BeginY,nullptr);
            //划线到某个位置
            LineTo(hdc,x,y);
            ReleaseDC(hWnd,hdc);
            //再次更新起始的鼠标x和y的信息
            BeginX = x;
            BeginY = y;
        }
	}
        break;
}

WM_MOUSEWHEEL 鼠标滚轮的滚动

鼠标滚轮滚动的信息放在wParam中

//WndProc消息处理函数中
switch (message)
{
    //鼠标滚轮滚动
    case WM_MOUSEWHEEL: 
    {
		int loVal = LOWORD(wParam);
        //确定鼠标滚轮滚动的信息放在wParam的高位中,通过hiVal的正负,可以判断鼠标是朝前滚动还是朝后滚动,正数朝前滚动,复数朝后滚动
        short hiVal = HIWORD(wParam);
    }
        break;
}

计时器消息

WM_TIMER 计时消息

窗口默认不戴计时器,需要主动的设置SetTimer(hWnd,1001,1000,nullprt);

使用完计时器需要手动销毁KillTimer(hWnd,1001);

//设置计时器
SetTimer(
    _In_opt_ HWND hWnd,             //哪个窗口开启计时器
    _In_ UINT_PTR nIDEvent,         //计时器的id
    _In_ UINT uElapse,              //计时器的时长,毫秒为单位
    _In_opt_ TIMERPROC lpTimerFunc);//时间回调函数,如果为null响应WM_TIMER消息,如果不为空,将直接调用该函数

//销毁计时器
KillTimer(
    _In_opt_ HWND hWnd,           //计时器所在窗口
    _In_ UINT_PTR uIDEvent);      //计时器的id

//计时器回调函数
void my_time(HWND hwnd)
{
    HDC hdc = GetDC(hwnd);
    static int j = 0;
    //x为400的位置输出
	TextOut(hdc,400,j,_("timer_3 id=1003"),7);
	ReleaseDC(hwnd,hdc);
	j+=20; 
}

//WndProc消息处理函数中
switch (message)
{
    //窗口创建时启动计时器
    case WM_CREATE:
    {
        my_time(hWnd);
        SetTimer(hWnd,1001,1000,nullprt); //第一个计时器
        SetTimer(hWnd,1002,2000,nullprt); //第二个计时器
        SetTimer(hWnd,1002,3000,(TIMERPROC)my_time); //第三个计时器,通过回调函数来开启计时器,无需WM_TIMER来响应
    }
        break;
    //开启计时器
    case WM_TIMER:
    {
        switch(wParam)
        {
                //第一个计时器
            case 1001:
                {
                    static int j = 0;
        			hdc=GetDC(hWnd);
                    //x为0的位置输出
        			TextOut(hdc,0,j,_("timer_1 id=1001"),7);
        			ReleaseDC(hWnd,hdc);
        			j+=20; 
                }
                break;
                //第二个计时器
            case 1002:
                {
                    static int j = 0;
        			hdc=GetDC(hWnd);
                    //x为200的位置输出
        			TextOut(hdc,200,j,_("timer_2 id=1001"),7);
        			ReleaseDC(hWnd,hdc);
        			j+=20; 
                }
                break;
        }
       
    }
        break;
        //关闭窗口时候销毁计时器
    case WQ_QUIT:
        {
            //销毁第一个计时器
            KillTimer(hWnd,1001);
            //销毁第二个计时器
            KillTimer(hWnd,1002);
            //销毁第二个计时器
            KillTimer(hWnd,1003);
        }
        break;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值