UCGUI中的实现透明窗体的原理Word文档格式.docx
- 文档编号:22271362
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:15
- 大小:34.46KB
UCGUI中的实现透明窗体的原理Word文档格式.docx
《UCGUI中的实现透明窗体的原理Word文档格式.docx》由会员分享,可在线阅读,更多相关《UCGUI中的实现透明窗体的原理Word文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
假设一张图片A与B,如果B是透明的,其意即,透明B可以看到A,但并不是完全看到A,只是看到A的朦胧的影象。
在图形处理上,其实就是在A上面再显示B的时候,对B上面的每个点的颜色做了处理,简单的说就是与A的颜色按比例进行了一个混合,混合的时候是按照R、G、G分别进行混合的.
2.透明显示的计算公式
alpha是透明度,亦即显示B时B的每个象素点与A的相同位置的象素点进行混合的比例系数,R(b)_new/G(b)_new/B(b)_new为计算所得的新的B要显示的象素点的R/G/B颜色分量,R(b)/G(b)/B(b)为B本来象素点要显示的象素点的R/G/B颜色分量,R(a)/G(a)/B(a)为A的点的R/G/B颜色分量.
R(b)_new=R(b)*(1-alpha)+R(a)*alpha;
G(b)_new=G(b)*(1-alpha)+G(a)*alpha;
B(b)_new=B(b)*(1-alpha)+B(a)*alpha;
3.实现窗体透明显示面临的问题
经过这样合成之后,就可以获得B透明显示于A,即可以看到A又可以看到B的效果。
但是这里其实也暗示了一个问题:
透明的图片B是在A的基础上显示的,即是在A显示之后再处理B,所以考虑一下我们下面要讨论的透明窗体:
[1].窗体要透明,则必须总是在不透明的窗体之后绘制,不然就会被其它窗体挡住了,这是窗体Z序的问题。
[2].透明的窗体不会对一般窗体构成遮挡关系,这是窗体剪切计算时的问题.
下面我们就将讨论一下UCGUI中如何利透明显示的知道实现透明窗体.
二.UCGUI中透明窗体支持。
1.UCGUI中窗体的Z序.
为了帮助理解透明窗体在剪切时的处理,这里有必要介绍一下UCGUI中z序的知识.有的朋友以为UCGUI中没有Z序,其实在窗体的最基本的结构WM_Obj当中,就包含了Z序:
typedefstruct{
GUI_RECTRect;
/*outerdimensionsofwindow*/
GUI_RECTInvalidRect;
/*invalidrectangle*/
WM_CALLBACK*cb;
/*ptrtonotificationcallback*/
WM_HWINhNextLin;
/*Nextwindowinlinearlist*/
WM_HWINhParent;
WM_HWINhFirstChild;
WM_HWINhNext;
U16Status;
/*Somestatusflags*/
}WM_Obj;
hNextLin----------所有窗体的链表指针,将UCGUI中所有的窗体形成一个键表,便于查找窗体。
hNext-------------兄弟窗体的链表指针,这个成员其实就表示了兄弟窗体的Z序关系,hNext所指窗体Z序高.
hParent-----------父窗体指体指针,父窗体被子孙窗体剪切.
hFirstChild-------第一个子窗体指针,用于快速查找窗体的所有子窗体.
Status------------窗体属性,如透明窗体/窗体是否可称动等.
Z序-----按照通行的解释,就是除平面的X/Y轴,抽象出来表示窗体层次关系的Z轴,沿着Z轴Z序增高,Z序高的窗体挡住Z序低的窗体.
注:
依我理解,表达更详细一点以及加深理解,可以把Z序理解成多层概念:
[1].兄弟窗体之间,Z序高的窗体高于Z序低的窗体的所有子孙窗体.
[2].父子窗体之间,子孙窗体Z序高于父窗体,但子孙窗体的区域不能超过父窗体.
根据UCGUI中的这个Z序,在剪切计算时如下的剪切规则:
[1].窗体被hNext之下的兄弟窗体剪切,以及被其父窗体的hNext之下兄弟窗体剪切,递归处理.
[2].窗体被子窗体剪切,注意只被第一级子窗体剪切[没有必要处理孙辈窗体,他们的区域被父窗体包含].
[3].子窗体不能超出父窗体区域.
2.UCGUI中透明窗体的具体支持.
UCGUI中实现的透明,是完全的透明,意即透明窗体相对于其它一般窗体完全不可见,这种完全不可见的的就是在剪切处理当中实现的,UCGUI中处理剪切时,透明窗体不会对其它一般窗体构成遮挡关系,无论是比其Z序高还是序低的窗体。
在UCGUI中实现透明窗体,必须指定如下两个属性:
WM_CF_HASTRANS-----透明属性
WM_CF_STAYONTOP----始终为UCGUI中同一级兄弟窗体中z序最高的窗体,以最后指定该属性的窗体Z序最高.
[1].WM_CF_HASTRANS属性是透明窗体的基本属性,相关窗体的剪切处理部分,凡是指定了这个属性的窗体,在UCGUI中的剪切计算时,不会对其它窗体形成剪切关系;
[2].透明窗体会在其它Z序低的窗体重绘后,重绘透明窗体,以保证透明窗体不会被挡住。
[3].指定透明窗体WM_CF_STAYONTOP属性,是为了实现透明窗体居于一般窗体的前台,这样透明窗体才不会被一般窗体挡住,保持透明的效果.
[4].因为WM_CF_STAYONTOP属性是相对于同一层级兄弟窗体的,因此透明窗体也是相对于同一层级的兄弟窗体。
3.UCGUI中透明窗体的实现原理.
[1].剪切处理时的支持.
关于剪切计算,是UCGUI中比较难理解的地方,我这里仅仅指出剪切处理时,透明窗体不会对一般窗体构成剪切的地方。
UCGUI390版的剪切计算有三个主要函数_Findy1()/_Findx0()/_Findx1(),这三个函数分别是找出一个剪切矩形的x0/x1/y1点,y0点是已知的.查看这几个函数可以知道,在处理剪切时,首先会判断窗体的透明属性,如果是透明窗体,就再查找透明窗体的所有子窗体。
[2].画窗体时的支持.
透明窗体是不会变成无效窗体的,它的重绘都是其它窗体的重绘引起的,这样处理对于效率是有帮助的.在画窗体时,主要查看voidWM__PaintWinAndOverlays(WM_PAINTINFO*pInfo);
这个函数是处理窗体得绘的,它在处理完每个窗体的重绘之后会调用两个函数,这两个函数作用如下:
if(WM__TransWindowCnt!
=0){
_PaintTransChildren(pWin);
/*Drawalltransparentchildren*/
_PaintTransTopSiblings(hWin,pWin);
/*Drawalltransparenttoplevelsiblings*/
}
_PaintTransChildren()-------重绘刚才绘制窗体的所有透明子窗体,保证透明窗体显示在其上层。
_PaintTransTopSiblings()----重绘刚才绘制窗体之上的所有透明窗体,保证位于其上的透明窗体显示在上层。
[注:
位于一个窗体之上的窗体,包括其hNext之下的兄弟窗体,以及位于其父辈窗体的hNext之下的兄弟窗体]
[3].UCGUI为了支持透明窗体,已经将窗体绘制与剪切处理复杂处理了,而且还必须处理因为一般窗体重绘而引起透明窗体的重绘(当有相交区域时),因此透明窗体比起一般窗体在效率下是比较低下的.
4.如何增加UCGUI中透明窗体的透明度支持.
综上分析,UCGUI中已经实现了透明窗体所须的各种属性,如此我们所需要做的工作就非常的简单了,仅仅须要提供2D层次实际绘图的透明处理即可,UCGUI中2D图形库是所有绘图的基础,它自己的基础则是更下一层的驱动级的绘点函数,所以仅须实现绘点函数的透明处理,就实现了UCGUI中的透明窗体支持。
以下以模拟器中的处理透明,来说明透明窗体支持(如果是在真实硬件下,其改动也类似,仅须提供相应的Alpah画点函数),改动如下:
[1].增加一个全局变量g_AlphaValue,用于记录当前绘图透明度。
[2].增加设置/获取Alpha透明度的函数SetAlpha()/GetAlpha(),进行透明绘图时SetAlpha(60),完成透明绘图后恢复SetAlpha(0);
[3].增加一个带透明处理的绘点函数LCDSIM_SetPixelIndexAlpha().
透明效果图如下:
[示例是UCGUI390T版提供的示例XEye.c]
在透明窗体当中,处理绘图时要增加透明度的设置,如下:
caseWM_PAINT:
State.x-=WM_GetWindowOrgX(hWin);
State.y-=WM_GetWindowOrgY(hWin);
SetAlpha(60);
//设置要绘图的透明度60%.
GUI_SetBkColor(GUI_BLUE);
GUI_Clear();
_DrawEye(EYE_X1,EYE_Y,EYE_RX,EYE_RY,State.x,State.y);
_DrawEye(EYE_X2,EYE_Y,EYE_RX,EYE_RY,State.x,State.y);
SetAlpha(0);
//恢复透明度为0,即以下绘图不再进行透明处理.
[特别注意:
透明窗体当中的绘制操作,会进行叠加透明处理,因此绘图时要注意相同区域的反复绘画]
5.具体的代码修改说明.
代码改动有三处地方,涉及两个文件LCDWin.c及LCDSim.c,主要是绘点宏定义的更改以及设置透明度的增加,具体的代码改动如下:
[1].在模拟器的LCDWin.c当中,增加如下代码:
//houhh20061211...
unsignedg_AlphaValue=0;
voidSetAlpha(unsignedalpha);
voidSetAlpha(unsignedalpha)
{
g_AlphaValue=alpha*256/100;
[2].在LCDWin.c当中,修改SETPIXEL画点的宏定义成如下:
#ifdef_DEBUG
staticint_CheckBound(unsignedintc){
unsignedintNumColors=LCD_BITSPERPIXEL>
8?
0xffff:
(1<
<
LCD_BITSPERPIXEL)-1;
if(c>
NumColors){
GUI_DEBUG_ERROROUT("
LCDWin:
:
SETPIXEL:
parametersoutofbounds"
);
return1;
}
return0;
/*2006-12-1113:
36:
31
#defineSETPIXEL(x,y,c)\
if(!
_CheckBound(c)){\
LCDSIM_SetPixelIndex(x,y,c,LCD_DISPLAY_INDEX);
\
}*/
#defineSETPIXEL(x,y,c)if(!
_CheckBound(c)){\
if(g_AlphaValue==0){\
LCDSIM_SetPixelIndex(x,y,c,LCD_DISPLAY_INDEX);
}\
else{\
LCDSIM_SetPixelIndexAlpha(x,y,c,LCD_DISPLAY_INDEX,g_AlphaValue);
\
}\
#else
//#defineSETPIXEL(x,y,c)LCDSIM_SetPixelIndex(x,y,c,LCD_DISPLAY_INDEX)
#defineSETPIXEL(x,y,c)if(g_AlphaValue==0){\
else{\
LCDSIM_SetPixelIndexAlpha(x,y,c,LCD_DISPLAY_INDEX,g_AlphaValue);
#endif
[3].在LCDSim.c文件中,增加如下代码,相应在LCDSim.h中增加如下LCDSIM_SetPixelIndexAlpha()函数的声明:
/*********************************************************************
*LCDSIM_SetPixelIndexAlpha
*/
//可参考LCD_MixColors256.c中的LCD_MixColors256()函数.
voidLCDSIM_SetPixelIndexAlpha(intx,inty,intIndex,intLayerIndex,unsignedAlpha){
RETURN_IF_NOT_INITIALIZED(;
#ifdef_DEBUG
_CheckBreak(x,y,LayerIndex);
#endif
ASSERT(x>
=0);
ASSERT(x<
_aVXSize[LayerIndex]);
ASSERT(y>
ASSERT(y<
_aVYSize[LayerIndex]);
if(_aBPP[LayerIndex]<
=8){
U32Color2,Color1;
Color1=LCD_Index2Color(Index);
Color2=LCDSIM_GetPixelColor(x,y,LayerIndex);
Color1=LCD_MixColors256(Color2,Color1,Alpha);
Index=LCD_Color2Index(Color1);
*XY2PTR(x,y,LayerIndex)=Index;
}else{
U32Index32=_ColorIndex2COLORREF(Index,LayerIndex);
Index32=LCD_MixColors256(LCDSIM_GetPixelColor(x,y,LayerIndex),Index32,Alpha);
*XY2PTR_DWORD(x,y,LayerIndex)=Index32;
MARK_MODIFIED(LayerIndex);
三.MemDev下实现透明窗体的问题
如果一般窗体创建时指定了WM_CF_MEMDEV属性,则实现透明窗体与上面有很大的不同,下面详细谈谈其原因.
1.首先必须明白,MemDev当中的绘图操作是针对一块分配的内存(对应屏幕一块矩形区域),所以绘图过程中不会对屏幕产生影响(避免了闪烁),只是在绘图完成之后,然后才将此块内存区域整块的复制到屏幕上,因此用户看到的就是一次屏幕更新,但实际上绘图时是经过多个基本绘图操作组合的.
2.窗体有WM_CF_MEMDEV属性后,则窗体上的绘图操将在内存当中进行,此块区域大小等于窗口大小,当然窗体重绘完成后就将此块区域复制到窗体在屏幕上的区域,因此的窗体绘制是调用的MemDev当中的基本绘图操作,所以必须更改这些绘图操作,使其支持透明绘制.
3.内存设备当中,支持1/8/16位三种类型(即内存中每个点所占的位数),其中实际显存中象素等于或小于8位的,均在内存当中用八位表示一个点,其实8/16这两种类型是一样的,仅仅是宏定义中的一些数据类型不一样(如定义象素点的数据类型为char或short),所以其代码是共用的.对于单色的情况,没有透明显示,所以我们仅须处理8位的MemDev当中的基本绘图透明支持即可.
4.主要的修改集中在GUIDEV_8.c当中,分别是_SetPixelIndex()/_FillRect()/_DrawVLine()等几个函数的透明化支持:
_SetPixelIndex()---------绘点.
_FillRect()--------------填充矩形(UCGUI中采取的是GUI_memset()赋值,因此这对于透明支持显然不行,因为透明支持必须逐点处理,取出每个点的颜色来处理,所以如此赋值达不到透明效果,必须更改为逐点画,这样做效率是比较低的).
_DrawVLine()-------------竖直线
_DrawHLine()-------------水平线(调用矩形填充).
_DrawBitmap()------------位图(要处理1/2/4/8/16这几种情况的位图).
_FillRect()在MemDev中的加速处理,与透明化支持相背的,所以必须降低效率变填充为逐点画才行]
5.具体的代码修改.
这里不再详细的说明代码修改,要改的地方已经都在第4点中列出,这时只略提几处改的地方.
[1].增加一个函数,用来将指定内存的点转换成透明处理后的颜色索引.
*GetAlphaColor
//houhh20061217...
externunsignedGetAlpha();
staticPIXELINDEXGetAlphaColor(PIXELINDEX*pData,intindex)
LCD_COLORColor1,Color2;
intAlpha=GetAlpha();
if(Alpha!
=0){
Color1=LCD_Index2Color(index);
Color2=LCD_Index2Color(*(pData));
Color2=LCD_MixColors256(Color1,Color2,Alpha);
return(PIXELINDEX)LCD_Color2Index(Color2);
else
returnindex;
[2].矩形填充,有一处修改如下:
/*Fill*/
/*2006-12-1816:
21:
03
#ifBITSPERPIXEL==8
GUI_MEMSET(pData,LCD_COLORINDEX,Len);
#elifBITSPERPIXEL==16
GUI__memset16(pData,LCD_COLORINDEX,Len);
#else
#errorUnsupported
#endif*/
intx=x0;
//houhh20061218...
for(;
x0<
=x1;
x0++){
pData=_XY2PTR(x0,y0);
*pData=GetAlphaColor(pData,LCD_COLORINDEX);
}
x0=x;
[3].画点函数,仅仅修改了一句,将颜色索引进行透明处理即可,其它的几个位图函数以及画线函数,基本都是类似这个的修改,仅仅修改一句代码即可.
*_SetPixelIndex
staticvoid_SetPixelIndex(intx,inty,intIndex){
GUI_MEMDEV*pDev=GUI_MEMDEV_H2P(GUI_Context.hDevData);
GUI_USAGE_hhUsage=pDev->
hUsage;
PIXELINDEX*pData=_XY2PTR(x,y);
//*pData=Index;
*pData=GetAlphaColor(pData,Index);
;
if(hUsage){
GUI_USAGE_AddPixel(GUI_USAGE_H2P(hUsage),x,y);
四.透明窗体是否仅绘图时进行透明处理即可?
特别把这一点拿出来单独的讲,是为了更强调这个问题,有些朋友会问,既然如上面所说,将绘图操作进行了透明处理,他们就这样理解:
"
窗体的透明设置我觉得可以对cb回调函数中的“WM_PAINT:
”进行相应的透明绘图,且不让它填充矩形框及颜色,那它就会显示透明了。
针对这种想法,可以提出几个问题,如果这几个问题都能回答,那么上面的说明才是可行,否则断不能行,WM_CF_HASTRANS属性必不可少.
[关键词:
我们称要实现透明的窗体为WIN_Trans]
1.首先指出一点,对于没指定WM_CF_HASTRANS属性的WIN_Trans窗体,是可以变成无效窗体,从而在DrawNext()当中调用窗体的重绘的,这与带WM_CF_HASTRANS属性的窗体的重绘是由其它窗体重绘而引发是截然不同的(此时总是在一般窗体绘制之后进行透明窗体绘制).
2.对于非指定WM_CF_HASTRANS属性的WIN_Trans窗体,进行绘制后如果慢慢拖动窗体的话,窗体内的原来绘画没有清理将会残留下来,简单的现象就是如果显示一些文字后拖动窗体,可以看到窗体上残留了文字的颜色(这个残留是先前窗体的绘制没被清理,此残留区域在移动前与移动后还包含在窗体内,所以未被清除而残留).
3.对于非指定WM_CF_HASTRANS属性的WIN_Trans窗体,当拖动其它窗体与本窗体产生相交的区域后,WIN_Trans窗体会进行重绘,如果不进行清除操作,那么就会残留下原来窗体的相交区域(当相交窗体移走后).
4.如果给WIN_Trans窗体加上WM_CF_STAYONTOP属性,如果其它窗体移动时会看到在WIN_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- UCGUI 中的 实现 透明 窗体 原理
![提示](https://static.bdocx.com/images/bang_tan.gif)