windows程序设计(10):矩形与区域

windows中,矩形结构RECT通过左上角和右下角两个点控制。
RECT rect;
rect.left= xLeft ;
rect.top= xTop ;
rect.right= xRight ;
rect.bottom= xBottom ;
矩形支持操作很多,比如OffsetRect (&rect, x, y) ;(将矩形移动);IntersectRect (&DestRect, &SrcRect1, &SrcRect2) ;获得两个矩形的交集;bInRect = PtInRect (&rect, point) ;判断点是否在矩形里等。这里不一一细讲了。

有一点需要注意,通常我们可以使用GetClientRect来或得整个客户区,将它存在一个RECT结构中,非常方便。

什么又是区域呢?区域可以使矩形、椭圆,多边形,或者是多个它们的组合,如何或得区域呢,以矩形为例,通过CreateRectRgnIndirect就能或得一个矩形区域了。先看一个简单程序:

#include <windows.h>
#include <math.h>


LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,		//当前实例句柄
				   HINSTANCE hPrevInstance, //先前实例句柄
				   LPSTR lpCmdLine,			//命令行
				   int iCmdShow)			//显示状态
{
	static TCHAR szAppName[] = TEXT("画图");
	//窗口句柄
	HWND hwnd;
	//消息
	MSG msg;
	//窗口类
	WNDCLASS wndclass;
	//窗口风格:当移动窗口或者改变大小时重绘窗口
	wndclass.style		   =  CS_HREDRAW | CS_VREDRAW;
	//指明回调函数
	wndclass.lpfnWndProc   = WndProc;
	//额外的比特用来确认下一个窗口类的位置,暂时不用
	wndclass.cbClsExtra    = 0;
	//额外的比特用来确认下一个窗口实例的位置,暂时不用
	wndclass.cbWndExtra    = 0;
	//实例句柄
	wndclass.hInstance     = hInstance;
	//装载图标
	wndclass.hIcon		   = LoadIcon(NULL, IDI_APPLICATION);
	//装载光标
	wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
	//背景为白色
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
	//菜单:暂时没有
	wndclass.lpszMenuName  = NULL;
	//窗口类名
	wndclass.lpszClassName = szAppName;

	//注册窗口
	if(!RegisterClass(&wndclass))
	{
		return -1;
	}

	//创建窗口
	hwnd = CreateWindow(szAppName,				//窗口类的名称,必须是已经注册的
						TEXT("我的画图"),		//窗口标题
						WS_OVERLAPPEDWINDOW,	//窗口风格
						CW_USEDEFAULT,			//X坐标
						CW_USEDEFAULT,			//Y坐标
						CW_USEDEFAULT,			//宽度
						CW_USEDEFAULT,			//高度
						NULL,					//父窗口句柄
						NULL,					//菜单窗口句柄
						hInstance,				//高级版本的windos忽略
						NULL);					

	//显示窗口
	//ShowWindow(hwnd,SW_SHOWNA);
	ShowWindow (hwnd, iCmdShow);

	//更新窗口
	UpdateWindow(hwnd);

	//消息循环
	while(GetMessage(&msg,NULL,0,0))
	{
		
		TranslateMessage(&msg);
		//将消息给窗口
		DispatchMessage(&msg);

	}

	return msg.wParam;

}


LRESULT CALLBACK WndProc (HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	HDC				hdc;
	//区域句柄
	HRGN			hRgn;
	//刷子句柄
	HBRUSH			hBrush;
	//矩形区域
	static RECT		rect;
	//客户区的矩形区域
	RECT			clientRect;
	static int		x,y;
  
	switch (message)
	{
	case WM_CREATE:
		x = 100;
		y = 100;
		//矩形区域的默认位置
		rect.left	=  0;
		rect.top	=  0;
		rect.right	= x + 100;
		rect.bottom = y + 100;


		return 0;

	case WM_LBUTTONDOWN:
		
		hdc	= GetDC(hwnd);
		//把整个客户区刷白
		GetClientRect(hwnd,&clientRect);
		hBrush = CreateSolidBrush(RGB(255,255,255));
		FillRect(hdc,&clientRect,hBrush);


		//设置指定颜色的刷子
		hBrush = CreateSolidBrush(RGB(255,0,0));
		//使用指定的刷子填充矩形
		FillRect(hdc,&rect,hBrush);


		//创建一个矩形区域
		//hRgn = CreateRectRgnIndirect(&rect);
		//使用指定的刷子填充区域
		//FillRgn(hdc,hRgn,hBrush);

		//将矩形移动指定的偏移
		OffsetRect(&rect,x,y);

		ReleaseDC(hwnd,hdc);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	}
	return DefWindowProc(hwnd,message,wParam,lParam); 
}


