Powerbuilder中利用API实现动画特效_1

Powerbuilder中利用API实现动画特效_1,第1张

API函数在Powerbuilder下的声明如下:

1〕 function uint GetDC(uint hwnd) library "c:\windows\system\user32.dll"//取得一个显示器设备描述表。参数hwnd标识将绘图的窗口的句柄。若成功,则返回指定窗口的设备描述表,若失败,则返回为NULL。

2〕 function long BitBlt(uint hdcdest,int xdest,int ydest,int wdest,int hdest,uint hdcsrc,int xsrc,int ysrc,ulong dwrop) library "c:\windows\system\gdi32.dll"//将源设备描述表中的图片转移到目的设备描述表中。参数hdcdest标识图象转移的目的DC,xdest和ydest标识目的DC的位置,wdest和hdest标识图象的宽度与高度,hwndsrc标识图象转移的来源DC,xsrc和ysrc标识来源DC的位置,dwrop标识图象转移方式。若成功返回值为0,若失败返回值为非零。

3〕 function long StretchBlt(uint hddest,int xdest,int ydest,int wdest,int hdest,uint hdsrc,int xsrc,int ysrc,int wsrc,int hsrc,ulong dwrop) library "c:\windows\system\gdi32.dll"//将源设备描述表中的图片放大、缩小、翻转、转移到目的设备描述表中。参数意义同BitBlt中的参数意义相同,多出的wsrc和hsrc为来源图象的宽度与高度。

4〕 function ulong ReleaseDC(ulong hwnd,ulong hdc) library "c:\windows\system\user32.dll" //将由GetDC取得的设备描述表释放掉。参数hwnd标识窗口,hdc标识ReleaseDC将释放的设备描述表,若释放成功则返回1,若释放失败则返回0。

5〕 function ulong CreateCompatibleDC(ulong hdc) library "c:\windows\system\gdi32.dll"//创建一个与hdc兼容的内存设备描述表。参数hdc标识设备描述表。若创建成功,则返回内存设备描述表,若创建失败,则返回为NULL。

6〕 function ulong DeleteDC(ulong hdc) library "c:\windows\system\gdi32.dll"//将由CreateCompatibleDC建立的DC释放掉。参数hdc为设备描述表的句柄。若成功则返回值为非零,若失败则返回值为0。

7〕 function ulong SelectObject(ulong hdc ,ulong hobject) library "c:\windows\system\gdi32.dll"//将一个已建立好的对象选入到指定的设备描述表中。参数hdc标识DC的句柄,hobject为对象的句柄。返回值为DC之中前一个同类型对象的句柄。

8〕 function ulong DeleteObject(ulong hobject) library "c:\windows\system\gdi32.dll"//删除一个位图、花色对象。参数 hobject为对象的句柄。若成功则返回值为非零,若失败则返回值为0。

9〕 function ulong LoadImageA(ulong hintance, ref string filename,uint utype,int width,int height,uint fload) library "c:\windows\system\user32.dll"//装入一个位图、图标、光标。参数hintance为装有图象的实例的句柄,若装入一OEM图象,此参数置为0,filename为图象的名字或定义,utype为装入图象的类型,width和height为装入时希望的图象的宽度与高度,fload为装入时的标志。若成功,返回值为最近装入图象的句柄,若失败,返回值为NULL。

四、设计举例

笔者设计的动画特效包括图片的逐渐放大和图片的翻转两大功能。

我们在窗口上放一个tab控件,在tab控件上分图象放大与图象翻转两个tab标签页。

在图象放大tab标签页,有一单行编辑器〔显示选择图片的路径与名称〕、一个picture控件、一个选择图片按钮〔用于选择显示的图片〕,另外就是从左上向右下、从左下向右上、从右上向左下、从右下向左上、从左向右、从右向左、从上向下、从下向上、从中央向四周九个功能按钮。

在图片翻转tab标签页上,有三个单行编辑器〔显示选择的背景图片、正面图片、背面图片的路径与名称〕、一个选择背景图片按钮、一个选择正面图片按钮、一个选择背面图片按钮、一个picture控件、一个翻转按钮。

在这里假定窗口上picture控件的宽为width,高为height。

1. 图片逐渐放大

将要显示的图片从小到大依次延迟复制到picture控件中,直到占据整个控件为止。

以从左上角向右下角放大为例:先将要显示的图片放入内存DC(设备环境)中,再依次延时将尺寸为1/8 width *1/8 height,2/8 width *2/8 height,3/8 width *3/8 height,4/8 width *4/8 height,5/8 width *5/8 height,6/8 width *6/8 height,7/8 width *7/8 height,整个控件大小的8幅图片复制到picture控件DC中即可。代码如下:

