zzxwbs 发表于 2017-6-15 21:53:49

win32编程(003)——绘图消息,键鼠消息,定时器消息和菜单的使用

本帖最后由 zzxwbs 于 2017-6-18 00:44 编辑

1.绘图消息WM_PAINT
当窗口需要绘制的时候,会发送窗口处理函数。

#include "stdafx.h"

HANDLE g_hOutout = 0;
void OnPaint(HWND hWnd)
{
        char *pszText = "WM_PAINT\n";
        WriteConsole(g_hOutout,pszText,strlen(pszText),NULL,NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

1.1InvalidateRect函数
在程序中,如果需要绘制窗口,调用函数声明窗口无效区域。向指定的窗体更新区域添加一个矩形,然后窗口客户区域的这一部分将被重新绘制。
窗口无效区域:被声明成需要重新绘制的区域。

BOOL InvalidateRect(
HWND hWnd,//窗口句柄
CONST RECT* lpRect,//区域的矩形坐标
BOOL bErase//重绘前是否先擦除
);

#include "stdafx.h"

HANDLE g_hOutout = 0;
void OnPaint(HWND hWnd)
{
        char *pszText = "WM_PAINT\n";
        WriteConsole(g_hOutout,pszText,strlen(pszText),NULL,NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_LBUTTONDOWN://鼠标左点击
                InvalidateRect(hWnd,NULL,TRUE);//将窗口声明为需要重绘
                break;
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

1.2绘图编程(今天只做简单介绍)
画图的几个步骤
消息处理步骤
1.2.1开始绘图处理
HDC BeginPaint(
        HWND hwnd, //绘图窗口
        LPPAINTSTRUCT lpPaint //绘图参数的BUFF
); 返回绘图设备句柄HDC
1.2.2绘图
1.2.3结束绘图处理
BOOL EndPaint(
        HWND hWnd, //绘图窗口
        CONST PAINTSTRUCT *lpPaint//绘图参数的指针BeginPaint返回
);

#include "stdafx.h"

HANDLE g_hOutout = 0;
void OnPaint(HWND hWnd)
{
        char *pszText = "WM_PAINT\n";
        WriteConsole(g_hOutout,pszText,strlen(pszText),NULL,NULL);
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd,&ps);
        TextOut(hdc,100,100,"fishc",5);
        EndPaint(hWnd,&ps);
        //以上绘图的代码必须放在WM_PAINT消息处理中调用
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_LBUTTONDOWN://鼠标左点击
                InvalidateRect(hWnd,NULL,TRUE);//将窗口声明为需要重绘
                break;
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

2.键盘消息
2.1键盘消息
        WM_KEYDOWN - 按键被按下时产生
        WM_KEYUP - 按键被放开时产生
        WM_SYSKEYDOWN - 系统键按下时产生比如ALT、F10
        WM_SYSKEYUP - 系统键放开时产生
        WM_CHAR - 字符消息
2.2消息参数
2.2.1按键消息:
WPARAM - 按键的Virtual Key(虚拟键码),无法区分大小写
LPARAM - 按键的参数,例如按下次数                       

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;

void OnPaint(HWND hWnd)
{
        char *pszText = "WM_PAINT\n";
        WriteConsole(g_hOutout,pszText,strlen(pszText),NULL,NULL);
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd,&ps);
        TextOut(hdc,100,100,"fishc",5);
        EndPaint(hWnd,&ps);
        //以上绘图的代码必须放在WM_PAINT消息处理中调用
}

void OnKeyDown( HWND hWnd, WPARAM wParam )
{
        char szText = { 0 };
        sprintf( szText, "WM_KEYDOWN:%08X\n", wParam );
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,
                NULL );
}

void OnKeyUp( HWND hWnd, WPARAM wParam )
{
        char szText = { 0 };
        sprintf( szText, "WM_KEYUP:%08X\n", wParam );
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,
                NULL );
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_KEYDOWN:
                OnKeyDown( hWnd, wParam );
                break;
        case WM_KEYUP:
                OnKeyUp( hWnd, wParam );
                break;
        case WM_LBUTTONDOWN://鼠标左点击
                InvalidateRect(hWnd,NULL,TRUE);//将窗口声明为需要重绘
                break;
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

用上下左右键控制fishc的位置
#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_xPos = 100;
int g_yPos = 100;
void OnPaint(HWND hWnd)
{
        char *pszText = "WM_PAINT\n";
        WriteConsole(g_hOutout,pszText,strlen(pszText),NULL,NULL);
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd,&ps);
        TextOut(hdc,g_xPos,g_yPos,"fishc",5);
        EndPaint(hWnd,&ps);
        //以上绘图的代码必须放在WM_PAINT消息处理中调用
}

void OnKeyDown( HWND hWnd, WPARAM wParam )
{
        char szText = { 0 };
        sprintf( szText, "WM_KEYDOWN:%08X\n", wParam );
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,
                NULL );
        switch(wParam)
        {
        case VK_UP:
                g_yPos--;
                break;
        case VK_DOWN:
                g_yPos++;
                break;
        case VK_LEFT:
                g_xPos--;
                break;
        case VK_RIGHT:
                g_xPos++;
                break;
        }
        InvalidateRect(hWnd,NULL,TRUE);
}

