Windows SDK(四)鼠标和键盘消息处理

附加消息

lParam,32位大小,低16位LOWORD存储x坐标,高16位HIWORD存储y坐标,用于存储鼠标目标前的坐标信息

wParam,32位大小,用于存储系统键盘,鼠标输入的消息以及其他按键的状态,例如Ctrl/Shift等一般情况下鼠标按下和抬起成对出现,在鼠标移动的过程中,会根据移动速度产生一系列WM_MOUSEMOVE消息

键盘基础知识

顶级窗口:存在多个窗口时,在最上面的窗口

焦点:鼠标点击处。当鼠标点击窗口后,各种消息,如键盘消息只能发送给被点击的窗口

键盘消息的发送:键盘发送的消息只会发送到有焦点的窗口,点击键盘时,系统将对应的硬件扫描

码格式化成消息,发送到操作系统的消息队列中,由操作系统进行消息的初步存储,当应用完成上

一次消息的处理后,系统将会从消息队列中抽取消息分发到应用程序进行翻译处理

Windows有以下两类,共用四种我们可以处理的键盘按键消息:

1.系统按键:WM_SYSKEYDOWN,WM_SYSKEYUP。如ALT+TAB:页面切换,ALT+F4:关闭窗口,诸如此类ALT按键+,都属于系统按键

2.非系统按键:WM_KEYDOWN,WM_KEYUP

当我们使用系统按键(如ALT+x)时,应用程序会跳过安全消息,通过API:DefWindowProc进行转发,由Windows对其进行默认处理,此时应用程序不对此消息进行处理,因此Windows通常会认为系统按键发送的消息是发送给他自己的信息。

通常系统按键消息和非系统按键消息是同时触发的。我们可以通过API:GetMessageTime获取消息触发时间

虚拟键码:虚拟键码是Windows操作系统中用于标识键盘按键的一套编码系统, 每一个按键都有相应的wParam虚拟键码对应,用于表示按键动作。因此按键的附加消息是wParam

当按我们按下按键不放开时,系统认为有很多个按下去的消息发送给操作系统,但此时抬起来时,只会有一次抬起来的消息发送给操作系统

我们可以让鼠标或键盘的输入的状态作为参数结合,用于判断是否同时多种行为同时进行,这些参数如下显示,都是以MK_ 前缀:

MK_LBUTTON : 左键按下

MK_MBUTTON : 中键按下

MK_RBUTTON: 右键按下

MK_SHIFT : Shift键按下

MK_CONTROL : Ctrl键按下

键盘消息应用

键盘消息在窗口过程函数中进行处理,由message进行分发。因此我们在处理键盘消息时,需要在message下新增键盘消息选项,如WM_LBUTTONDOWN或WM_LBUTTONDBLCLK等等移植后,进行消息处理的代码书写

现在让我们开始应用:

