|
当 alpha 为 0 时,你得到的是背景(图像完全透明);当 alpha 为 1 时,你得到非透明图像(完全不透明)。实际有透明效果的
alpha 值是一个 8 位的字节表示的值,范围从0-255,0 和 1 只是表示透明和非透明两个极端。它们都是可用的 alpha
值,但大多数应用程序不需要;多数应用程序使用一个常量 alpha
值来处理整个对象,如一幅图像。例如,你可能想让一幅特定的图像以25%的透明度显示。 逆风者
AlphaBlend 函数类似老的 BitBlt 和 StretchBlt,但它仅仅实现渐变。发音为“blit”,这个术语是从古老的
PDP-10 BLT (块转移)指令派生而来,这个指令用于将大块内存从一个位置转移到另一个位置。AlphaBlend 的细节如
Figure 1
所示,参数简单明了,但是用 AlphaBlend 来实现渐变很繁琐,因为只调用一次是不行的,必须重复调用来产生渐变效果,用一个定时器和
0-255 之间不同的 alpha 值来控制。
为了展示 AlphaBlend 实际的工作过程,我编写了一个程序 BlendView,该程序基于我的一个图像查看程序,参见 2002 年 3
月刊的专栏文章。BlendView 可以查看各种图像文件(BMP、JPG、GIF 以及其它任何 GDI
支持的格式),但是当你打开一幅新图像时,原来的图像会渐变成新图像,如 Figure 2 所示。

Figure 2 原图像

Figure 2 渐变的图像

Figure 2 最终的图像
为了将一幅图像渐变为另一幅,你需要两幅图像,当用户打开一个新文档时,MFC 要做的第一件事情是销毁旧的那个对象。所以你考虑在 MFC
加载新图像前将旧图像保存在某个地方。因为渐变效果概念上属于视图处理(绘制图像范畴),所以我把处理过程放在在视图(View)中。也就是说在视图中保存旧图像。但视图如何知道何时要保存图像呢?你当然得告诉它。幸运的是,CDocument
具备一个方法,你可以用它来随时通知视图发生了什么。这个方法就是 CDocument::UpdateAllViews: // in Doc.cpp:
BOOL CPictureDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
UpdateAllViews(NULL, PREOPENDOC, this);
return m_pict.Load(lpszPathName);
}
PREOPENDOC 是我自己的枚举代码,在 doc.h 中定义。当你调用 UpdateAllViews
时,将自己的“提示代码”(一个32位整数)随一个指针传递到“提示对象”,该对象可以是任何 CObject 派生的 MFC
类。这里我传的是文档本身。注意我是在加载新图像之前调用 UpdateAllViews,而旧图像仍然有效。视图处理通知消息保存该图像: void CPictureView::OnUpdate(CView* pSender,
LPARAM lHint, CObject* pHint)
{
if (lHint==CPictureDoc::PREOPENDOC) {
SaveDocImage((CPictureDoc*)pHint);
}
}
相同的 OnUpdate
函数处理所有文档的通知消息,所以你得检查发送了哪个通知消息。一般情况下,提示代码和提示对象背后的工作原理是文档以提示方式提供信息,告诉视图它需要更新屏幕的哪一部份。对于 CPictureView
来说,如果提示代码是 PREOPENDOC,那么 CPictureView则调用一个辅助函数 SaveDocImage
来保存当前图像。Figure 3 是 SaveDocImage
的代码,它创建一个位图和内存设备上下文(DC),然后在内存设备上下文中呈现图像,在文档摧毁原来图像后有效地进行渐变拷贝。
现在,当用户打开一个新文件,文档通知视图以及 OnUpdate 处理例程以位图形式保存图像。渐变是怎么做出来的呢?它需要重复调用 AlphaBlend
从老图像渐变成新图像。最显而易见的方法是设置一个定时器。假设你想用三秒来渐变。为了用 100 步来实现渐变,你可以将定时期设置成
3000/100=30毫秒。但问题是 AlphaBlend实际上花了大量的时间来处理渐变。而且,所花的时间依赖于图像的大小。较大的图像渐变的时间较长。如果你使用定时器来做,最后得到的幻灯效果是较小的图像更快,较大的图像更慢——可能不是你想要的结果。
本文章更多内容:<<上一页 - 1 - 2 - 3 - 4 - 下一页>> |