void OnKeyUp( HWND hWnd, WPARAM wParam )
{
        char szText = { 0 };
        sprintf( szText, "WM_KEYUP:%08X\n", wParam );
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,
                NULL );
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_KEYDOWN:
                OnKeyDown( hWnd, wParam );
                break;
        case WM_KEYUP:
                OnKeyUp( hWnd, wParam );
                break;
        case WM_LBUTTONDOWN://鼠标左点击
                InvalidateRect(hWnd,NULL,TRUE);//将窗口声明为需要重绘
                break;
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

2.2.2WM_CHAR消息:
WPARAM - 输入的字符(ASC字符编码),可以区分大小写
LPARAM - 按键的相关参数

2.3消息的使用总结
2.3.1KEYDOWN可以重复出现,KEYUP只能在按键松开时出现1次
2.3.2TranslateMessage在转换WM_KEYDOWN消息时,对于可见字符可以产生WM_CHAR,不可见字符无此消息。
2.3.3WM_KEYDOWN/UP的wParam是表示的按键,WM_CHAR是表示输入的字符。

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_xPos = 100;
int g_yPos = 100;
void OnPaint(HWND hWnd)
{
        char *pszText = "WM_PAINT\n";
        WriteConsole(g_hOutout,pszText,strlen(pszText),NULL,NULL);
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd,&ps);
        TextOut(hdc,g_xPos,g_yPos,"fishc",5);
        EndPaint(hWnd,&ps);
        //以上绘图的代码必须放在WM_PAINT消息处理中调用
}

void OnKeyDown( HWND hWnd, WPARAM wParam )
{
        char szText = { 0 };
        sprintf( szText, "WM_KEYDOWN:%08X\n", wParam );
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,
                NULL );
}

void OnKeyUp( HWND hWnd, WPARAM wParam )
{
        char szText = { 0 };
        sprintf( szText, "WM_KEYUP:%08X\n", wParam );
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,
                NULL );
}
void OnChar(HWND hWnd,WPARAM wParam)
{
        char szText = {0};
        sprintf(szText,"WM_CHAR:0x%08X\n",wParam);
        WriteConsole( g_hOutout, szText, strlen(szText), NULL,NULL );
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_CHAR:
                OnChar(hWnd,wParam);
                break;
        case WM_KEYDOWN:
                OnKeyDown( hWnd, wParam );
                break;
        case WM_KEYUP:
                OnKeyUp( hWnd, wParam );
                break;
        case WM_LBUTTONDOWN://鼠标左点击
                InvalidateRect(hWnd,NULL,TRUE);//将窗口声明为需要重绘
                break;
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);//处理大小写
                DispatchMessage(&nMsg);
        }
        return 0;
}

3.鼠标消息

3.1 基本鼠标消息
WM_LBUTTONDOWN - 鼠标左键按下
WM_LBUTTONUP - 鼠标左键抬起
WM_RBUTTONDOWN - 鼠标右键按下
WM_RBUTTONUP - 鼠标右键抬起
WM_MOUSEMOVE - 鼠标移动消息
3.2 双击消息
WM_LBUTTONDBLCLK - 鼠标左键双击
WM_RBUTTONDBLCLK - 鼠标右键双击
3.3 滚轮消息
WM_MOUSEWHEEL - 鼠标滚轮消息

