在SDK中实现画条直线,画个矩形等都有现成的函数供我们去调用,有时候直线,矩形画完之后需要能够随鼠标进行移动进而调整图形的位置。
不知道该怎么去表述,就贴代码吧,代码中已经添加了很详细的注释了。
直接把完整的例子代码都贴出来吧,这样最省事了。
// areatest.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "areatest.h"
#include
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_AREATEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_AREATEST));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
// 注释:
//
// 仅当希望
// 此代码与添加到 Windows 95 中的“RegisterClassEx”
// 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
// 这样应用程序就可以获得关联的
// “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_AREATEST));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_AREATEST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//随便定义2点用来画线
static POINT start={200,200},end={500,500};
//保存鼠标按下的点
static POINT ptButtondown;
//保存鼠标移动的点
static POINT ptMousemove;
//判断是否绘制
static bool draw;
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc,hdcMem;
HBITMAP hBitmap;
static HRGN hrgn;
RECT clientrect;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(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_LBUTTONDOWN:
{
//////////////////////////////////////////////////
///每次鼠标按下,需要销毁原来的感应区域,重新创建/
///新的感应区域///////////////////////////////////
DeleteObject(hrgn);
hrgn=NULL;
POINT pointList[4];
////////////////////////////////////////////////////
///简单说明一下这里,由于一条直线是由首位2点组成////
///这里需要给他创建一个感应区域,方便起见,创建一///
///个矩形感应区域,简单的用了勾股定理3,4,5就是创建//
///一个宽度为2*5,长度为直线长度的矩形裁剪区域,当鼠/
///标在此区域按下的时候给予感应,变换鼠标形状实施拖/
///动操作///////////////////////////////////////////
pointList[0].x = (int)(start.x-3);
pointList[0].y = (int)(start.y+4);
pointList[1].x = (int)(start.x+3);
pointList[1].y = (int)(start.y-4);
pointList[2].x = (int)(end.x-3);
pointList[2].y = (int)(end.y+4);
pointList[3].x = (int)(end.x+3);
pointList[3].y = (int)(end.y-4);
//创建直线新位置的感应区域
hrgn = CreatePolygonRgn(pointList, _countof(pointList), WINDING);
ptButtondown.x=LOWORD(lParam);
ptButtondown.y=HIWORD(lParam);
if(PtInRegion(hrgn,ptButtondown.x,ptButtondown.y))
{
OutputDebugString(_T("InRegion"));
//设置鼠标捕获,让鼠标逃不出我窗口的手心控制
SetCapture(hWnd);
//设置光标为四个方向
SetCursor(LoadCursor(NULL,IDC_SIZEALL));
draw=true;
}
}
break;
case WM_MOUSEMOVE:
hdc=GetDC(hWnd);
if(draw==false) break;
OutputDebugString(_T("Move\n"));
SetCursor(LoadCursor(NULL,IDC_SIZEALL));
//得到此刻鼠标移动位置的坐标
ptMousemove.x=LOWORD(lParam);
ptMousemove.y=HIWORD(lParam);
//计算新直线的起点跟终点,加上偏移
start.x=start.x+ptMousemove.x-ptButtondown.x;
start.y=start.y+ptMousemove.y-ptButtondown.y;
end.x=end.x+ptMousemove.x-ptButtondown.x;
end.y=end.y+ptMousemove.y-ptButtondown.y;
//在新的位置上画线
MoveToEx(hdc,start.x,start.y,NULL);
LineTo(hdc,end.x,end.y);
//把当前鼠标移动位置的坐标赋值给ptButtondown,下次计算偏移才准确
ptButtondown.x=ptMousemove.x;
ptButtondown.y=ptMousemove.y;
//完成在新的位置绘制直线
InvalidateRect(hWnd,NULL,TRUE);
ReleaseDC(hWnd,hdc);
break;
case WM_LBUTTONUP:
//释放窗口对鼠标的捕获
ReleaseCapture();
//改变鼠标形状
SetCursor(LoadCursor(NULL,IDC_ARROW));
//设置画线标记
draw=false;
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
/////////////////////////
//如果嫌弃闪烁,可以使用双缓冲
GetClientRect(hWnd,&clientrect);
hdcMem=CreateCompatibleDC(hdc);
hBitmap=CreateCompatibleBitmap(hdc,clientrect.right,clientrect.bottom);
SelectObject(hdcMem,hBitmap);
FillRect(hdcMem,&clientrect,NULL);
MoveToEx(hdcMem,start.x,start.y,NULL);
LineTo(hdcMem,end.x,end.y);
BitBlt(hdc,0,0,clientrect.right,clientrect.bottom,hdcMem,0,0,SRCCOPY);
DeleteObject(hBitmap);
DeleteDC(hdcMem);
///////////////////////////////////
///////////////////////////////////
EndPaint(hWnd, &ps);
break;
/////////////////////////////////////////////////////////////////////
//由于把整个背景都重绘了,所以不再需要擦除背景了,默认的擦除背景是用/
//DefWindowProc(xxx,WM_ERASEBKGND,X,X)做到的,因此在这里我们主动去告/
//诉系统我已经处理过了。/////////////////////////////////////////////
case WM_ERASEBKGND:
return true;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
至于矩形,椭圆的移动就不多说了。
给个简单的运行事例吧。
光棍节要来了。。。。。。。。。
祝各位棍友good luck!!!!