这个程序实现了通过单击鼠标左键是得矩形实现偏移。程序比较简单,唯一值得注意的是,有两种方法实现显示红色的矩形:第一是用红刷子对矩形填充,第二是用矩形创建一个区域,用刷子填充整个区域。

下面这个程序着重讨论区域的拼接问题:

#include <windows.h>		
#include <math.h>		
#define TWO_PI (2.0 * 3.14159)		
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;		
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)		
{		
	static TCHAR szAppName[] = TEXT ("Clover") ;		
	HWND			hwnd ;		
	MSG				msg ;		
	WNDCLASS		wndclass ;		
			
	wndclass.style				= CS_HREDRAW | CS_VREDRAW ;		
	wndclass.lpfnWndProc		= WndProc ;		
	wndclass.cbClsExtra			= 0 ;		
	wndclass.cbWndExtra			= 0 ;		
	wndclass.hInstance			= hInstance ;		
	wndclass.hIcon				= LoadIcon (NULL, IDI_APPLICATION) ;		
	wndclass.hCursor			= LoadCursor (NULL, IDC_ARROW) ;		
	wndclass.hbrBackground		= (HBRUSH) GetStockObject (WHITE_BRUSH) ;		
	wndclass.lpszMenuName		= NULL ;		
	wndclass.lpszClassName		= szAppName ;
		  		
	if (!RegisterClass (&wndclass))		
	{
		
			MessageBox (NULL, TEXT ("This program requires Windows NT!"),szAppName, MB_ICONERROR) ;		
			return 0 ;	
	}
		
   		
	hwnd = CreateWindow (szAppName, TEXT ("Draw a Clover"),  WS_OVERLAPPEDWINDOW,   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;
		
	ShowWindow (hwnd, iCmdShow) ;
		
	UpdateWindow (hwnd) ;
		   		
	while (GetMessage (&msg, NULL, 0, 0))		
	{
		
			TranslateMessage (&msg) ;
		
			DispatchMessage (&msg) ;
		
	}
		
	return msg.wParam ;
		
}
		

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
		
{
	//全局区域句柄	
	static HRGN		hRgnClip ;		
	static int		cxClient, cyClient ;		
	double			fAngle, fRadius ;		
	HCURSOR			hCursor ;		
	HDC				hdc ;
	//局部区域句柄数组	
	HRGN			hRgnTemp[6] ;		
	int				i ;		
	PAINTSTRUCT		ps ;

	switch (iMsg)
		
	{
		
	case   WM_SIZE:
		
			cxClient	  = LOWORD (lParam) ;		
			cyClient	  = HIWORD (lParam) ;
			//装载等待光标
			hCursor= SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
			//显示光标
			ShowCursor (TRUE) ;
						
			if (hRgnClip)
				DeleteObject (hRgnClip) ;
		
		
			//创建椭圆区域的参数为外接矩形的左上角x坐标,左上角y坐标;右下角x坐标,右下角y坐标			
			hRgnTemp[0]   = CreateEllipticRgn (0, cyClient / 3, cxClient / 2, 2 * cyClient / 3) ;		
			hRgnTemp[1]   = CreateEllipticRgn (cxClient / 2, cyClient / 3, cxClient, 2 * cyClient / 3) ;		
			hRgnTemp[2]   = CreateEllipticRgn (cxClient / 3, 0,2 * cxClient / 3, cyClient / 2) ;		
			hRgnTemp[3]   = CreateEllipticRgn (cxClient / 3, cyClient / 2,2 * cxClient / 3, cyClient) ;		
			//整个客户区
			hRgnTemp[4]   = CreateRectRgn (0, 0, 1, 1) ;		
			hRgnTemp[5]   = CreateRectRgn (0, 0, 1, 1) ;		
			hRgnClip	= CreateRectRgn (0, 0, 1, 1) ;
		
			//将区域拼接起来
			//参数为:目标区域,原区域,原区域,拼接模式
			//两个区域的并集
			CombineRgn (hRgnTemp[4], hRgnTemp[0], hRgnTemp[1], RGN_OR) ;		
			CombineRgn (hRgnTemp[5], hRgnTemp[2], hRgnTemp[3], RGN_OR) ;	
			//两个区域的并集,但是不包括重叠的部分
			CombineRgn (hRgnClip,	hRgnTemp[4], hRgnTemp[5], RGN_XOR) ;
		
		
			//删除临时的区域
			for (i = 0 ; i < 6 ; i++)		
				   DeleteObject (hRgnTemp[i]) ;
		
		
		
			SetCursor (hCursor) ;
		
			ShowCursor (FALSE) ;
		
			return 0 ;
		
		
		
	case   WM_PAINT:
		
			hdc = BeginPaint (hwnd, &ps) ;		
			//将视口原点设置到客户区中心
			SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;	
			//选择我们已经合并好的区域
			SelectClipRgn (hdc, hRgnClip) ;	
			//通过两条直角边计算斜边
			fRadius = _hypot (cxClient / 2.0, cyClient / 2.0) ;
			//1度1度的变化
			for (fAngle = 0.0 ; fAngle < TWO_PI ; fAngle += TWO_PI / 360)
		
			{
		
				//起点移动到原点
				MoveToEx (hdc, 0, 0, NULL) ;
				//画线
				LineTo (hdc,  (int) ( fRadius * cos (fAngle) + 0.5), (int) (-fRadius * sin (fAngle) + 0.5)) ;
		
			}
		
			EndPaint (hwnd, &ps) ;
		
			return 0 ;
		
	case WM_DESTROY:
			//删除该区域
			DeleteObject (hRgnClip) ;
		
			PostQuitMessage (0) ;
		
			return 0 ;
		
	}
		
	return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
		
}


程序中将4个椭圆拼接起来,形成了新的区域。fRadius是中心到客户区顶点的距离。

将视口的原点设置到了客户区的中心,然后对于每一度,计算一条线与客户区边沿的交点的x,y坐标(加0.5是为了四舍五入),但是由于我们之前定义了区域,所以不论线实际画了多长,屏幕上只会显示出现在区域中的部分。

但是这个程序有一个bug,在win7下,如果将客户区最大化(或者放的非常大)时,画的线会出现一些明显的裂缝,我通过如下代码测试:

	case   WM_PAINT:
		
			hdc = BeginPaint (hwnd, &ps) ;

			//获取整个区域的轮廓
			SelectClipRgn (hdc, hRgnClip) ;	
			hBrush = CreateSolidBrush(RGB(0,0,0));
			FillRgn(hdc,hRgnClip,hBrush);

			/*
			//将视口原点设置到客户区中心
			SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;	
			//选择我们已经合并好的区域
			SelectClipRgn (hdc, hRgnClip) ;	
			//通过两条直角边计算斜边
			fRadius = _hypot (cxClient / 2.0, cyClient / 2.0) ;
			//1度1度的变化
			for (fAngle = 0.0 ; fAngle < TWO_PI ; fAngle += TWO_PI / 360)
		
			{
		
				//起点移动到原点
				MoveToEx (hdc, 0, 0, NULL) ;
				//画线
				LineTo (hdc,  (int) ( fRadius * cos (fAngle) + 0.5), (int) (-fRadius * sin (fAngle) + 0.5)) ;
		
			}
			*/
			EndPaint (hwnd, &ps) ;
			
			return 0 ;



发现最大化窗口时,区域依然四个椭圆拼接而成的的,但是画出的线却出现了问题。

不论是VS2010还是VC++6.0这个问题依然存在。有人说xp下不会出现这种情况,具体为什么我也不知道。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Delphi是一种编程语言与集成开发环境(IDE)的组合,用于创建应用程序。在Delphi中,矩形区域是一种用于界面设计的控件,常用于显示和容纳其他控件。 矩形区域是一个矩形的可见区域,其边界由左上角和右下角的坐标确定。它可以用来创建复杂的布局,将不同的控件组织在一个矩形区域内,使界面更加清晰和易于管理。 在Delphi中,可以通过拖拽和放置的方式将矩形区域添加到窗体或面板上。可以设置矩形区域的位置、大小、颜色、边框样式等属性。通过调整这些属性,可以实现不同风格和功能的矩形区域矩形区域可以包含其他控件,比如标签、按钮、文本框等。通过将这些控件放置在矩形区域内,可以实现更复杂的界面布局和交互功能。还可以通过代码来控制矩形区域中的控件,比如改变它们的内容、位置、可见性等。 在Delphi中,矩形区域还具有事件处理的能力。可以通过代码为矩形区域添加的事件,比如鼠标点击、键盘按键等,实现与用户的交互。 总而言之,Delphi中的矩形区域是一种用于界面设计的控件,可以帮助我们创建更复杂、清晰和易于管理的界面布局。通过设置属性和添加事件,可以进一步实现更多的功能和交互操作。 ### 回答2: Delphi是一种编程语言和集成开发环境,它在图形用户界面设计中有着广泛应用。在Delphi中,矩形区域是一种常用的图形控件,用于在用户界面中显示矩形形状的区域。 在Delphi中,可以通过使用TShape组件创建矩形区域。TShape是Delphi中的一个图形控件,它可以用来显示各种形状,包括矩形。通过设置TShape的Shape属性为stRectangle,可以将它设置为矩形形状。 在界面设计中,可以通过拖放TShape组件到窗体上创建矩形区域。然后,可以通过设置TShape的Left、Top、Width和Heigh属性来调整矩形区域的位置和大小。可以通过设置TShape的Color属性来改变矩形区域的填充颜色,通过设置TShape的Pen属性来改变矩形区域的边框颜色。 除了TShape组件,Delphi还提供了其他一些用于矩形区域的控件和组件,比如TPanel、TImage等。这些控件和组件都可以用来创建矩形区域,并且可以根据实际需要来设置其属性和样式。 总之,Delphi中的矩形区域是通过使用TShape组件或其他相关控件和组件来创建和显示的。通过设置这些控件和组件的属性和样式,可以调整矩形区域的位置、大小、填充颜色和边框颜色等,从而实现各种不同的界面设计需求。 ### 回答3: Delphi是一款流行的编程语言和集成开发环境(IDE),用于开发Windows平台的应用程序。在Delphi中,矩形区域是一个常见的概念,用于表示一个平面上的矩形区域矩形区域由四条边界线包围,具有四个顶点和四个角。在Delphi中,我们可以通过使用`TRect`结构来表示一个矩形区域。`TRect`结构包含了矩形的左上角和右下角的坐标。这个结构有`Left`、`Top`、`Right`和`Bottom`四个属性,分别表示矩形左上角和右下角的X和Y坐标。 我们可以使用`TRect`结构来实现各种矩形区域相关的操作,例如计算两个矩形是否相交、计算矩形的宽度和高度等。可以使用`IntersectRect`函数来判断两个矩形是否相交,该函数会返回一个布尔值表示是否相交。此外,还有一些其他的函数可以用来计算矩形的宽度、高度和面积,例如`RectWidth`、`RectHeight`和`RectArea`等。 在Delphi中,我们可以使用矩形区域来处理窗口、控件和图形等方面的操作。例如,我们可以通过设置控件的`BoundsRect`属性来定义控件的大小和位置,该属性接受一个`TRect`结构作为参数。 总的来说,Delphi提供了丰富的功能来处理矩形区域,使得我们能够轻松地进行各种矩形区域相关的操作。无论是处理窗口、控件还是图形等方面的操作,我们都可以使用Delphi的矩形区域功能来简化和优化代码的编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值