int i,i1,dx,dy,pixelwidth,pixelheight,xz,yz,div,mode

uint hdc,hpicture

ulong scrcopy,hmdc

string picname

div=8//图片描绘的次数

mode=16//代表从指定的文件装入图片

p_2.picturename=""

picname=trim(sle_1.text)//sle_1.text中为要显示的图片的文件名

scrcopy=13369376//代表图片转移时的 *** 作方式为覆盖

pixelwidth=UnitsToPixels(p_2.width,XUnitsToPixels!)//将picture控件在pb下的宽度转换为以象素为单位的宽度

pixelheight=UnitsToPixels(p_2.height,yUnitsToPixels!)// 将picture控件在pb下的高度转换为以象素为单位的高度

dx=pixelwidth/div

dy=pixelheight/div

hdc=GetDC(handle(p_2))//取得p_2控件的DC

hpicture=LoadImageA(0,picname,0,pixelwidth,pixelheight,mode)//将图片以宽度pixelwidth高度pixelheight的尺寸装入内存

hmdc=CreateCompatibleDC(hdc)//创建与hdc兼容的内存设备描述表hmdc

SelectObject(hmdc,hpicture)//将位图对象选入hmdc

for i=1 to div

xz=0

yz=0

StretchBlt(hdc,xz,yz,dx*i,dy*i,hmdc,0,0,pixelwidth,pixelheight,scrcopy)//将左上角坐标为〔0,0〕,宽度为pixelwidth,高度为pixelheight的hmdc的图象转移到左上角坐标为〔xz,yz〕宽度为dx*I, 高度为dy*I的hdc中

for i1=1 to 20000//用于延迟时间

next

next

ReleaseDC(0,hdc)

DeleteDC(hmdc)

DeleteObject(hpicture)

p_2.picturename=picname//注意此句可防止点击图片时,图象从picture控件中消失

其它几种放大方式与此类似,只要注意改变源设备描述表中图象的左上角的坐标、高度、宽度即可。限于篇幅,在此省略。

2. 图片翻转特效

1)将背景图片放入内存DC(hmdc)中,正面图片放入内存DC(hmdc1)中,依次将正面图片以大小为整个控件、7/8 width *7/8 height,6/8 width *6/8 height,5/8 width *5/8 height,4/8 width*4/8 height,3/8 width *3/8 height,2/8 width *2/8 height,1/8 width *1/8 height、零尺寸覆盖到存放背景图片的hmdc中,再从hmdc中复制到picture控件DC中。

2) 将背景图片放入内存DC(hmdc)中,背面图片放入内存DC(hmdc1)中,依次将背面图片以大小为零、1/8 width *1/8 height,2/8 width *2/8 height,3/8 width *3/8 height,4/8 width *4/8 height,5/8 width *5/8 height,6/8 width *6/8 height,7/8 width *7/8 height,整个控件的尺寸覆盖到存放背景图片的hmdc中,再从hmdc中复制到picture控件DC中。

代码如下:

int i,i1,dx,dy,pixelwidth,pixelheight,xz,yz,div,mode,diff

uint hdc,hpicture,hback

ulong scrcopy,hmdc,hmdc1

string picname,picname1,back

div=8

mode=16

p_1.picturename=""

picname=trim(sle_3.text) //sle_3.text中为正面图片的文件名

picname1=trim(sle_4.text) //sle_4.text中为背面图片的文件名

back=trim(sle_2.text) //sle_2.text中为背景图片的文件名

scrcopy=13369376

pixelwidth=UnitsToPixels(p_1.width,XUnitsToPixels!)

pixelheight=UnitsToPixels(p_1.height,yUnitsToPixels!)

dx=pixelwidth/div

dy=pixelheight/div

hdc=GetDC(handle(p_1))

hpicture=LoadImageA(0,picname,0,pixelwidth,pixelheight,mode)// 装入正面图片

hmdc=CreateCompatibleDC(hdc)

SelectObject(hmdc,hpicture)

diff=dx/2

for i=0 to div

hback=LoadImageA(0,back,0,pixelwidth,pixelheight,mode)//装入背景图片 hmdc1=CreateCompatibleDC(hdc)

SelectObject(hmdc1,hback)

StretchBlt(hmdc1,diff*i,0,pixelwidth,diff*i*2,pixelheight,hmdc,0,0,pixelwidth,pixelheight, scrcopy)//将正面图片与背景图片在背景图片DC中进行"复制" *** 作

BitBlt(hdc,0,0,pixelwidth,pixelheight,hmdc1,0,0, scrcopy)//将hmdc1中的合成图片转移到picture控件的hdc中

DeleteDC(hmdc1)

DeleteObject(hback)

for i1=1 to 15000

