绘图基础

防止闪烁的方法

1.将Invalidate()替换为InvalidateRect()。
Invalidate()会导致整个窗口的图象重画,需要的时间比较长,而InvalidateRect()仅仅重画Rect区域内的内容,所以所需时间会少一些。

2.禁止系统擦除你的窗口。
系统在需要重画窗口的时候会帮你用指定的背景色来擦除窗口。可是,也许需要重画的区域也许非常小。或者,在你重画这些东西之间还要经过大量的计算才能开始.这个时候你可以禁止系统擦掉原来的图象。直到你已经计算好了所有的数据,自己把那些需要擦掉的部分用背景色覆盖掉(如:dc.FillRect(rect,&brush);rect是需要擦除的区域,brush是带背景色的刷子),再画上新的图形。要禁止系统擦除你的窗口,可以重载OnEraseBkgnd()函数,让其直接返回TRUE就可以了。如

BOOL CmyWin::OnEraseBkgnd(CDC* pDC) 
{
return TRUE;
//return CWnd::OnEraseBkgnd(pDC);
}


3.有效的进行擦除。
擦除背景的时候,不要该擦不该擦的地方都擦。比如,你在一个窗口上放了一个很大的Edit框,几乎占了整个窗口,那么你频繁的擦除整个窗口背景将导致Edit不停重画形成剧烈的闪烁.事实上你可以CRgn创建一个需要擦除的区域,只擦除这一部分.如

GetClientRect(rectClient);//获取窗口客户区
rgn1.CreateRectRgnIndirect(rectClient);//
rgn2.CreateRectRgnIndirect(m_rectEdit);
if(rgn1.CombineRgn(&rgn1,&rgn2,RGN_XOR)= ERROR)
//处理后的rgn1只包括了Edit框之外的客户区域,这样,Edit将不会被我的背景覆盖而导致重画.
{
ASSERT(FALSE);
return ;
}
brush.CreateSolidBrush(m_clrBackgnd);
pDC->FillRgn(&rgn1,&brush);
brush.DeleteObject();


注意:在使用这个方法的时候要同时使用方法二。

4.使用MemoryDC先在内存里把图画好,再复制到屏幕上。
这对于一次画图过程很长的情况比较管用。毕竟内存操作比较快,而且复制到屏幕又是一次性的,至少不会出现可以明显看出一个东西从左画到右的情况。

void CMyWin::OnPaint() 
{
CPaintDC dc1(this); // device context for painting
DcMemory.CreateCompatibleDC(&dc1);
CBitmap bmp;
//这里的Bitmap是必须的,否则当心弄出一个大黑块.
Bmp.CreateCompatibleBitmap(&dc1,rectClient.Width(),rectClient.Height());
DcMemory.SelectObject(&bmp);
//接下来你想怎么画就怎么画
//dcMemory.FillRect(rectClient,&brush); 

dc1.BitBlt(0,0,rectClient.Width(),rectClient.Height(),&dcMemory,0,0,SRCCOPY);
dcMemory.DeleteDC();
// Do not call CWnd::OnPaint() for painting messages
}


SetBrushOrg设置Brush的原点

void CDrawDemoView::OnDraw(CDC* pDC)
{
CBitmap bitmapx;
bitmapx.LoadBitmap(IDB_BITMAP1);
CBrush brushx;
brushx.CreatePatternBrush(&bitmapx);
CRect r(0,0,1024,410);
pDC->SetBrushOrg(500,200);
pDC->FillRect(r,&brushx);
}


MFC(C++)裁剪区域

可以把它理解为一个绘图区域,其大小可以我们来控制。我们知道对单文档应用程序来说,除了标题栏菜单栏以外,剩余的就是客户区。通常可把客户区看做是一个大的裁剪区域,但裁剪区域也可以局限于客户区中的一个很小的范围之内。例如,可以限制一个矩形区域为裁剪区,把以后绘图操作仅限于这个矩形之内。


逻辑坐标和设备坐标

1.设备坐标(Device Coordinate)又称为物理坐标(Physical Coordinate),是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标。设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的X轴向右为正,Y轴向下为正,坐标原点位于窗口的左上角。

2.逻辑坐标(Logical Coordinate)是系统用作记录的坐标。在缺省的模式(MM_TEXT)下,逻辑坐标的方向和单位与设备坐标的方向和单位相同,也是以像素为单位来表示的,X轴向右为正,Y轴向下为正,坐标原点位于窗口的左上角。

