组态软件要实现图元的鼠标交互绘制,并且在运行中需对实时数据以比较高的频率进行屏幕动态刷新显示(一般每50ms刷新一次),因此,对画面窗口绘制实现要求比较高,在此设计画面窗口绘制是以缓存与区域刷新两种技术的组合来实现。
缓存技术是指在画面窗口绘制过程中,不是直接将各图元的绘制效果显示在屏幕上,而是首先将窗口画面以位图形式保存到内存,然后将各图元绘制到该缓存中,最后将缓存中信息重新写回画面窗口,整体显示,使得CRT不为每一个画面的变化而进行一次整屏刷新,从而实现画面窗口的高速绘制。区域刷新技术是指在上述操作过程中只对当前刷新区域进行处理,如仅复制当前区域内屏幕信息到内存,只对与当前刷新区域相容或相交的图元进行绘制,从而进一步提高画面窗口的绘制速度。如何创建memDC的文章网上已经很多,此次不再具体描述。
在程序中,各函数通过逐阶调用或消息通知运行即可实现不同方式的画面窗口绘制。如图元操作函数调用Invalidate函数或CDrawView::InvalObj(this)函数即可实现实时显示本次图元变换操作效果;在视图编辑函数中通过调用OnUpdate函数即可实现不同模式的画面窗口绘制;在工程运行过程中,动画对象也可实现对动画显示区域的动态刷新,而不需整屏刷新,避免了屏幕闪烁,提高系统运行速度。建立画面窗口绘制函数调用关系图如图1.1所示。
分析图1.1画面窗口绘制函数调用关系图,可以看到最终的绘制过程都由画面视图的OnDraw()函数汇总实现,主要有两个大支流,分别对应InvalidateRect()函数和Invalidate()函数,实现单个图元的区域绘制和整屏重绘,这两种绘制方式将根据不同情况而被应用,以达到最快的画面绘制效率。
单个图元绘制指在图形开发/运行时,画面视图仅对变动的图元所占区域进行重绘,主要是采用区域绘制与缓存技术的结合方式实现。如图1.1所描述,单个图元的绘制主要发生在图元编辑操作和动画连接显示。
1.图元编辑操作时,通过逻辑模块定位该图元,调用本图元类的Invalidate()函数,宣布本图元所在区域无效,调用画面逻辑模块::UpdateAllViews在图元所在逻辑模块的所有视图中重绘本图元,各视图获取该图元指针,并重绘图元所占区域;对于单个画面视图刷新,也可直接将本图元指针传给所在视图,调用该视图:: InvalObj()函数,重绘图元所占区域。
2. 运行时进行动画刷新时,直接关联数据改变,需要动画刷新的图元指针传给所在画面视图,调用该视图:: InvalObj()函数,重绘图元所占区域。这个过程可采用两种方法,一种是在动画扫描时,每扫描到一个关联数据发生变化的动画对象,便在动画数据处理后,实现对应图元的重绘;另一种方法是全部扫描完该画面视图动画链表后对整屏进行重绘。二者各有优缺点,当图元重合度小或瞬间动画图元少时,采用第一种方式具有明显速度优势;但当图元重合度大时,因单个图元的绘是采用区域绘制技术,将会造成实际绘制图元数明显大于画面视图的图元总数,此时采用第二种方式全屏绘制反而能保证刷新速度。
局部刷新技术具体实现如下:
每个图元更新时调用pDC->InvalidataRect(m_sz),这个时候在画面刷新时将获得该刷新区域的剪裁区,其中剪裁区分为region 和 clipRect,区别见下图:
其中蓝色的区域合集为region,用GetUpdateRgn获得,红色的区域为所有region围成的最小矩形区,用dc.GetClipBox(clipBoxRect)获得。
在OnPaint函数中先获得该画面目前需要刷新的CRgn和Rect
//获得所要刷新的区域WWW_PLCJS※COM-PLC-技×术_网(可编程控※制器技术门户)
CRgn* pInvalidateRgn;WWW_P※LCJS_COM-PLC-)技.术_网
CRgn rgnInvalidate;WWW_PLCJS※COM-PLC-技×术_网(可编程控※制器技术门户)
rgnInvalidate.CreateRectRgn( 0,0,0,0 );WWW_PLC※JS_COM-PLC-技.术_网(可编程控※制器技术门户)
int nRgnResult = this->GetUpdateRgn( &rgnInvalidate );WWW_PLCJS_COM-PLC-技.术_网
if ( nRgnResult != ERROR && nRgnResult != NULLREGION )WW.W_PLCJS_COM-PLC-技.术_网
{P.L.C.技.术.网——可编程控制器技术门户
pInvalidateRgn = &rgnInvalidate;WWW_PLCJS※COM-PLC-技×术_网(可编程控※制器技术门户)
}WWW※PLCJS_COM-PL#C-技.术_网(可编※程控※制器技术门户)
elseWWW.PLCJS.COM——可编程控制器技术门户
{——可——编——程——控-制-器-技——术——门——户
return;WWW_P※LCJS_COM-PLC-)技.术_网
}P.L.C.技.术.网——可编程控制器技术门户
//获得需要刷新的最小剪裁矩形W1WW_P4LCJS_COM-PLC-技.术_网
CRect clipBoxRect;WWW_P※LCJS_COM-PLC-)技.术_网
dc.GetClipBox(clipBoxRect);W1WW_P4LCJS_COM-PLC-技.术_网
if( clipBoxRect.IsRectEmpty() )WWW_PLCJS_COM-PLC-技.术_网
{WWW_P※LCJS_CO※M-PLC-技-.术_网
if ( rgnInvalidate.GetSafeHandle() )plcjs.技.术_网
{W1WW_P4LCJS_COM-PLC-技.术_网
rgnInvalidate.DeleteObject();WWW_PLCJS@_COM%-PLC-技.术_网
}WWW_PLCJ-S_COM-PLC-技.术_网(可-编程控-制器技术-门户)
return;WWW_PLCJS※COM-PLC-技.术_网(可※编程控※制器技术门户)
}WWW_P※LCJS_CO※M-PLC-技-.术_网
将pInvalidateRgn和clipBoxRect以及memDC传入每个图元的绘制函数中,绘制前先判断该region和clipRect是否与该图元的边界有交集
/// <summary>WWW_P※LCJS_CO※M-PLC-技-.术_网WWW_PLCJ-S_COM-PLC-技.术_网(可-编程控-制器技术-门户)
/// 判断是否与矩形相交,包括包含WWcW_PLCJS_COM-PLC-技.术_网plcjs.技.术_网
/// </summary>WW.W_PLCJS_COM-PLC-技.术_网WW.W_PLCJS_COM-PLC-技.术_网
BOOL CLayer::IsIntersectsWith( const CRect& rect1,const CRect& rect2 )WW.W_PLCJS_COM-PLC-技.术_网WWW_PLC※JS_COM-PmLC-技.术_网
{P_L_C_技_术_网——可——编——程——控-制-器-技——术——门——户WWW_PLCJS※COM-PLC-技.术_网(可※编程控※制器技术门户)
return ( (rect1.left < (rect2.left rect2.Width()))P_L_C_技_术_网——可——编——程——控-制-器-技——术——门——户WWW_PLC※JS_COM-PLC-技.术_网(可编程控※制器技术门户)
&& (rect1.top < (rect2.top rect2.Height()))WWW_PLCJS※COM-PLC-技.术_网(可※编程控※制器技术门户)WWW※PLCJS_COM-PL#C-技.术_网(可编※程控※制器技术门户)
&& (rect2.left < (rect1.left rect1.Width()))——可——编——程——控-制-器-技——术——门——户WW.W_PLCJS_COM-PLC-技.术_网
&& (rect2.top < (rect1.top rect1.Height())) );WW.W_PLC※JS_C,OM-PL,C-技.术_网——可——编——程——控-制-器-技——术——门——户
}WWW_P※LCJS_COM-PLC-)技.术_网WWW_PLCJS※COM-PLC-技.术_网(可※编程控※制器技术门户)
/// <summary>WWW_PLCJS_COM-PLC-技.术_网WWcW_PLCJS_COM-PLC-技.术_网
/// 图层绘制函数plcjs.技.术_网——可——编——程——控-制-器-技——术——门——户
/// </summary>WWW_PLCJS@_COM%-PLC-技.术_网plcjs.技.术_网
void CLayer::Draw(CDC *pDC,CRect *pr,CRgn* pInvalidateRgn)WWW.PLCJS.COM——可编程控制器技术门户WWcW_PLCJS_COM-PLC-技.术_网
{WWW_PLC※JS_COM-PLC-技.术_网(可编程控※制器技术门户)P_L_C_技_术_网——可——编——程——控-制-器-技——术——门——户
int i;WW.W_PLC※JS_C,OM-PL,C-技.术_网P_L_C_技_术_网——可——编——程——控-制-器-技——术——门——户
if(!m_enable) return ;WWW_P※LCJS_CO※M-PLC-技-.术_网WWW_PLC※JS_COM-PmLC-技.术_网
WWW_PLCJS_COM-PLC-技.术_网WWW_PLCJS_COM-PLC-技.术_网
int cnt = m_FigObjArray.GetSize();WW.W_PLC※JS_C,OM-PL,C-技.术_网WWW_PLCJS※COM-PLC-技.术_网(可※编程控※制器技术门户)
BOOL bl=TRUE;WW.W_PLCJS_COM-PLC-技.术_网P.L.C.技.术.网——可编程控制器技术门户
for(i=0; i<cnt; i ) {P_L_C_技_术_网——可——编——程——控-制-器-技——术——门——户WWW_PLCJS@_COM%-PLC-技.术_网
CObjBase *pFigObj = m_FigObjArray.GetAt(i);P_L_C_技_术_网——可——编——程——控-制-器-技——术——门——户WW.W_PLC※JS_C,OM-PL,C-技.术_网
CRect pixelBounds(pFigObj->m_pt0,pFigObj->m_sz CSize(1,1));——可——编——程——控-制-器-技——术——门——户W1WW_P4LCJS_COM-PLC-技.术_网
///过滤不在剪裁区中的图元WWcW_PLCJS_COM-PLC-技.术_网WWW_PLCJS※COM-PLC-技.术_网(可※编程控※制器技术门户)
if (!IsIntersectsWith(pixelBounds,*pr))WW.W_PLC※JS_C,OM-PL,C-技.术_网WWW_P※LCJS_CO※M-PLC-技-.术_网
{WWW_PLC※JS_COM-PLC-技.术_网(可编程控※制器技术门户)WWW_PLCJS@_COM%-PLC-技.术_网
continue;WWW_P※LCJS_CO※M-PLC-技-.术_网plcjs.技.术_网
}///过滤不在刷新区域中的图元WWW_PL※CJS_COM-PLC-技.术_网WWW_P※LCJS_CO※M-PLC-技-.术_网
if (pInvalidateRgn)WWW_P※LCJS_COM-PLC-)技.术_网WWW_PLCJS_COM-PLC-技.术_网
{WWW.PLCJS.COM——可编程控制器技术门户plcjs.技.术_网
pDC->LPtoDP(&pixelBounds);WWW_PLCJ-S_COM-PLC-技.术_网(可-编程控-制器技术-门户)WWW_PLCJ-S_COM-PLC-技.术_网(可-编程控-制器技术-门户)
if (!pInvalidateRgn->RectInRegion( pixelBounds ))WWW_PLC※JS_COM-PmLC-技.术_网WWW_PLCJS_COM-PLC-技.术_网
{WWW※PLCJS_COM-PL#C-技.术_网(可编※程控※制器技术门户)P.L.C.技.术.网——可编程控制器技术门户
continue;WWW_P※LCJS_CO※M-PLC-技-.术_网WWW_PL※CJS_COM-PLC-技.术_网
}WWW_PLCJS@_COM%-PLC-技.术_网WWW_P※LCJS_COM-PLC-)技.术_网
}WWW_PLCJS@_COM%-PLC-技.术_网WWW_PLC※JS_COM-PLC-技.术_网(可编程控※制器技术门户)
plcjs.技.术_网WWW.PLCJS.COM——可编程控制器技术门户
///只有在刷新区域内的图元才真正绘制WWW_PLC※JS_COM-PmLC-技.术_网WWW_PLCJS※COM-PLC-技×术_网(可编程控※制器技术门户)
bl=pFigObj->DrawFig(pDC,bl);WWW.PLCJS.COM——可编程控制器技术门户WWW.PLCJS.COM——可编程控制器技术门户
W1WW_P4LCJS_COM-PLC-技.术_网WWW_PLCJS@_COM%-PLC-技.术_网
}WWW_P※LCJS_COM-PLC-)技.术_网WWcW_PLCJS_COM-PLC-技.术_网
}WWW_PLCJS※COM-PLC-技×术_网(可编程控※制器技术门户)WW.W_PLCJS_COM-PLC-技.术_网