next

next

DeleteDC(hmdc)

DeleteObject(hpicture)

hpicture=LoadImageA(0,picname1,0,pixelwidth,pixelheight,mode)// 装入背面图片

hmdc=CreateCompatibleDC(hdc)

SelectObject(hmdc,hpicture)

for i=div to 0 step -1

hback=LoadImageA(0,back,0,pixelwidth,pixelheight,mode)

hmdc1=CreateCompatibleDC(hdc)

SelectObject(hmdc1,hback)

StretchBlt(hmdc1,diff*i,0,pixelwidth,diff*i*2,pixelheight,hmdc,0,0,pixelwidth,pixelheight, scrcopy) //将背面图片与背景图片在背景图片Dc中进行"与复制" *** 作

BitBlt(hdc,0,0,pixelwidth,pixelheight,hmdc1,0,0, scrcopy) //将hmdc1中的合成图片转移到picture控件的hdc中

DeleteDC(hmdc1)

DeleteObject(hback)

for i1=1 to 15000

next

next

DeleteDC(hmdc)

DeleteObject(hpicture)

ReleaseDC(0,hdc)

p_1.picturename=picname1

曾经在一些书上看到用C语言实现动态菜单的方法 需要调用大量的API函数 但是这里我想换一种方法 借助PowerBuilder提供的属性和递归算法实现动态菜单的创建过程 需要指出的是 这里讨论的动态菜单是已经在外部数据源中定义好菜单结构 而菜单对象没有有任何菜单项 需要由程序生成各个定义好的菜单项

一 定义菜单数据结构

实现动态菜单 首先设计合理的菜单数据结构 其数据源可以是任何DBMS 甚至可以是TXT文本文件(只要能建立好合理的分层结构)

菜单如同一个树形控件 有着分层的顺序结构 所以在定义数据结构时 应当选择一种能够形象地表示父子 兄弟关系的模型 而能够最好反映菜单结构的控件就是树形控件 treeview 并且定义按照二位递进的数据结构形式 即 以级别确定层数 以序号确定兄弟关系 以二位递进确定父子关系 例如 如图所示的菜单的对应数据结构如下

这样的菜单结构 在建立菜单结构时 非常适合用递归的算法 那么我们可以按照树的遍历算法建立一个树形结构的菜单对象

接下来 定义菜单数据结构 菜单数据结构应当包含以下基本元素 菜单名 菜单类型 菜单序号 菜单项文本 菜单项id 菜单项的执行代码 菜单显示风格 如下表说明

二 动态创建菜单

流程图

流程说明

如上图 整个建立菜单的过程分成两部分 初始化菜单和设置菜单属性 初始化菜单即是以递归的算法从数据源中读取菜单数据 每读一个菜单项建立一个菜单项对象 利用powerbuilder中create方法一级一级建立菜单 首先定义一个菜单实例对象 这里的菜单是指主菜单 而不是d出菜单 由于而者的区别 对于d出菜单的处理在后面介绍 菜单建立的核心原理很简单 只有四句 创建菜单对象 挂接菜单项目 先隐藏后显示菜单对象 如下

 integer      ai_item_serial_no     //序号 作为递归的函数传入参数 menu    am_obj        //菜单对象 作为递归的函数传入参数  m_menu_item   lam_root       //菜单对象 m_menu_item是预先定义的一//个菜单对象 该对象没有一个菜单项 //创建菜单对象 lam_root item[ai_item_serial_no] = create m_menu_item    //将新建的菜单对象 挂接到已有菜单对象上  am_obj = lam_root item[ai_item_serial_no] //下面两句用于显示建立好的菜单 lam_root Hide()      //隐藏菜单对象  lam_root Show()      //显示菜单对象

将上面的语句放在一个递归过程中 就可以建立起整个的菜单结构        

在建立菜单的过程中需要得到菜单的itemid 该属性是用来捕获菜单响应动作的唯一标示 只有知道的菜单的itemid 才知道是触发了哪个菜单项的事件

得到菜单项itemid的方法 在不同系统经过反复测试之后 发现一个规律 父项菜单的itemid是从 开始依次递增 子项菜单的itemid是从 开始依次递增 由此按照递归算法 生成每层每个菜单项的itemid 并存入数据库中

设置菜单显示风格 是在菜单建立后设置三种显示风格 文字风格 图片风格 文字图片混合的显示方式 为了提高效率 在设置每个菜单风格时 不对所有父项菜单 不可视菜单项和没有定义显示图片的菜单项进行设置 因为文字风格是默认风格不必更改 这部分程序员主要用到三个API函数