3.4鼠标消息总结

3.4.1基本鼠标消息
3.4.1.1消息参数
WPARAM - 其他按键的状态,例如Ctrl/Shift等
LPARAM - 鼠标的位置,窗口客户区坐标系。
LOWORD X坐标位置
HIWORD Y坐标位置
3.4.1.2鼠标消息使用
一般情况鼠标按下/抬起成对出现。在鼠标移动过程中,会根据移动速度产生一系列的WM_MOUSEMOVE消息。

3.4.2双击鼠标消息
3.4.2.1消息参数
WPARAM - 其他按键的状态,例如Ctrl/Shift等
LPARAM - 鼠标的位置,窗口客户区坐标系。
LOWORD X坐标位置
HIWORD Y坐标位置
3.4.2.2使用时需要在注册窗口类的时候添加CS_DBLCLKS 风格。
3.4.2.3消息产生顺序
以WM_LBUTTONDBLCLK为例:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP

3.4.3鼠标滚轮 WM_MOUSEWHEEL
3.4.3.1消息参数
WPARAM:
        LOWORD - 其他按键的状态
        HIWORD - 滚轮的偏移量,是120的倍数,通过正负值表示表示滚动方向。
        正:向前滚动
        负:向后滚动
LPARAM:鼠标当前的位置,【屏幕】坐标系
        LOWORD - X坐标
        HIWORD - Y坐标
3.4.3.2使用:通过偏移量,获取滚动的方向和倍数。

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;

void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
        char szText = {0};
        sprintf(szText,"WM_LBUTTONDOWN:按键状态=%08X,X=%d,Y=%d\n",wParam,LOWORD(lParam),HIWORD(lParam));
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}
void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
        char szText = {0};
        sprintf(szText,"WM_LBUTTONUP:按键状态=%08X,X=%d,Y=%d\n",wParam,LOWORD(lParam),HIWORD(lParam));
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}

void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
        char szText = {0};
        sprintf(szText,"WM_MOUSEMOVE:x=%d,y=%d\n",LOWORD(lParam),HIWORD(lParam));
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_MOUSEMOVE:
                OnMouseMove(hWnd,wParam,lParam);
                break;
        case WM_LBUTTONDOWN:
                OnLButtonDown(hWnd,wParam,lParam);
                break;
        case WM_LBUTTONUP:
                OnLButtonUp(hWnd,wParam,lParam);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

fishc跟着鼠标移动而移动
#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_xPos = 100;
int g_yPos = 100;

void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
        g_xPos = LOWORD(lParam);
        g_yPos = HIWORD(lParam);
        InvalidateRect(hWnd,NULL,TRUE);
}

void OnPaint(HWND hWnd)
{
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd,&ps);
        TextOut(hdc,g_xPos,g_yPos,"fishc",5);
        EndPaint(hWnd,&ps);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_PAINT:
                OnPaint(hWnd);
                break;
        case WM_MOUSEMOVE:
                OnMouseMove(hWnd,wParam,lParam);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;

