Windows API窗口绘图程序设计
Windows API窗口绘图程序设计
设计一个简单的Windows 窗口程序,在程序窗口内任意位置按下鼠标左键,可绘制范围在10-100之间随机大小的正方形。并且显示的正方形用红色填充。
1、窗口过程函数
本次实验涉及主要消息类型:
1、WM_CREATE:初始化全局变量
2、WM_LBUTTONDOWN:处理鼠标左键按下的消息
3、WM_PAINT:处理窗口重绘的消息
//窗口过程函数:处理窗口接收的消息
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
//关闭窗口
case WM_DESTROY:
PostQuitMessage(0);
break;
//通知窗口需要重绘
case WM_PAINT: {
DrawRect(hwnd);
break;
}
case WM_CREATE:
// 初始化全局变量
start.x = 0;
start.y = 0;
squareSize = 0;
break;
//鼠标左键
case WM_LBUTTONDOWN:
OnLButtonDown(hwnd,lParam);
break;
//都不符合
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);//转给windows处理,默认的窗口过程
}
return 0;
}
2、WM_LBUTTONDOWN:处理鼠标左键按下的消息
期望得到鼠标左键单击时的坐标作为绘制正方形的起始坐标,因此可以使用LOWORD(lParam)获得x坐标,HIWORD(lParam)获得y坐标,然后随机生成正方形的边长,通过全局变量RECT rect存储矩形的边界信息,然后InvalidateRect(hwnd, NULL, TRUE);通知窗口立即重绘。
void OnLButtonDown(HWND hwnd, LPARAM lParam)
{
start.x= LOWORD(lParam);//鼠标X坐标
start.y = HIWORD(lParam);//鼠标Y坐标
squareSize = rand() % 91 + 10;//正方形的边长
rect = { start.x, start.y, start.x + squareSize, start.y + squareSize };//正方形的边界信息
InvalidateRect(hwnd, NULL, TRUE);
}
鼠标消息相关知识点
基本鼠标消息
WM_LBUTTONDOWN:鼠标左键按下
WM_LBUTTONUP:鼠标左键抬起
WM_RBUTTONDOWN:鼠标右键按下
WM_RBUTTONUP:鼠标右键抬起
WM_MOUSEMOVE:鼠标移动消息
双击消息
使用时要在注册窗口类时添加CS_DBLCLKS风格
WM_LBUTTONDBLCLK:鼠标左键双击
WM_RBUTTONDBLCLK:鼠标右键双击
消息产生顺序(左键双击):WM_LBUTTONDOWN
->WM_LBUTTONUP
->WM_LBUTTONDBLCLK
->WM_LBUTTONUP
附带信息
wPARAM:其他按键的状态,如CTRl(包括鼠标本身按键)
lPARAM:鼠标的位置,窗口客户窗坐标系
LOWORD(lPARAM) X坐标
HIWORD(lPARAM) Y坐标
滚轮消息
WM_MOUSEWHEEL:鼠标滚轮消息
附带信息:
wPARAM:
LOWORD(wPARAM) 其他按键的状态,如CTRl(包括鼠标本身按键)
HIWORD(wPARAM) 滚轮的偏移量,正:向前滚动;负:向后滚动
lPARAM:鼠标当前的位置,屏幕坐标系
LOWORD(lPARAM) X坐标
HIWORD(lPARAM) Y坐标
3、WM_PAINT:处理窗口重绘的消息
我们要使用红色实线画笔和红色画刷根据rect存储的正方形信息绘制一个红色实心正方形Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);//根据获得的矩形绘制一个矩形。
void DrawRect(HWND hwnd)
{
PAINTSTRUCT ps;//存储绘画操作的信息。
HDC hdc = BeginPaint(hwnd, &ps);//得到绘图设备
if (squareSize > 0) {
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));//创建红色实心画笔
HGDIOBJ hOldPen = SelectObject(hdc,hPen);//应用画笔到DC
HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));//创建红色画刷
HGDIOBJ hOldBrush = SelectObject(hdc, hBrush);//应用画刷到DC
//绘图
Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);//根据获得的矩形绘制一个矩形
SelectObject(hdc, hOldPen);//取出画笔
SelectObject(hdc, hOldBrush);//取出画刷
DeleteObject(hPen);//释放画笔
DeleteObject(hBrush);//释放画刷
}
//结束绘画操作,将绘画结果提交到屏幕上。
EndPaint(hwnd, &ps);
}
窗口绘图相关知识点
窗口绘图基本流程
绘图设备 DC(Device Context),绘图上下文,绘图描述表
HDC:DC句柄
绘图步骤:
1、得到绘图设备
HDC BeginPaint(
HWND hWnd, //窗口句柄
LPPAINTSTRUCT lpPaint //存储绘画操作的指针
);
2、开始绘画
3、结束绘画,将绘画结果提交到屏幕上。
BOOL EndPaint(
HWND hWnd, //窗口句柄
CONST PAINTSTRUCT *lpPaint //存储绘画操作的指针
);
开始绘画
绘制封闭图形(能使用画刷填充的图形)
矩形:Rectangle
BOOL Rectangle(
HDC hdc, //绘图设备句柄
int left, //矩形的左
int top, //矩形的上
int right, //矩形的右
int bottom //矩形的下
);
通常和结构体RECT
配合使用,RECT
用于定义要绘制的矩形的边界,而Rectangle
函数则根据这些边界信息在屏幕上绘制矩形。
typedef struct RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} ;
GDI绘图对象
HGDIOBJ:GDI绘图对象句柄,兼容画笔句柄,画刷句柄等
HPEN:画笔句柄,描绘线的样式(虚线、点线、实线)、线粗、颜色
HBRUSH:画刷句柄,给封闭图形(不管线型)填充颜色和图案
步骤:
1、创建GDI绘图对象句柄(画笔、画刷)
// 画笔
HPEN CreatePen(
int iStyle, //样式 PS_SOLID:实心线,可以支持多个像素宽,其他类型只能支持一个像素宽
int cWidth, //线粗
COLORREF color //颜色
);
// 画刷
HBRUSH CreateSolidBrush( //创建实心画刷,填充单一颜色
COLORREF color //颜色
);
HBRUSH CreateHatchBrush( //创建纹理画刷,填充纹理线
int iHatch, //纹理样式
COLORREF color //颜色
);
2、将创建的GDI绘图对象句柄应用到DC(绘图设备)中,此时自动取出原来的GDI绘图对象句柄
只能置换同种GDI绘图对象,即画刷换画刷,画笔换画笔
HGDIOBJ SelectObject( //返回值为原来的GDI绘图对象句柄
HDC hdc, //绘图设备句柄
HGDIOBJ hgdiobj //GDI绘图对象句柄(画笔句柄、画刷句柄)
);
3、绘图
4、取出DC(绘图设备)中的GDI绘图对象句柄
使用SelectObject(hdc,原来的GDI绘图对象句柄),即可将之前创建的GDI绘图对象句柄(画笔、画刷)取出
且不需要接收返回值,因为之前创建GDI绘图对象时已有此对象句柄,此时只是将此GDI绘图对象从DC中取出
5、释放GDI绘图对象句柄
只能删除现在不被DC使用的GDI绘图对象,所以释放前要取出创建的GDI绘图对象
BOOL DeleteObject(
HGDIOBJ hgdiobj //GDI绘图对象句柄(画笔句柄、画刷句柄)
);
实验结果
实验小结
本次实验主要处理WM_LBUTTONDOWN
和WM_PAINT
这两类消息类型,通过获得鼠标左击时的坐标作为正方形的起始坐标,通过随机数获取正方形的边长,然后在窗口重绘时使用红色画笔和画刷绘制并填充矩形。
相关链接
win32窗口创建流程
https://www.cnblogs.com/wa2211lq/p/18540536