Getsubmenu 用于得到指定菜单项的句柄 SetMenuItemBitmaps 用于设置文字显示风格或设置图片风格 两种情况的区别在于该函数的最后两位若为 则是去掉菜单项上的位图 最后两位若是图片句柄 则是在菜单项上添加位图 ModifyMenu 用于设置图片显示风格

经过反复测试 发现如果指定的显示图片名为 ***bmp 等不合法名称 则显示出的效果是一个分割符

在整个菜单建立过程 需要重点设计的是程序算法 数据存取的方式和出错控制

) 程序算法主要指递归算法 一般递归有两种算法 即FOR循环的方法和DO…while循环方法 两者都是循环算法 但是效率不同 建议用户根据自己的能力选择方法 切忌不能写成死循环 For循环的方式比较简单直观 循环控制遍历的次数 循环内再调用本身 实现递归调用 DO…while循环方法主要在循环内判断叶子或枝子(即父亲节点) 对叶子和枝子进行分别处理 内部也要调用本身 实现递归调用

) 选择合理安全的数据存取方式 对于稳定建立菜单也很重要 定义一个datastore(数据存储)对象 在初始化菜单时候 将从数据库中提取的所有数据存入该datastore对象 然后不再对数据库进行任何 *** 作 直到需要结束时将变更的菜单数据(如 itemid)以datastore的update形式提交数据库 在此之前所有需要从datastore得到的数据 用过滤的方式得到 即用setfilter()和filter()函数 一定要注意的是 按照结对编程的规则 在过滤并使用完datastore中数据后 一定再写一对过滤条件为空字符串的过滤 如下 setfilter( 条件 )filter()……处理过程……setfilter( )filter()

这样也可以将数据及时还原到初始状态 以便下一个模块调用

利用datastore 既可以保持在菜单建立期间的数据安全 不受数据库影响 又可以提高效率 省去对数据库的反复读写 *** 作

) 因为菜单的重要性 使得出错控制在菜单建立尤为重要 我们在递归建立菜单时 要考虑尽可能多的潜在错误 谁也不能保证数据库中的菜单结构数据不出错 虽然正确定义不是建立模块的事 尤其菜单的二位递进的分层数据结构 若有一处错误 可能导致整个建立过程失败 更糟糕的会发生程序异常退出 所以程序在设计出错处理时 应当考虑是终止进程 还是跳过错误的环节继续进行 我建议 在设计程序时应但兼具一定的冗余度和纠错能力 即遇到错误的数据能够根据环境修正为正确的值 对于可以忽略的一些小问题 为提高效率不作处理

需要指出的是 经过反复测试 发现对于菜单的属性 如果是字符类型则不能赋空值 如果没有应当是空字符串 如果是整数类型也不能赋空值 如果没有应当是某个缺省整数 否则程序会报异常错误 然后退出

由此可见 反复测试是非常重要的 不仅能发现语法错误和确保算法的正确 更能找出许多我们难以推断的错误

三 对d出菜单的特殊处理

由于d出菜单的对象定义和调用方式与主菜单的不同 需要进行一些特殊处理 首先定义一个菜单实例对象 该对象需有且只有一个根菜单 所有d出的菜单项都挂接在根菜单项后 要在窗口的鼠标右键事件中 调用d出菜单 而主菜单则在窗口初始化事件调用 调用d出菜单之前需要知道d出点的X Y坐标 然后用popmenu()函数显示出来

四 菜单响应事件的处理

由于菜单的响应事件在数据结构中定义好了 在建立菜单之后 用户点击某菜单时候 只需要获得菜单的句柄 就知道是触发了哪个菜单 而后在数据库中找到对应的事件定义 就可以开始执行动作了 重要的是句柄如何得到 菜单的句柄就是itemid 在菜单所在窗口定义一个自定义事件 ue_mouse_clicked EVENT_ID pbm_menuselect 此事件中有两个参数可用 itemid和flag itemid即被触发菜单对象的句柄 flag是对应于windows消息号的标志 当此标志不等于 时就是触发了菜单事件 所以我们可以定义一个实例变量 保存itemid 就可以调用菜单事件了 还有一个关键问题 何时触发事件ue_mouse_clicked呢 在用户定义的菜单实例对象的clicked事件中写以下代码 if  Isvalid(iw_win)  then  message StringParm = this is_ItemID   //将itemid作为消息传递 iw_win postEvent( ue_menuitemclicked ) //触发窗口事件 处理消息end ifiw_win 定义的窗口实例变量is_ItemID 用以保存菜单itemid的字符串类型的实例变量postEvent 是把响应处理放在菜单事件的最后 以免妨碍之前定义的动作

lishixinzhi/Article/program/SQL/201311/16396


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11662307.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-17
下一篇2023-05-17

发表评论

登录后才能评论

评论列表(0条)

    保存