3.在VC鼠标坐标的坐标位置用设备坐标表示,但所有GDI绘图都用逻坐标表示,所以用鼠标绘图时,那么必须将设备坐标转换为逻辑坐标,可以使用CDC 函数DPtoLP()将设备坐标转化为逻辑坐标,同样可以用LPtoDP()将逻辑坐标转化为设备坐标。

4.设备坐标转换为逻辑坐标

void CDdView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

    CSize sizeTotal(800, 1050);
    CSize sizePage(sizeTotal.cx/2, sizeTotal.cy/2);
    CSize sizeLine(sizeTotal.cx/50, sizeTotal.cy/50);
    SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine);
	//将逻辑单位转换为设备单位的度量单位,并定义了设备的X、Y轴的方向

	m_pointTopLeft.x=100;
	m_pointTopLeft.y=-100;
	m_sizeEllipse.cx=500;
	m_sizeEllipse.cy=-500;
}
void CDdView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CRect rectEllipse(m_pointTopLeft, m_sizeEllipse);
	CRgn circle;
	CClientDC dc(this);
    OnPrepareDC(&dc);
	//TRACE("Check Point3: HORZSIZE = %d, VERTSIZE = %d/n",dc.GetDeviceCaps(HORZSIZE), dc.GetDeviceCaps(VERTSIZE));
	//HORZSIZE = 320mm, VERTSIZE = 240mm
	TRACE("\r\nBefore LPtoDP:");
	TRACE("rectEllipse.top = %d, rectEllipse.bottom = %d, rectEllipse.left = %d, rectEllipse.right = %d",
		rectEllipse.top, rectEllipse.bottom, rectEllipse.left, rectEllipse.right);
	dc.LPtoDP(rectEllipse);
	TRACE("\r\nnAfter LPtoDP:");
	TRACE("nrectEllipse.top = %d, rectEllipse.bottom = %d, rectEllipse.left = %d, rectEllipse.right = %d",
		rectEllipse.top, rectEllipse.bottom, rectEllipse.left, rectEllipse.right);
	//LPtoDP将rectEllipse从逻辑坐标转换成设备坐标

	/设备坐标
	circle.CreateEllipticRgnIndirect(rectEllipse);
	
	//创建一个内切于特定矩形的椭圆区域
	//TRACE("Check Point2: point = (%d, %d)/n", point.x, point.y);
	//point为逻辑坐标

	//确定点是否在指定区域内
	if(circle.PtInRegion(point))
	{
		SetCapture();
		//Causes all subsequent mouse input to be sent to the current CWnd object regardless of the
		//position of the cursor.
		m_bCaptured = TRUE;
		CPoint pointTopLeft(m_pointTopLeft);
		dc.LPtoDP(&pointTopLeft);
		m_sizeOffset = point - pointTopLeft;
		//m_sizeOffset, point, pointTopLeft皆为设备坐标
		::SetCursor(::LoadCursor(NULL, IDC_CROSS));
    }

	CScrollView::OnLButtonDown(nFlags, point);
}


Before LPtoDP:rectEllipse.top = -100, rectEllipse.bottom = -600, rectEllipse.left = 100, rectEllipse.right = 600
nAfter LPtoDP:nrectEllipse.top = 93, rectEllipse.bottom = 556, rectEllipse.left = 92, rectEllipse.right = 554

逻辑坐标-100转换为设备坐标93方法如下:

设备坐标:屏幕的左上方为(0, 0),屏幕的右边为x坐标的正方向,屏幕的下边为y轴的正方向。

逻辑坐标:屏幕的左上方为(0, 0),右边为x坐标的正方向,对于不同的映射模式,y轴的正方向是不一样的,对

于MM_LOENGLISH而言,向上的方向是正方向,向下的方向是负方向。

最终目标把逻辑100转换为设备坐标想得到的像素

MM_LOENGLISH映射模式下,每逻辑单位是0.01英寸。

100 X 0.01 = 1英寸 = 1 X 2.54 = 2.54cm

dc.GetDeviceCaps(HORZSIZE), dc.GetDeviceCaps(VERTSIZE)的到屏幕尺寸为(440mm,247mm),屏幕分辨率为(1600px,900px)。

设备坐标为:

2.54cm = 25.4mm = 25.4mm / 247mm X 900px = 92.55px



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值