UCGUI中的实现透明窗体的原理Word文档格式.docx

上传人:b****8 文档编号:22271362 上传时间:2023-02-03 格式:DOCX 页数:15 大小:34.46KB
下载 相关 举报
UCGUI中的实现透明窗体的原理Word文档格式.docx_第1页
第1页 / 共15页
UCGUI中的实现透明窗体的原理Word文档格式.docx_第2页
第2页 / 共15页
UCGUI中的实现透明窗体的原理Word文档格式.docx_第3页
第3页 / 共15页
UCGUI中的实现透明窗体的原理Word文档格式.docx_第4页
第4页 / 共15页
UCGUI中的实现透明窗体的原理Word文档格式.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

UCGUI中的实现透明窗体的原理Word文档格式.docx

《UCGUI中的实现透明窗体的原理Word文档格式.docx》由会员分享,可在线阅读,更多相关《UCGUI中的实现透明窗体的原理Word文档格式.docx(15页珍藏版)》请在冰豆网上搜索。

UCGUI中的实现透明窗体的原理Word文档格式.docx

假设一张图片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_

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1