void OnMouseWheel(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
        short nDelta = HIWORD(wParam);//偏移量
        char szText = {0};
        sprintf(szText,"偏移量=%d\n,x=%d,y=%d\n",nDelta,LOWORD(lParam),HIWORD(lParam));
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_MOUSEWHEEL:
                OnMouseWheel(hWnd,wParam,lParam);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

4.定时器消息
可以在程序中设置定时器,当到达时间间隔时,定时器会向程序发送一个WM_TIMER消息。
定时器的精度是毫秒,但是准确度很低。例如设置时间间隔为1000ms,但是会在非1000毫秒到达。

4.1消息的参数
WPARAM - 定时器ID
LPARAM - 定时器处理函数的指针

4.2定时器使用
4.2.1 创建定时器
UINT_PTR SetTimer(
HWND hWnd,//定时器窗口句柄
UINT_PTR nIDEvent, //定时器ID
UINT uElapse,//时间间隔
TIMERPROC lpTimerFunc //定时器处理函数指针
);创建成功,返回非0。
使用窗口处理函数,做为定时器处理函数,lpTimerFunc为NULL
使用定时器处理函数处理定时器消息。

4.2.2 消息处理WM_TIMER
4.2.3 关闭定时器
BOOL KillTimer(
        HWND hWnd,//定时器窗口句柄
        UINT_PTR uIDEvent //定时器ID
);

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;

void OnTimer(HWND hWnd,WPARAM wParam)
{
        char szText = {0};
        sprintf(szText,"定时器:%d\n",wParam);
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}

//自定义(定时器处理函数)处理WM_TIMER消息
VOID CALLBACK TimerProc(HWND hWnd,UINT msgID,UINT timeID,DWORD dwTimer)
{
        char szText = {0};
        sprintf(szText,"定时器处理函数处理:%d\n",timeID);
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_LBUTTONDOWN:
                KillTimer(hWnd,1);//鼠标左键关闭定时器1
                break;
        case WM_TIMER:
                OnTimer(hWnd,wParam);
                break;
        case WM_CREATE:
                SetTimer(hWnd,1,1000,NULL);
                SetTimer(hWnd,2,2000,TimerProc);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}


5.菜单的使用
5.1菜单的分类
5.1.1 窗口的顶层菜单
5.1.2 弹出式菜单(鼠标右键,下拉菜单)
5.1.3 系统菜单(标题栏右键)
HMENU类型表示菜单,菜单每一项有相应的ID。

5.2窗口的顶层菜单
5.2.1创建菜单
HMENU CreateMenu(VOID); //创建成功返回菜单句柄
增加菜单项
BOOL AppendMenu(
        HMENU hMenu, //菜单句柄
        UINT uFlags, //菜单项风格
        UINT_PTR uIDNewItem, //菜单项ID或下拉菜单句柄
        LPCTSTR lpNewItem //菜单项的名称
);
uFlags:
MF_POPUP - 具有这种风格的菜单项,被点击后弹出下拉菜单,uIDNewItem参数必须填写下拉菜单的句柄。
MF_SEPARATOR - 具有这种风格的菜单项,为分隔线
MF_STRING - 具有这种风格的菜单项,被点击后能够发出消息(WM_COMMAND),uIDNewItem参数必须填写菜单项ID

设置到窗口
BOOL SetMenu(
        HWND hWnd,//窗口句柄
        HMENU hMenu //菜单句柄
);

5.3菜单命令处理
5.3.1WM_COMMAND 消息
WPARAM:
        HIWORD - 对于菜单为0
        LOWORD - 菜单项的ID
LPARAM - 对于菜单为NULL

5.3.2命令处理过程
获取WPARAM菜单ID,根据ID处理。

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();

        HMENU hFile = CreatePopupMenu();
        AppendMenu(hFile, MF_STRING | MF_CHECKED, 1003, "新建");
        AppendMenu(hFile, MF_SEPARATOR, 0, "");
        AppendMenu(hFile, MF_STRING | MF_MENUBARBREAK, 1004, "退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp, MF_STRING | MF_DISABLED, 1005, "关于");

        AppendMenu(hMain, MF_POPUP, (UINT)hFile, "文件");
        AppendMenu(hMain, MF_POPUP, (UINT)hHelp, "帮助");
        SetMenu(hWnd, hMain);

}

void OnCommand(HWND hWnd, WPARAM wParam)
{
        switch (LOWORD(wParam))
        {
        case 1003:
                MessageBox(hWnd, "新建被点击", "信息", MB_OK);
                break;
        case 1004:
                MessageBox(hWnd, "退出被点击", "信息", MB_OK);
                break;
        case 1005:
                MessageBox(hWnd, "关于被点击", "信息", MB_OK);
                break;
        }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_COMMAND:
                OnCommand(hWnd, wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hInstance, pszText);
        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg = { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

5.3.3菜单项的状态
在增加菜单项可以设置菜单项的状态。
可以使用菜单API修改状态
CheckMenuItem
//更改菜单项 勾选/非勾选 状态
DWORD CheckMenuItem(
HMENU hmenu,      // 菜单句柄
UINT uIDCheckItem,// 菜单项ID或菜单项位置(索引)
UINT uCheck         // 具体状态
);
uCheck:
    MF_BYCOMMAND - 指明uIDCheckItem参数必须填写菜单项ID
    MF_BYPOSITION - 指明uIDCheckItem参数必须填写菜单项位置
    MF_CHECKED - 勾选
    MF_UNCHECKED - 非勾选
EnableMenuItem
//更改菜单项 可用/不可用 状态
BOOL EnableMenuItem(
HMENU hMenu,         // 菜单句柄
UINT uIDEnableItem,// 菜单项ID或菜单项位置(索引)
UINT uEnable         // 具体状态 / 还指明第二个参数填的是什么
);


函数使用时,需要通过设置MF_BYPOSITION或者MF_BYCOMMAND,确定使用菜单索引或者菜单ID。


#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_state = 0;//标志量
HMENU hFile;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();
       
        hFile = CreatePopupMenu();
        AppendMenu(hFile,MF_STRING|MF_CHECKED,1003,"新建");
        AppendMenu(hFile,MF_SEPARATOR,0,"");
        AppendMenu(hFile,MF_STRING|MF_MENUBARBREAK,1004,"退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp,MF_STRING|MF_DISABLED,1005,"关于");

        AppendMenu(hMain,MF_POPUP,(UINT)hFile,"文件");
        AppendMenu(hMain,MF_POPUP,(UINT)hHelp,"帮助");
        SetMenu(hWnd,hMain);

}

void OnCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1003:
                if(g_state == 0)
                {
                        CheckMenuItem(hFile,1003,MF_BYCOMMAND|MF_UNCHECKED);
                }
                else
                {
                        CheckMenuItem(hFile,0,MF_BYPOSITION|MF_CHECKED);
                }
                g_state = !g_state;
                break;
        case 1004:
                MessageBox(hWnd,"退出被点击","信息",MB_OK);
                break;
        case 1005:
                MessageBox(hWnd,"关于被点击","信息",MB_OK);
                break;
        }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_COMMAND:
                OnCommand(hWnd,wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

5.3.4WM_INITMENUPOPUP
在菜单被激活但是未显示,窗口会收到这个消息
WPARAM – 即将显示的菜单句柄
LPARAM - LOWORD 是被点击的菜单项索引
HIWORD 是窗口菜单标识

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_state = 0;//标志量
HMENU hFile;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();
       
        hFile = CreatePopupMenu();
        AppendMenu(hFile,MF_STRING|MF_CHECKED,1003,"新建");
        AppendMenu(hFile,MF_SEPARATOR,0,"");
        AppendMenu(hFile,MF_STRING|MF_MENUBARBREAK,1004,"退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp,MF_STRING|MF_DISABLED,1005,"关于");

        AppendMenu(hMain,MF_POPUP,(UINT)hFile,"文件");
        AppendMenu(hMain,MF_POPUP,(UINT)hHelp,"帮助");
        SetMenu(hWnd,hMain);

}

void OnCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1003:
                if(g_state == 0)
                {
                        CheckMenuItem(hFile,1003,MF_BYCOMMAND|MF_UNCHECKED);
                }
                else
                {
                        CheckMenuItem(hFile,0,MF_BYPOSITION|MF_CHECKED);
                }
                g_state = !g_state;
                break;
        case 1004:
                MessageBox(hWnd,"退出被点击","信息",MB_OK);
                break;
        case 1005:
                MessageBox(hWnd,"关于被点击","信息",MB_OK);
                break;
        }
}

void OnInitMenuPopup(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
        char szText = {0};
        sprintf(szText,"即将显示的菜单句柄:%d,被点击顶层菜单项位置:%d,即将显示的菜单是否为窗口菜单:%d\n",wParam,LOWORD(lParam),HIWORD(lParam));
        WriteConsole(g_hOutout,szText,strlen(szText),NULL,NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_INITMENUPOPUP:
                OnInitMenuPopup(hWnd,wParam,lParam);
                break;
        case WM_COMMAND:
                OnCommand(hWnd,wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

5.4系统菜单的使用(了解)
5.4.1 系统菜单的获取
HMENU GetSystemMenu(
        HWND hWnd,//窗口句柄
        BOOL bRevert //重置选项
); 返回获取到的系统菜单句柄
bRevert:TRUE - 删除旧菜单,恢复到默认的系统菜单
                FALSE - 返回当前的系统菜单句柄。

5.4.2 系统菜单的修改
AppendMenu函数
DeleteMenu函数

5.4.3 系统菜单命令响应
通过WM_SYSCOMMAND响应菜单命令。
WPARAM的LOWORD是命令ID

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_state = 0;//标志量
HMENU hFile;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();
       
        hFile = CreatePopupMenu();
        AppendMenu(hFile,MF_STRING|MF_CHECKED,1003,"新建");
        AppendMenu(hFile,MF_SEPARATOR,0,"");
        AppendMenu(hFile,MF_STRING|MF_MENUBARBREAK,1004,"退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp,MF_STRING|MF_DISABLED,1005,"关于");

        AppendMenu(hMain,MF_POPUP,(UINT)hFile,"文件");
        AppendMenu(hMain,MF_POPUP,(UINT)hHelp,"帮助");
        SetMenu(hWnd,hMain);
        HMENU hSys = GetSystemMenu(hWnd,FALSE);
        for(int i=0;i<6;i++)
        {
                DeleteMenu(hSys,0,MF_BYPOSITION);
        }
        AppendMenu(hSys,MF_SEPARATOR,0,"");
        AppendMenu(hSys,MF_STRING,1001,"我的菜单项");

}

void OnCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1003:
                if(g_state == 0)
                {
                        CheckMenuItem(hFile,1003,MF_BYCOMMAND|MF_UNCHECKED);
                }
                else
                {
                        CheckMenuItem(hFile,0,MF_BYPOSITION|MF_CHECKED);
                }
                g_state = !g_state;
                break;
        case 1004:
                MessageBox(hWnd,"退出被点击","信息",MB_OK);
                break;
        case 1005:
                MessageBox(hWnd,"关于被点击","信息",MB_OK);
                break;
        }
}

void OnSysCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1001:
                MessageBox(hWnd,"我的菜单项被点击","信息",MB_OK);
                break;
        }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_SYSCOMMAND:
                OnSysCommand(hWnd,wParam);
                break;
        case WM_COMMAND:
                OnCommand(hWnd,wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

5.5右键菜单 Context Menu的使用
5.5.1 创建菜单
右键菜单是一个弹出式菜单,使用CreatePopupMenu创建。

5.5.2 显示菜单
BOOL TrackPopupMenu(
        HMENU hMenu, //菜单句柄
        UINT uFlags, //显示方式
        int x,//水平位置,屏幕坐标系
        int y,//垂直位置,屏幕坐标系
        int nReserved, //保留,必须0
       HWND hWnd, //处理菜单消息的窗口句柄
        CONST RECT *prcRect //NULL,忽略
); TrackPopupMenu是阻塞函数

5.5.3 命令处理
WM_COMMAND,与窗口菜单一致
如果TrackPopupMenu设置了TPM_RETURNCMD选项,那么点击的菜单项ID通过函数的返回值获取。

5.5.4 菜单项的状态
WM_INITMENUPOPUP,按照弹出菜单处理

5.5.5菜单处理位置
5.5.5.1 鼠标右键抬起
WM_RBUTTONUP 鼠标右键消息窗口坐标系坐标,要使用需要转换成屏幕坐标系
ClientToScreen
ScreenToClient

//将 客户区坐标系下的坐标 转换为 屏幕坐标系下的坐标
BOOL ClientToScreen(
HWND hWnd,       // 窗口句柄
LPPOINT lpPoint//
                输入:客户区坐标系下的一个坐标
                输出 : 转换后屏幕坐标系下的坐标
);

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_state = 0;//标志量
HMENU hFile;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();
       
        hFile = CreatePopupMenu();
        AppendMenu(hFile,MF_STRING|MF_CHECKED,1003,"新建");
        AppendMenu(hFile,MF_SEPARATOR,0,"");
        AppendMenu(hFile,MF_STRING|MF_MENUBARBREAK,1004,"退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp,MF_STRING|MF_DISABLED,1005,"关于");

        AppendMenu(hMain,MF_POPUP,(UINT)hFile,"文件");
        AppendMenu(hMain,MF_POPUP,(UINT)hHelp,"帮助");
        SetMenu(hWnd,hMain);
}

void OnCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1003:
                if(g_state == 0)
                {
                        CheckMenuItem(hFile,1003,MF_BYCOMMAND|MF_UNCHECKED);
                }
                else
                {
                        CheckMenuItem(hFile,0,MF_BYPOSITION|MF_CHECKED);
                }
                g_state = !g_state;
                break;
        case 1004:
                MessageBox(hWnd,"退出被点击","信息",MB_OK);
                break;
        case 1005:
                MessageBox(hWnd,"关于被点击","信息",MB_OK);
                break;
        case 1010:
                MessageBox(hWnd,"右键新建被点击","信息",MB_OK);
                break;
        case 1011:
                MessageBox(hWnd,"右键退出被点击","信息",MB_OK);
                break;
        }
}


