在VB中制作调色板动画

邮编:100085 北京2855信箱41分箱 王秀英


有时,我们在利用程序制作一些动画时,其实屏幕上的画面本身并没有改变,如闪烁的彩灯,这时虽然也可以通过保存多幅画面,然后再连续播放这些画面来表现动态效果,但Windows给我们提供了更简便的方法,即:调色搬动画,它利用对系统调色板的直接访问,可以实现“对显示的位图没有真正改变”的动画的制作。这种方法适合于颜色周期变化的动画,使用这种技术即使没有使用更多的内部资源和多帧动画制作方法,也可以模仿流水、天气现象、光线变化,甚至运动的物体等等,从而创造出运动的视觉效果。

实现调色板动画主要有以下几个步骤:

1.创建自己定义的逻辑调色板;

2.将这个自定义的逻辑调色板选入要进行操作的设备环境中;

3.在这个设备环境中利用逻辑调色板中的颜色来绘制图形;

4.周期性地改变逻辑调色板中的颜色值,并使其立即反映到系统调色板中。


进行上面的操作,要用到以下的API函数、数据结构以及常数:

API函数有:

CreatePalette:创建一个逻辑调色板,并返回该调色板的句柄;

SelectPalette:将一个逻辑调色板选入一个设备环境中;

RealizePalette:将新选入到设备环境中的调色板映射到系统调色板中;

AnimatePalette:不仅改变逻辑调色板中的颜色,还直接改变系统调色板的颜色,所以每次改变所选的颜色,不必调用RealizePalette函数。


数据结构:

Type PALETTEENTRY

peRed As Byte

peGreen As Byte

peBlue As Byte

peFlags As Byte

End Type

该结构用来定义调色板项,前三个字段分别设置红、绿、兰三原色的值,取值为0~255;最后一个字段为一个标志位,取值为Windows定义的常数,见下面的常数部分。


Type LOGPALETTE

palVersion As Integer

palNumEntries As Integer

palPalEntry(4) As PALETTEENTRY

End Type

该结构用来定义逻辑调色板。其中第一个字段包含一个常数,为十六进制的300,表示为&H300;第二个字段指定新调色板中的调色板项的数量;第三个字段是PALETTEENTRY结构的一个数组。


常数:

Const PC_RESERVED = &H1

该常数的含义为:调色板中只有标记为PC_RESERVED的项才能被AnimatePalette函数修改,该标记还禁止其它窗口将它们的逻辑调色板映射到保留的颜色项,这将把颜色变化的影响限制在活动窗口中。


下面具体介绍在VB中实现调色板动画的方法,如下:

在VB中新建一个工程,在其默认的Form1窗体上放两个CommandButton控件,分别将起Name属性设为CmdStart和CmdEnd;放一个Picture控件,将其Name属性设为Pict1,将其FillStyle属性设为0;放一个Timer控件,将其Interval属性设为1000,Enabled属性设为False,然后将下面代码放入窗体的代码窗口中:


Option Explicit


Private Declare Function SelectPalette Lib "gdi32" (ByVal hdc As Long, ByVal hPalette As Long, ByVal bForceBackground As Long) As Long

Private Declare Function CreatePalette Lib "gdi32" (lpLogPalette As LOGPALETTE) As Long

Private Declare Function RealizePalette Lib "gdi32" (ByVal hdc As Long) As Long

Private Declare Function AnimatePalette Lib "gdi32" (ByVal hPalette As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteColors As PALETTEENTRY) As Long


Private Type PALETTEENTRY

peRed As Byte

peGreen As Byte

peBlue As Byte

peFlags As Byte

End Type


Private Type LOGPALETTE

palVersion As Integer

palNumEntries As Integer

palPalEntry(4) As PALETTEENTRY

End Type


Private Const PC_RESERVED = &H1


Private m_hCurrentPal As Long '定义调色板句柄

Dim newPal As LOGPALETTE '定义逻辑调色板


Private Sub CmdEnd_Click()

