您的位置:首页 > 编程语言 > C语言/C++

VC++SDK中实现直线(矩形,椭圆等)的移动及直线依附矩形椭圆的移动方法(附:运行效果图)

2011-11-03 21:19 483 查看
在SDK中实现画条直线,画个矩形等都有现成的函数供我们去调用,有时候直线,矩形画完之后需要能够随鼠标进行移动进而调整图形的位置。

不知道该怎么去表述,就贴代码吧,代码中已经添加了很详细的注释了。

直接把完整的例子代码都贴出来吧,这样最省事了



// areatest.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "areatest.h"
#include <math.h>

#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!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