void OnRButtonUp(HWND hWnd,LPARAM lParam)
{
        HMENU hPopup = CreatePopupMenu();
        AppendMenu(hPopup,MF_STRING,1010,"新建");
        AppendMenu(hPopup,MF_SEPARATOR,0,"");
        AppendMenu(hPopup,MF_STRING,1011,"退出");
        POINT pt = {0};
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        ClientToScreen(hWnd,&pt);
        TrackPopupMenu(hPopup,TPM_CENTERALIGN|TPM_VCENTERALIGN,pt.x,pt.y,0,hWnd,NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
       
        case WM_RBUTTONUP:
                OnRButtonUp(hWnd,lParam);
                break;
        case WM_COMMAND:
                OnCommand(hWnd,wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_state = 0;//标志量
HMENU hFile;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();
       
        hFile = CreatePopupMenu();
        AppendMenu(hFile,MF_STRING|MF_CHECKED,1003,"新建");
        AppendMenu(hFile,MF_SEPARATOR,0,"");
        AppendMenu(hFile,MF_STRING|MF_MENUBARBREAK,1004,"退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp,MF_STRING|MF_DISABLED,1005,"关于");

        AppendMenu(hMain,MF_POPUP,(UINT)hFile,"文件");
        AppendMenu(hMain,MF_POPUP,(UINT)hHelp,"帮助");
        SetMenu(hWnd,hMain);
}

void OnCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1003:
                if(g_state == 0)
                {
                        CheckMenuItem(hFile,1003,MF_BYCOMMAND|MF_UNCHECKED);
                }
                else
                {
                        CheckMenuItem(hFile,0,MF_BYPOSITION|MF_CHECKED);
                }
                g_state = !g_state;
                break;
        case 1004:
                MessageBox(hWnd,"退出被点击","信息",MB_OK);
                break;
        case 1005:
                MessageBox(hWnd,"关于被点击","信息",MB_OK);
                break;
        case 1010:
                MessageBox(hWnd,"右键新建被点击","信息",MB_OK);
                break;
        case 1011:
                MessageBox(hWnd,"右键退出被点击","信息",MB_OK);
                break;
        }
}


void OnRButtonUp(HWND hWnd,LPARAM lParam)
{
        HMENU hPopup = CreatePopupMenu();
        AppendMenu(hPopup,MF_STRING,1010,"新建");
        AppendMenu(hPopup,MF_SEPARATOR,0,"");
        AppendMenu(hPopup,MF_STRING,1011,"退出");
        POINT pt = {0};
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        ClientToScreen(hWnd,&pt);
        BOOL nRet = TrackPopupMenu(hPopup,TPM_CENTERALIGN|TPM_VCENTERALIGN|TPM_RETURNCMD,pt.x,pt.y,0,hWnd,NULL);
        switch(nRet)
        {
        case 1010:
                MessageBox(hWnd,"没发出COMMAND消息,右键新建被点击","信息",MB_OK);
                break;
        case 1011:
                MessageBox(hWnd,"没发出COMMAND消息,右键退出被点击","信息",MB_OK);
                break;
        }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
       
        case WM_RBUTTONUP:
                OnRButtonUp(hWnd,lParam);
                break;
        case WM_COMMAND:
                OnCommand(hWnd,wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

5.5.5.2 WM_CONTEXTMENU
WParam - 右键点击的窗口句柄
LPARAM - LOWORD X坐标,屏幕坐标系
HIWORD Y坐标,屏幕坐标系
WM_CONTEXTMENU消息是在WM_RBUTTONUP消息之后产生。

#include "stdafx.h"
#include "stdio.h"

HANDLE g_hOutout = 0;
int g_state = 0;//标志量
HMENU hFile;

void OnCreate(HWND hWnd)
{
        HMENU hMain = CreateMenu();
       
        hFile = CreatePopupMenu();
        AppendMenu(hFile,MF_STRING|MF_CHECKED,1003,"新建");
        AppendMenu(hFile,MF_SEPARATOR,0,"");
        AppendMenu(hFile,MF_STRING|MF_MENUBARBREAK,1004,"退出");

        HMENU hHelp = CreatePopupMenu();
        AppendMenu(hHelp,MF_STRING|MF_DISABLED,1005,"关于");

        AppendMenu(hMain,MF_POPUP,(UINT)hFile,"文件");
        AppendMenu(hMain,MF_POPUP,(UINT)hHelp,"帮助");
        SetMenu(hWnd,hMain);
}

void OnCommand(HWND hWnd,WPARAM wParam)
{
        switch(LOWORD(wParam))
        {
        case 1003:
                if(g_state == 0)
                {
                        CheckMenuItem(hFile,1003,MF_BYCOMMAND|MF_UNCHECKED);
                }
                else
                {
                        CheckMenuItem(hFile,0,MF_BYPOSITION|MF_CHECKED);
                }
                g_state = !g_state;
                break;
        case 1004:
                MessageBox(hWnd,"退出被点击","信息",MB_OK);
                break;
        case 1005:
                MessageBox(hWnd,"关于被点击","信息",MB_OK);
                break;
        case 1010:
                MessageBox(hWnd,"右键新建被点击","信息",MB_OK);
                break;
        case 1011:
                MessageBox(hWnd,"右键退出被点击","信息",MB_OK);
                break;
        }
}


void OnContextMenu(HWND hWnd,LPARAM lParam)
{
        HMENU hPopup = CreatePopupMenu();
        AppendMenu(hPopup,MF_STRING,1010,"新建");
        AppendMenu(hPopup,MF_SEPARATOR,0,"");
        AppendMenu(hPopup,MF_STRING,1011,"退出");
        POINT pt = {0};
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        BOOL nRet = TrackPopupMenu(hPopup,TPM_CENTERALIGN|TPM_VCENTERALIGN|TPM_RETURNCMD,pt.x,pt.y,0,hWnd,NULL);
        switch(nRet)
        {
        case 1010:
                MessageBox(hWnd,"没发出COMMAND消息,右键新建被点击","信息",MB_OK);
                break;
        case 1011:
                MessageBox(hWnd,"没发出COMMAND消息,右键退出被点击","信息",MB_OK);
                break;
        }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_CONTEXTMENU:
                OnContextMenu(hWnd,lParam);
                break;
        case WM_COMMAND:
                OnCommand(hWnd,wParam);
                break;
        case WM_CREATE:
                OnCreate(hWnd);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return DefWindowProc(hWnd, msgID, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
        AllocConsole();//创建一个控制台
        g_hOutout = GetStdHandle(STD_OUTPUT_HANDLE);
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(wc);
        wc.hIconSm = NULL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.hCursor = NULL;
        wc.hIcon = NULL;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = "fishc";
        wc.lpszMenuName = NULL;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&wc);
        char *pszText = "fishc";
        HWND hWnd = CreateWindow("fishc", "fishc",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,pszText);
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

下期预告:资源的使用,windows 绘图
题外话:好多东西我都没有细说,等你们问呢,win32好多都是实践和思考的东西,并不难,然而发了这么多,连回复都没有几个。。。

不定时停更

duhui 发表于 2018-1-18 20:51:28

用vs2015如何创建菜单资源,能把过程详细说一下吗?包括.rc文件的创建
页: [1]
查看完整版本: win32编程(003)——绘图消息,键鼠消息,定时器消息和菜单的使用