Timer1.Enabled = False

Unload Me

End Sub


Private Sub CmdStart_Click()

Timer1.Enabled = True

End Sub


Private Sub Form_Load() '在窗体加载时,给逻辑调色板赋值并创建这个逻辑调色板

newPal.palVersion = &H300

newPal.palNumEntries = 4


newPal.palPalEntry(0).peRed = &HFF

newPal.palPalEntry(0).peGreen = &H0

newPal.palPalEntry(0).peBlue = &H0

newPal.palPalEntry(0).peFlags = PC_RESERVED


newPal.palPalEntry(1).peRed = &H0

newPal.palPalEntry(1).peGreen = &HFF

newPal.palPalEntry(1).peBlue = &H0

newPal.palPalEntry(1).peFlags = PC_RESERVED


newPal.palPalEntry(2).peRed = &H0

newPal.palPalEntry(2).peGreen = &H0

newPal.palPalEntry(2).peBlue = &HFF

newPal.palPalEntry(2).peFlags = PC_RESERVED


m_hCurrentPal = CreatePalette(newPal)

End Sub


Private Sub Pict1_Paint()

Dim Dummy As Long

Dim iCount As Integer

Dim X As Integer, Y As Integer


Dummy = SelectPalette(Pict1.hdc, m_hCurrentPal, False)'将自己定义的逻辑调色板选 '入Pict1的设备环境中

Dummy = RealizePalette(Pict1.hdc) '实现这个新选入的逻辑调色板,即将其映射到

'系统调色板上


X = -35: Y = Pict1.ScaleHeight / 2


For iCount = 0 To 2 '画出红、绿、兰三个圆

X = X + (Pict1.ScaleWidth - 10) / 3

Pict1.FillColor = &H1000000 Or iCount '将颜色的最高位设为1表示最后两位数是调色

'板的索引号,而不是红颜色的数值,这样就会使用索引号指定的调色板项的颜色。

Pict1.Circle (X, Y), (Pict1.ScaleWidth - 70) / 6, &H1000000 Or iCount

Next iCount

End Sub


Private Sub Timer1_Timer() '该事件每隔1秒钟触发一次

Dim iCount As Integer


For iCount = 3 To 1 Step -1 '将逻辑调色板中的颜色循环移动

newPal.palPalEntry(iCount).peRed = newPal.palPalEntry(iCount - 1).peRed

newPal.palPalEntry(iCount).peGreen = newPal.palPalEntry(iCount - 1).peGreen

newPal.palPalEntry(iCount).peBlue = newPal.palPalEntry(iCount - 1).peBlue

Next iCount

newPal.palPalEntry(0).peRed = newPal.palPalEntry(3).peRed

newPal.palPalEntry(0).peGreen = newPal.palPalEntry(3).peGreen

newPal.palPalEntry(0).peBlue = newPal.palPalEntry(3).peBlue


AnimatePalette m_hCurrentPal, 0, 3, newPal.palPalEntry(0) '立刻将逻辑调色板的变化反映到系统调色板中。


End Sub


上例中如果将各个圆组成一个连续的首尾相接的图形,例如:由圆组成的矩形,则会呈现更加明显的动态效果。读者可以通过修改Pict1_Paint事件中的代码来绘制自己需要的图案。本程序中仅仅是绘制了红、绿、兰三个圆,图案比较简单,旨在说明制作调色板动画的过程。


另外还有一点值得提出:直接从Visual Basic 5.0提供的API查看器中拷贝的AnimatePalette函数的声明有误,运行时会出现“找不到该函数的动态库入口点”的错误,请去掉声明中的Alias子句。在VB提供的API函数声明中,只有用字符串作参数的函数才使用Alias子句,以区别字符串的编码方式(ANSI码还是UNICODE码),而AnimatePalette函数并没有使用字符串作为参数,所以不需要Alias子句的辅助说明。


本程序在Windows 95操作系统上VB5.0开发环境中调试通过。