#include <windows.h>
// 工具按钮ID定义:用于区分不同的绘图工具按钮
#define ID_TOOL_LINE 1001 // 直线工具ID
#define ID_TOOL_RECT 1002 // 矩形工具ID
#define ID_TOOL_ELLIPSE 1003 // 椭圆/圆形工具ID
#define ID_TOOL_ERASER 1005 // 橡皮擦工具ID
#define ID_TOOL_CLEAR 1004 // 清空画布工具ID
// 颜色按钮ID定义:用于区分不同的颜色选择按钮
#define ID_COLOR_RED 1010 // 红色ID
#define ID_COLOR_GREEN 1011 // 绿色ID
#define ID_COLOR_BLUE 1012 // 蓝色ID
#define ID_COLOR_BLACK 1013 // 黑色ID
// 全局变量:存储绘图程序的核心状态
int currentTool = 0; // 当前选中的工具:0直线/1矩形/2椭圆/3橡皮擦
COLORREF currentColor = RGB(0,0,0); // 当前绘图颜色,默认黑色
BOOL isDrawing = FALSE; // 是否正在绘图的标志:FALSE未绘制,TRUE正在绘制
int startX, startY, endX, endY; // 绘图起点(start)和终点(end)坐标
// 双缓冲绘图相关全局变量(解决绘图闪烁问题)
HBITMAP canvasBitmap = NULL; // 画布位图:存储所有绘制的内容
HDC memDC = NULL; // 内存DC:在内存中绘制,再一次性显示到窗口
// 窗口过程函数:处理窗口所有消息(核心回调函数)
// hWnd:窗口句柄 msg:消息类型 wParam/lParam:消息附加参数
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps; // 绘图结构体:用于WM_PAINT消息绘图
HDC hdc; // 设备上下文句柄:绘图的核心接口
switch(msg) // 根据消息类型执行不同操作
{
case WM_CREATE: // 窗口创建时触发:初始化界面+画布
{
// 获取应用程序实例句柄
HINSTANCE hInst = ((LPCREATESTRUCT)lParam)->hInstance;
// ========== 创建绘图工具按钮 ==========
// 创建"直线"按钮:可见+子窗口,坐标(20,10),大小60x25
CreateWindowA("BUTTON","直线",WS_VISIBLE|WS_CHILD,20,10,60,25,hWnd,(HMENU)ID_TOOL_LINE,hInst,0);
// 创建"矩形"按钮
CreateWindowA("BUTTON","矩形",WS_VISIBLE|WS_CHILD,90,10,60,25,hWnd,(HMENU)ID_TOOL_RECT,hInst,0);
// 创建"圆形"按钮
CreateWindowA("BUTTON","圆形",WS_VISIBLE|WS_CHILD,160,10,60,25,hWnd,(HMENU)ID_TOOL_ELLIPSE,hInst,0);
// 创建"橡皮擦"按钮
CreateWindowA("BUTTON","橡皮擦",WS_VISIBLE|WS_CHILD,230,10,60,25,hWnd,(HMENU)ID_TOOL_ERASER,hInst,0);
// 创建"清空画布"按钮
CreateWindowA("BUTTON","清空画布",WS_VISIBLE|WS_CHILD,300,10,80,25,hWnd,(HMENU)ID_TOOL_CLEAR,hInst,0);
// ========== 创建颜色选择按钮 ==========
// 创建"红"色按钮
CreateWindowA("BUTTON","红",WS_VISIBLE|WS_CHILD,20,45,40,25,hWnd,(HMENU)ID_COLOR_RED,hInst,0);
// 创建"绿"色按钮
CreateWindowA("BUTTON","绿",WS_VISIBLE|WS_CHILD,70,45,40,25,hWnd,(HMENU)ID_COLOR_GREEN,hInst,0);
// 创建"蓝"色按钮
CreateWindowA("BUTTON","蓝",WS_VISIBLE|WS_CHILD,120,45,40,25,hWnd,(HMENU)ID_COLOR_BLUE,hInst,0);
// 创建"黑"色按钮
CreateWindowA("BUTTON","黑",WS_VISIBLE|WS_CHILD,170,45,40,25,hWnd,(HMENU)ID_COLOR_BLACK,hInst,0);
// ========== 初始化双缓冲画布 ==========
RECT r; // 定义矩形结构体,存储窗口客户区大小
GetClientRect(hWnd, &r); // 获取窗口客户区坐标(可绘图区域)
hdc = GetDC(hWnd); // 获取窗口DC
memDC = CreateCompatibleDC(hdc); // 创建与窗口兼容的内存DC
// 创建与窗口兼容的位图,作为画布,大小=窗口大小
canvasBitmap = CreateCompatibleBitmap(hdc, r.right, r.bottom);
SelectObject(memDC, canvasBitmap); // 将位图选入内存DC
// 把画布背景填充为白色
HBRUSH whiteBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); // 获取白色画刷
SelectObject(memDC, whiteBrush); // 选入内存DC
Rectangle(memDC, 0, 0, r.right, r.bottom); // 绘制白色背景矩形
ReleaseDC(hWnd, hdc); // 释放窗口DC
break;
}
case WM_COMMAND: // 按钮点击消息:处理工具/颜色选择
{
switch(LOWORD(wParam)) // LOWORD(wParam)获取按钮ID
{
case ID_TOOL_LINE: // 点击直线按钮
currentTool = 0; // 设置当前工具为直线
break;
case ID_TOOL_RECT: // 点击矩形按钮
currentTool = 1; // 设置当前工具为矩形
break;
case ID_TOOL_ELLIPSE: // 点击圆形按钮
currentTool = 2; // 设置当前工具为椭圆
break;
case ID_TOOL_ERASER: // 点击橡皮擦按钮
currentTool = 3; // 设置当前工具为橡皮擦
break;
case ID_TOOL_CLEAR: // 点击清空画布按钮
{
RECT r; // 获取窗口客户区
GetClientRect(hWnd, &r);
HBRUSH whiteBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); // 白色画刷
SelectObject(memDC, whiteBrush);
Rectangle(memDC, 0, 0, r.right, r.bottom); // 全屏绘制白色
InvalidateRect(hWnd, NULL, TRUE); // 刷新窗口,显示清空效果
break;
}
case ID_COLOR_RED: // 点击红色按钮
currentColor = RGB(255,0,0); // 设置当前颜色为红色
break;
case ID_COLOR_GREEN: // 点击绿色按钮
currentColor = RGB(0,255,0); // 设置当前颜色为绿色
break;
case ID_COLOR_BLUE: // 点击蓝色按钮
currentColor = RGB(0,0,255); // 设置当前颜色为蓝色
break;
case ID_COLOR_BLACK: // 点击黑色按钮
currentColor = RGB(0,0,0); // 设置当前颜色为黑色
break;
}
break;
}
case WM_LBUTTONDOWN: // 鼠标左键按下:开始绘图
isDrawing = TRUE; // 标记正在绘图
startX = LOWORD(lParam); // 获取鼠标按下X坐标(起点)
startY = HIWORD(lParam); // 获取鼠标按下Y坐标(起点)
break;
case WM_MOUSEMOVE: // 鼠标移动:实时预览/擦除
if(isDrawing) // 判断是否按住左键拖动
{
endX = LOWORD(lParam); // 更新鼠标当前X坐标(终点)
endY = HIWORD(lParam); // 更新鼠标当前Y坐标(终点)
// 橡皮擦功能:按住拖动实时擦除
if(currentTool == 3)
{
// 定义橡皮擦大小:24x24的白色矩形
RECT rect = { endX-12, endY-12, endX+12, endY+12 };
// 用白色填充矩形,实现擦除效果
FillRect(memDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
}
InvalidateRect(hWnd, NULL, FALSE); // 刷新窗口,显示实时效果
}
break;
case WM_LBUTTONUP: // 鼠标左键抬起:完成绘图
if(isDrawing) // 判断之前是在绘图状态
{
isDrawing = FALSE; // 结束绘图
endX = LOWORD(lParam); // 获取鼠标抬起X坐标(终点)
endY = HIWORD(lParam); // 获取鼠标抬起Y坐标(终点)
if(currentTool != 3) // 非橡皮擦工具:执行绘图
{
// 创建画笔:实线,宽度2,当前选择的颜色
HPEN pen = CreatePen(PS_SOLID, 2, currentColor);
SelectObject(memDC, pen); // 将画笔选入内存DC
// 选择空画刷:图形只描边,不填充
SelectObject(memDC, GetStockObject(NULL_BRUSH));
if(currentTool == 0) // 直线工具
{
MoveToEx(memDC, startX, startY, NULL); // 移动到起点
LineTo(memDC, endX, endY); // 绘制直线到终点
}
if(currentTool == 1) // 矩形工具
{
// 绘制矩形:起点+终点确定矩形大小
Rectangle(memDC, startX, startY, endX, endY);
}
if(currentTool == 2) // 椭圆/圆形工具
{
// 绘制椭圆:外接矩形为起点到终点
Ellipse(memDC, startX, startY, endX, endY);
}
DeleteObject(pen); // 删除画笔,释放资源
}
InvalidateRect(hWnd, NULL, TRUE); // 刷新窗口显示最终图形
}
break;
case WM_PAINT: // 窗口绘图消息:窗口刷新时执行
hdc = BeginPaint(hWnd, &ps); // 开始绘图,获取DC
// 将内存DC的画布内容,一次性复制到窗口DC(双缓冲核心)
BitBlt(hdc, 0, 0, 1000, 600, memDC, 0, 0, SRCCOPY);
// 正在绘图且不是橡皮擦:显示实时预览图形
if(isDrawing && currentTool != 3)
{
HPEN pen = CreatePen(PS_SOLID, 2, currentColor);
SelectObject(hdc, pen);
SelectObject(hdc, GetStockObject(NULL_BRUSH));
if(currentTool == 0) // 预览直线
{
MoveToEx(hdc, startX, startY, NULL);
LineTo(hdc, endX, endY);
}
if(currentTool == 1) // 预览矩形
{
Rectangle(hdc, startX, startY, endX, endY);
}
if(currentTool == 2) // 预览椭圆
{
Ellipse(hdc, startX, startY, endX, endY);
}
DeleteObject(pen);
}
EndPaint(hWnd, &ps); // 结束绘图
break;
case WM_DESTROY: // 窗口销毁:释放资源+退出程序
DeleteObject(canvasBitmap); // 删除画布位图
DeleteDC(memDC); // 删除内存DC
PostQuitMessage(0); // 发送退出消息,关闭程序
break;
default: // 其他消息:交给系统默认处理
return DefWindowProcA(hWnd, msg, wParam, lParam);
}
return 0;
}
// 主函数:程序入口
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR cmd, int nShow)
{
WNDCLASSA wc = {0}; // 定义窗口类结构体并初始化
wc.lpfnWndProc = WndProc; // 绑定窗口过程函数
wc.hInstance = hInstance; // 设置应用程序实例句柄
wc.lpszClassName = "SimplePaint"; // 窗口类名
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // 窗口背景色
RegisterClassA(&wc); // 注册窗口类
// 创建窗口
HWND hWnd = CreateWindowA(
"SimplePaint", // 窗口类名
"简易画图软件", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口样式(带标题栏+边框)
100,100,800,550, // 窗口坐标(100,100),大小800x550
NULL,NULL,hInstance,NULL
);
ShowWindow(hWnd, nShow); // 显示窗口
UpdateWindow(hWnd); // 刷新窗口
MSG msg; // 消息结构体
// 消息循环:持续获取并处理消息
while(GetMessage(&msg, NULL, 0,0))
{
TranslateMessage(&msg); // 翻译消息
DispatchMessage(&msg); // 分发消息到窗口过程
}
return 0;
}