如下是我们在窗口按下F1时的消息处理

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_KEYDOWN //用于接收按键按下的消息
    {
        switch(wParam) //判断按了哪个按键
        {
        case VK_F1: //按下F1按键的处理
        {
            MessageBox(NULL, L"F1", L"Msg", MB_OK);
            break;
        } 
        case 'B':
        case 'b': //当我们按下B或b时,执行相同的程序
        {
            Message(NULL, L"B/b", L"Msg", MB_OK);
            break;
        }
        dafault:
            break;
        }   
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

如下是我们按下两个按键的消息处理:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_KEYDOWN //用于接收按键按下的消息
    {
        switch(wParam) //判断按了哪个按键
        {
        case VK_F1: //按下F1按键的处理
        {
            SHORT bFlag = (GetKeyState(VK_SHIFT) & 0X8000);//该函数用来获取指定的虚拟键码的按键的状态,加上&0x8000,可以屏蔽其他无关状态
            if(bFlag <= 0) //此处表示同时按下shift键
            {
                MessageBox(NULL, L"SHIFT + F1", L"Msg", MB_OK);
            }
            else() //此处表示没有同时按下shift键
            {
                MessageBox(NULL, L"F1", L"Msg", MB_OK);
            }
            break;    
        }
        case 'B':
        case 'b': //当我们按下B或b时,执行相同的程序
        {
            Message(NULL, L"B/b", L"Msg", MB_OK);
            break;
        }
        dafault:
            break;
        }    
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

此时我们对上述代码进行进一步的优化,使得但我们按下一个按键时可以触发另一个按键的消息

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_KEYDOWN //用于接收按键按下的消息
    {
        switch(wParam) //判断按了哪个按键
        {
        case VK_F1: //按下F1按键的处理
        {
            SHORT bFlag = (GetKeyState(VK_SHIFT) & 0X8000);//该函数用来获取指定的虚拟键码的按键的状态,加上&0x8000,可以屏蔽其他无关状态
            if(bFlag <= 0) //此处表示同时按下shift键
            {
                MessageBox(NULL, L"SHIFT + F1", L"Msg", MB_OK);
            }
            else() //此处表示没有同时按下shift键
            {
                MessageBox(NULL, L"F1", L"Msg", MB_OK);
            }
            break;
        }    
        case VK_F2
        {
            //可以有以下两种情况,既可发送自定义消息也可发现正常按键消息
            //情况一:
            //SendMessage(hWnd, WM_KEYDOWN, VK_F1, NULL); 发送消息到某窗口,该函数不仅可以发送给自己的窗口,也可以是别的窗口,此处是发送给别的窗口。此时窗口按下F2,会在hWnd窗口中的WM_KEYDOWN消息中找到VK_F1的指令进行执行
            //情况二:
            SendMessage(hWnd, 0x12138, 9999, NULL); 按下F2,会在hWnd窗口中0x12138消息中找到9999的指令进行执行
            break;
        }
        case 'B':
        case 'b': //当我们按下B或b时,执行相同的程序
        {
            Message(NULL, L"B/b", L"Msg", MB_OK);
            break;
        }
        dafault:
            break;
        }
    }
    case 0x12138: //此处表示接收一个自定义消息
    {
        switch (wParam)
        {
        case 9999:
        {
            MessageBox(NULL, L"MyMsg", L"Msg", MB_OK);
            break;
        }
        }
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

查找指定类名和窗口名的顶级窗口句柄的函数FindWindow()。该函数有以下两种使用方式:

方式一,用类名寻找窗口句柄

方式二,用标题名寻找窗口句柄

鼠标基础知识

鼠标也是键盘的一种,比如鼠标左键按下与抬起,等同键盘按下与抬起

鼠标一般分为三种状态,三个按钮

三种状态:单击,双击,拖动

三个按钮:左键(LBUTTON),右键(RBUTTON),中键(MBUTTON)

左键具有的消息

WM_LBUTTONDOWM 点击鼠标产生的消息

WM_LBUTTONUP 抬起鼠标产生的消息

WM_LBUTTONDBLCLK 双击鼠标产生的消息,有的窗口不支持

右键具有的消息

WM_RBUTTONDOWM 点击鼠标

WM_RBUTTONUP 抬起鼠标

WM_RBUTTONDBLCLK 双击,有时窗口不支持

中键具有的消息

WM_MBUTTONDOWM 点击鼠标

WM_MBUTTONUP 抬起鼠标

WM_MBUTTONDBLCLK 双击,有时窗口不支持

WM_MOUSEWHEEL  鼠标滚轮消息

直接通过messsage进行分发的消息一般是WM开头,也叫顶层消息,如上诸多消息都是顶层消息

鼠标具有lParam和wParam两种附加消息,我们可以通过wParam判断鼠标和键盘按键是否同时按下。当我们设置了WM_LBUTTONDOWM 左键按下时的消息类型时,可以在代码中通过wParam & MK_RBUTTON,判断左键按下的同时,右键是否同时按下

如下是能够这样判断的键的种类:

MK_LBUTTON

MK_RBUTTON

MK_MBUTTON

MK_SHIFT

MK_CONTROL

鼠标消息简单应用

如下是鼠标的简单应用,点击鼠标弹出窗口

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN: //用于接收系统鼠标左键按下的消息
    {
        MessageBox(NULL, L"LBUTTON", L"MSG", MB_OK);
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

鼠标具有lParam和wParam两种附加消息,我们可以通过wParam判断组合按键是否同时按下。比如:当我们设置了WM_LBUTTONDOWM 左键按下时的消息类型时,可以在代码中通过wParam & MK_RBUTTON,判断左键按下的同时,右键是否同时按下

如下是能够这样判断的键的种类:

MK_LBUTTON

MK_RBUTTON

MK_MBUTTON

MK_SHIFT

MK_CONTROL

此时我们针对鼠标的组合按键进行一个代码的演示

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN: //用于接收系统鼠标左键按下的消息
    {
        if(wParam & MK_SHIFT) //判断是否左键和shift同时按下
        {
            MessageBox(NULL, L"MK_SHIFT + LBUTTON", L"MSG", MB_OK);
            break;
        }
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

鼠标信息复杂应用

鼠标点击画点

鼠标点击处,出现点

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN: //用于接收系统鼠标左键按下的消息
    {
       int nPosX = LOWORD(lParam); //IParam高低位存储的是点的yx坐标
       int nPosY = HIWORD(lParam); //获取鼠标点击处的xy坐标
       HWND hMyHWnd = FindWindow(NULL, L"GrkDemo");//获取指定类名和窗口名的顶级窗口句柄。
       HDC hDC = GetDC(hMyHWnd); //获取该窗口DC的句柄
       HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建一个画笔
       SelectObject(hDC, hPen); //选择画笔
       POINT pi = { 0 };//画笔位置初始化
       MoveToEx(hDC, nPosX, nPosY, &pi); //设置起点坐标
       LineTo(hDC, nPosX, nPosY);  //设置终点坐标,此处原地画一个点
       ReleaseDC(hMyHWnd, hDC);  //释放DC
       break
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

鼠标点击划线

鼠标点击某处,再移动到其他处,松开鼠标,出现一条线

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN: //用于接收系统鼠标消息,此处左键按下,保存直线起始的点的坐标
    {
       Pos[0].x = LOWORD(lParam); //保存直线起始点的x坐标
       Pos[0].y = HIWORD(lParam); //保存直线起始点的y坐标
       break;
    }
    case WM_LBUTTONUP: //鼠标抬起时绘制,保存直线结束的点
    {
       Pos[1].x = LOWORD(lParam); //保存直线结束的点x坐标
       Pos[1].y = HIWORD(lParam); //保存直线结束的点y坐标
       HWND hMyHWnd = FindWindow(NULL, L"GrkDemo"); //获取指定窗口名的顶级窗口的句柄。
       HDC hDC = GetDC(hMyHWnd); //获取该窗口的DC句柄
       HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建画笔
       SelectObject(hDC, hPen); //选择画笔
       POINT pi = { 0 }; //画笔位置初始化
       MoveToEx(hDC, Pos[0].x, Pos[0].y, &pi); //画笔移至起始位置
       LineTo(hDC, Pos[1].x, Pos[1].y); //画笔移至结束位置
       ReleaseDC(hMyHWnd, hDC);
       break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

鼠标点击画矩形

鼠标点击某处,再移动到其他点,松开鼠标,出现一个矩形

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN: //用于接收系统鼠标消息,此处左键按下,保存直线起始的点的坐标
    {
       Pos[0].x = LOWORD(lParam); //保存直线起始点的x坐标
       Pos[0].y  = HIWORD(lParam); //保存直线起始点的y坐标
       break;
    }
    case WM_LBUTTONUP: //鼠标抬起时绘制,保存直线结束的点
    {
       Pos[1].x = LOWORD(lParam); //保存直线结束的点x坐标
       Pos[1].y = HIWORD(lParam); //保存直线结束的点y坐标
       HWND hMyHWnd = FindWindow(NULL, L"GrkDemo"); //获取指定窗口名的顶级窗口的句柄。
       HDC hDC = GetDC(hMyHWnd); //获取该窗口的DC句柄
       HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建画笔
       SelectObject(hDC, hPen); //选择画笔
       Rectangle(hDC, Pos[0].x, Pos[0].y, Pos[1].x, Pos[1].y);
       ReleaseDC(hMyHWnd, hDC);
       break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

鼠标点击画圆

鼠标点击某处,再移动到其他点,松开鼠标,出现一个圆

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN: //用于接收系统鼠标消息,此处左键按下,保存直线起始的点的坐标
    {
       Pos[0].x = LOWORD(lParam); //保存直线起始点的x坐标
       Pos[0].y  = HIWORD(lParam); //保存直线起始点的y坐标
       break;
    }
    case WM_LBUTTONUP: //鼠标抬起时绘制,保存直线结束的点
    {
       Pos[1].x = LOWORD(lParam); //保存直线结束的点x坐标
       Pos[1].y = HIWORD(lParam); //保存直线结束的点y坐标
       HWND hMyHWnd = FindWindow(NULL, L"GrkDemo"); //获取指定窗口名的顶级窗口的句柄。
       HDC hDC = GetDC(hMyHWnd); //获取该窗口的DC句柄
       HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建画笔
       SelectObject(hDC, hPen); //选择画笔
       Arc(hDC, Pos[0].x, Pos[0].y, Pos[1].x, Pos[1].y, 350, 350, 350, 350); 绘制圆形
       ReleaseDC(hMyHWnd, hDC);
       break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

鼠标点击移动画线

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_MOUSEMOVE: //用于接收鼠标滑动的信息
    {
       if(wParam & WM_LBUTTONDOWN) //点击鼠标左键加移动处理的信息
       {
           int nPosX = LOWORD(lParam); //IParam高低位存储的是点的yx坐标
           int nPosY = HIWORD(lParam); //获取鼠标点击处的xy坐标
           HWND hMyHWnd = FindWindow(NULL, L"GrkDemo");//获取指定类名和窗口名的顶级窗口句柄。
           HDC hDC = GetDC(hMyHWnd); //获取该窗口DC的句柄
           HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建一个画笔
           SelectObject(hDC, hPen); //选择画笔
           POINT pi = { 0 };//画笔位置初始化
           MoveToEx(hDC, nPosX, nPosY, &pi); //设置起点坐标
           LineTo(hDC, nPosX, nPosY);  //设置终点坐标,此处原地画一个点
           ReleaseDC(hMyHWnd, hDC);  //释放DC
           break
       }
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

按钮绘制

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps; //PAINTSTRUCT为绘图上下文的结构体,此处创建绘图设备上下文
        SetBkMode(hdc, TRANSPARENT); //设置背景色
        HDC hdc = BeginPaint(hWnd, &ps);//获取绘图上下文DC的句柄
        HFONT hFont = CreateFont(20, 10, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, L"宋体"); //创建一个高级字体
        SelectObject(hdc, hFont); //选择应用该字体,将该字体投放到hdc
        RECT rect; //创建矩形对象
        SetRect(&rect, 30, 50, 400, 200);//设置指定矩形的坐标位置
        SetTextColor(hdc, RGB(0, 0, 255)); //设置字体颜色
        DrawText(hdc, L"蓝色", -1, &rect, DT_NOCLIP); //输出字体
        SetRect(&rect, 30, 100, 400, 200);
        SetTextColor(hdc, RGB(255, 0, 0));
        DrawText(hdc, L"红色", -1, &rect, DT_NOCLIP);//再次输出字体
        HBRUSH hSolidBrushBlue = CreateSolidBrush(RGB(0, 0, 255));//创建实心画刷
        SelectObject(hdc, hSolidBrushBlue); //选择画刷
        Rectangle(hdc, 90, 50, 120, 80); 
        HBRUSH hSolidBrushRed = CreateSolidBrush(RGB(255, 0, 0));
        SelectObject(hdc, hSolidBrushRed);
        Rectangle(hdc, 90, 100, 120, 130);
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

按钮应用

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps; //PAINTSTRUCT为绘图上下文的结构体,此处创建绘图设备上下文
        SetBkMode(hdc, TRANSPARENT); //设置背景色
        HDC hdc = BeginPaint(hWnd, &ps);//获取绘图上下文DC的句柄
        HFONT hFont = CreateFont(20, 10, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, L"宋体"); //创建一个高级字体
        SelectObject(hdc, hFont); //选择应用该字体,将该字体投放到hdc
        RECT rect; //创建矩形对象
        SetRect(&rect, 30, 50, 400, 200);//设置指定矩形的坐标位置
        SetTextColor(hdc, RGB(0, 0, 255)); //设置字体颜色
        DrawText(hdc, L"蓝色", -1, &rect, DT_NOCLIP); //输出字体
        SetRect(&rect, 30, 100, 400, 200);
        SetTextColor(hdc, RGB(255, 0, 0));
        DrawText(hdc, L"红色", -1, &rect, DT_NOCLIP);//再次输出字体
        HBRUSH hSolidBrushBlue = CreateSolidBrush(RGB(0, 0, 255));//创建实心画刷
        SelectObject(hdc, hSolidBrushBlue); //选择画刷
        Rectangle(hdc, 90, 50, 120, 80); 
        HBRUSH hSolidBrushRed = CreateSolidBrush(RGB(255, 0, 0));
        SelectObject(hdc, hSolidBrushRed);
        Rectangle(hdc, 90, 100, 120, 130);
        EndPaint(hWnd, &ps);
        break;
    }
	case WM_LBUTTONDOWN: //此处为点击按钮的处理
	{
		int nPosX = LOWORD(lParam);
		int nPosY = HIWORD(lParam); //保存点击时鼠标的坐标
		if (nPosX > 90 && nPosX << 120 && nPosY > 50 && nPosY < 80)
		{
			MessageBox(NULL, L"蓝色", L"Msg", MB_OK);
		}
		if (nPosX > 90 && nPosX << 120 && nPosY > 100 && nPosY < 130)
		{
			MessageBox(NULL, L"红色", L"Msg", MB_OK);
		}
		break;
	}
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

作业

自制简易画图工具:
01.画笔画刷可以选择颜色(三原色)
02.可以选择画笔画刷的类型
    2.1 包括画笔的各种实线虚线实现
    2.2 包括实心和阴影画刷的各种形式
03.实现各种工具(直线,曲线,自由画笔,圆形,矩形)

POINT Pos[5] = { 0 };
int Flag = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	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);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
	}
	break;
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);
		// TODO: 在此处添加使用 hdc 的任何绘图代码...
		SetBkMode(hdc, TRANSPARENT);
		HFONT hFont = CreateFont(15, 8, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, L"宋体");
		SelectObject(hdc, hFont);
		RECT rect1;
		SetTextColor(hdc, RGB(255, 0, 0));
		SetRect(&rect1, 50, 50, 100, 100);
		DrawText(hdc, L"红直笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 290, 50, 100, 100);
		DrawText(hdc, L"红矩刷", -1, &rect1, DT_NOCLIP);
		SetTextColor(hdc, RGB(0, 255, 0));
		SetRect(&rect1, 130, 50, 100, 100);
		DrawText(hdc, L"绿直笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 370, 50, 100, 100);
		DrawText(hdc, L"绿矩刷", -1, &rect1, DT_NOCLIP);
		SetTextColor(hdc, RGB(0, 0, 255));
		SetRect(&rect1, 210, 50, 100, 100);
		DrawText(hdc, L"蓝直笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 450, 50, 100, 100);
		DrawText(hdc, L"蓝矩刷", -1, &rect1, DT_NOCLIP);
		SetTextColor(hdc, RGB(0, 0, 0));
		SetRect(&rect1, 50, 150, 100, 100);
		DrawText(hdc, L"红曲笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 130, 150, 100, 100);
		DrawText(hdc, L"绿曲笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 210, 150, 100, 100);
		DrawText(hdc, L"蓝曲笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 600, 50, 100, 100);
		DrawText(hdc, L"红自由笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 680, 50, 100, 100);
		DrawText(hdc, L"绿自由笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 760, 50, 100, 100);
		DrawText(hdc, L"蓝自由笔", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 840, 50, 100, 100);
		DrawText(hdc, L"红圆刷", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 920, 50, 100, 100);
		DrawText(hdc, L"绿圆刷", -1, &rect1, DT_NOCLIP);
		SetRect(&rect1, 1000, 50, 100, 100);
		DrawText(hdc, L"蓝圆刷", -1, &rect1, DT_NOCLIP);
		HBRUSH hRedSoidBrush = CreateSolidBrush(RGB(255, 0, 0));
		SelectObject(hdc, hRedSoidBrush);
		Rectangle(hdc, 60, 70, 90, 100); //红直笔
		Rectangle(hdc, 300, 70, 330, 100);//红矩刷
		Rectangle(hdc, 60, 170, 90, 200);//红曲笔
		Rectangle(hdc, 610, 70, 640, 100);//红自由笔
		Rectangle(hdc, 850, 70, 880, 100);//红圆刷
		HBRUSH hGreenSoidBrush = CreateSolidBrush(RGB(0, 255, 0));
		SelectObject(hdc, hGreenSoidBrush);
		Rectangle(hdc, 140, 70, 170, 100);//绿直笔
		Rectangle(hdc, 380, 70, 410, 100);//绿矩刷
		Rectangle(hdc, 140, 170, 170, 200);//绿曲笔
		Rectangle(hdc, 690, 70, 720, 100);//绿自由笔
		Rectangle(hdc, 930, 70, 960, 100);//绿圆刷
		HBRUSH hBlueSoidBrush = CreateSolidBrush(RGB(0, 0, 255));
		SelectObject(hdc, hBlueSoidBrush);
		Rectangle(hdc, 220, 70, 250, 100);//蓝直笔
		Rectangle(hdc, 460, 70, 490, 100);//蓝圆刷
		Rectangle(hdc, 220, 170, 250, 200);//蓝曲笔
		Rectangle(hdc, 770, 70, 800, 100);//蓝自由笔
		Rectangle(hdc, 1010, 70, 1040, 100);//蓝圆刷
		EndPaint(hWnd, &ps);
	}
	break;
	case WM_LBUTTONDOWN:
	{
		HDC hdc = GetDC(hWnd);
		Pos[0].x = LOWORD(lParam);
		Pos[0].y = HIWORD(lParam);
		if (Pos[0].x > 60 && Pos[0].x < 90 && Pos[0].y > 70 && Pos[0].y < 100)
		{
			Flag = 1;//红直笔
		}
		else if (Pos[0].x > 300 && Pos[0].x < 330 && Pos[0].y > 70 && Pos[0].y < 100)
		{
			Flag = 2;//红矩刷
		}
		else if (Pos[0].x > 850 && Pos[0].x < 880 && Pos[0].y > 70 && Pos[0].y < 100)
		{
			Flag = 3;//红圆刷
		}
		else if (Pos[0].x > 610 && Pos[0].x < 640 && Pos[0].y > 70 && Pos[0].y < 100)
		{
			Flag = 4;//红自由笔
		}
	}
	break;
	case WM_LBUTTONUP:
	{
		HDC hdc = GetDC(hWnd);
		Pos[1].x = LOWORD(lParam);
		Pos[1].y = HIWORD(lParam);
		if (Flag == 1)
		{
			HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建红色画笔
			SelectObject(hdc, hPen);
			POINT pi = { 0 };
			MoveToEx(hdc, Pos[0].x, Pos[0].y, &pi);
			LineTo(hdc, Pos[1].x, Pos[1].y);
			ReleaseDC(hWnd, hdc);
		}
		if (Flag == 2)
		{
			HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0)); //创建红色画刷
			SelectObject(hdc, hBrush); 
			POINT pi = { 0 };
			Rectangle(hdc, Pos[0].x, Pos[0].y, Pos[1].x, Pos[1].y);
			ReleaseDC(hWnd, hdc);
		}
		ReleaseDC(hWnd, hdc);
	}
	break;
	case WM_MOUSEMOVE:
	{
		if (wParam & WM_LBUTTONDOWN && Flag == 4)
		{

			Pos[1].x = LOWORD(lParam);
			Pos[1].y = HIWORD(lParam);
			HDC hdc = GetDC(hWnd);
			HPEN hPen = CreatePen(PS_SOLID, 8, RGB(255, 0, 0)); //创建红色画笔
			SelectObject(hdc, hPen);
			POINT pi = { 0 };
			MoveToEx(hdc, Pos[1].x, Pos[1].y, &pi);
			LineTo(hdc, Pos[1].x, Pos[1].y);
			ReleaseDC(hWnd, hdc);
		}
	}
	break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

由于本人时间有限,因此只实现了红色直线画笔自由笔以及红色矩形画刷。其他两种颜色的画笔画刷只需要改变其颜色即可,其他代码一致。

因本人能力有限,圆形画刷以及曲线画笔并没有实现成功。望看客给予帮助指导

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值