




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、动态创建菜单条2008年12月13日 星期六 1:41本文拟结合powerbuilder语言,简述如何实现动态添加菜单效果。在实际开发过程当中很多时候会因为权限控制的需要,根据用户的不同权限来动态添加菜单项目,如何避免使用繁琐的api函数(如:createmenu、insertmenu、insertmenuitem、appendmenu等),利用powerbuilder语言自身功能达到这一目的呢?本文将就此问题简单予以论述。一、基本思路在pb帮助的menu object一节当中,关于其properties描述当中有一项:item menu specifies the menu objects
2、under a menu object.这看似简单的一句话其实包含了三层含义:1、这句话说明menu对象有一个属性为数组类型,它其中的各个元素记录了其所有的具体子item项目,可以借助这个数组中各元素来访问底层的各子菜单;2、这些子item项目仍是menu类型,因此可以按照第一点的逻辑继续向下层推广,借助该子item的item属性可以进而访问其所属下层的第二层子菜单,推而广之,即可全面遍历整个菜单体系的所有子菜单项目;3、既然该属性是一个数组类型,那么就可以按照数组类型变量来处理,我们可以对其进行upperbound()、lowerbound()等函数操作,还可以进行数组的扩展,即添加新项目,
3、这一点很重要,它是我们整篇文章的核心,如何利用pb实现动态添加菜单,说白了就是添加这个数组元素(读者必须对此有一个清晰的认识),同时期间有一些配套具体的实现技巧,详见下文。二、具体实现(一)基本工作创建一个window窗口和二个menu菜单,其中一个菜单命名为m_main,用作窗口的基本主菜单,新增菜单将在其上添加,该菜单初始可以包含一些基本菜单,如:文件、添加、删除、保存、退出等;另外一个菜单命名为m_new,该菜单只有主菜单一个item,其下没有进一步的子菜单,因此该菜单其实就是一个菜单item。在主窗口中声明实例变量(instance variables):menu im_new /声明
4、一菜单数组用于引用新增菜单integer ii_count /声明一变量记录总共新增菜单个数(二)具体代码1、添加一级菜单功能的实现:/用途:在最后一项以及菜单之后新增一项一级菜单/时间:2003-6-1/integer li_itemcount /声明变量记录当前一级菜单总个数; /新创建一个菜单对象,并将其放到菜单数组im_new当中;ii_count+im_newii_count=create m_new/此处对新创建的菜单对象获取引用;li_itemcount=upperbound(m_main.item)m_main.itemli_itemcount + 1=im_newii_cou
5、nt.item1/下面是设置新生成菜单的text属性,这个属性可以从数据库中取,但此处省略简化掉了;m_main.itemli_itemcount + 1.text="新增一级-" + string(li_itemcount + 1)/下面是设置新生成菜单的tag属性,这个属性可以从数据库中取,但此处省略简化掉了;/通过这个tag可以当作功能号等来使用,通过gf_menumessage()函数来予以公共处理;/m_main.itemli_itemcount + 1.tag="xxxxxxxxx"/此处来将新生成的菜单对象显示出来;m_main.item1
6、.hide()m_main.item1.show()2、添加二级菜单功能的实现:/用途:在最后一项一级菜单下新增一项二级菜单/时间:2003-6-1/声明变量记录当前一级菜单总个数、最后一项一级菜单对应的二级菜单总个数; integer li_precount,li_itemcount/新创建一个菜单对象,并将其放到菜单数组im_new当中;ii_count+im_newii_count=create m_new/此处对新创建的菜单对象获取引用;li_precount=upperbound(m_main.item)li_itemcount=upperbound(m_main.itemli_pr
7、ecount.item)m_main.itemli_precount.itemli_itemcount + 1=im_newii_count.item1/下面是设置新生成菜单的text属性,这个属性可以从数据库中取,但此处省略简化掉了;m_main.itemli_precount.itemli_itemcount + 1.text="新增二级-" + string(li_precount) + "-" + string(li_itemcount + 1)/下面是设置新生成菜单的tag属性,这个属性可以从数据库中取,但此处省略简化掉了;/通过这个tag可以
8、当作功能号等来使用,通过gf_menumessage()函数来予以公共处理;/m_main.itemli_precount.itemli_itemcount + 1.tag="xxxxxxxxx"/此处来将新生成的菜单对象显示出来;m_main.item1.hide()m_main.item1.show()3、添加三级菜单功能的实现:/用途:在最后一项二级菜单下新增一项三级菜单/时间:2003-6-1/声明变量记录当前一级菜单总个数、最后一项一级菜单对应的二级菜单总个数; integer li_fircount,li_precount,li_itemcount/新创建一个菜
9、单对象,并将其放到菜单数组im_new当中;ii_count+im_newii_count=create m_new/此处对新创建的菜单对象获取引用;li_fircount=upperbound(m_main.item)li_precount=upperbound(m_main.itemli_fircount.item)if li_precount = 0 then messagebox("提示","请先点击-添加二级菜单-按钮创建一个二级菜单,:)") returnend ifli_itemcount=upperbound(m_main.itemli_
10、fircount.itemli_precount.item)m_main.itemli_fircount.itemli_precount.itemli_itemcount + 1=im_newii_count.item1/下面是设置新生成菜单的text属性,这个属性可以从数据库中取,但此处省略简化掉了;m_main.itemli_fircount.itemli_precount.itemli_itemcount + 1.text="新增三级-" + string(li_fircount) & + "-" + string(li_precount)
11、 + "-" + string(li_itemcount + 1)/下面是设置新生成菜单的tag属性,这个属性可以从数据库中取,但此处省略简化掉了;/通过这个tag可以当作功能号等来使用,通过gf_menumessage()函数来予以公共处理;/m_main.itemli_precount.itemli_itemcount + 1.tag="xxxxxxxxx"/此处来将新生成的菜单对象显示出来;m_main.item1.hide()m_main.item1.show()4、处理动态生成菜单的clicked事件:总体思想是采用参数化思想,借助统一的函数,
12、根据函数参数不同来予以不同处理。(1)处理m_new对象的clicked事件:/用途:根据新生成的各菜单所对应的功能号,即从数据库中取出的tag属性/ 来调用gf_menumessage()全局函数来实现不同的系统功能;/时间:2003-6-1/此处本应该去调用gf_menumessage()全局函数来处理不同功能所对应要处理的功能号,/但此处均略掉了,具体内容可参见 gf_menumessage() 函数;/此处仅仅演示一个messagebox()功能,如下;/integer li_ret/li_ret = gf_menumessage(this.tag)/下面代码是避免点击含有下一级子菜单
13、的菜单时会弹出对话框,导致无法显示下一级菜单的情况;if upperbound(this.item) > 0 then returnend ifmessagebox("动态菜单演示","您当前点击的菜单是:" + this.text)(2)编写gf_menumessage函数:/用途:根据新生成的各菜单所对应传进来的功能号,即从数据库中取出的tag属性/ 来动态判断所要进行的操作;/时间:2003-6-1/输入:string 型 as_funcode:对应传进来的菜单要实现的功能号;/输出:integer型 1:成功/ -1:失败/注:根据新生成的
14、各菜单所对应传进来的功能号,即从数据库中取出的tag属性/ 来动态判断所要进行的操作;此操作需要连接数据库,故此处简列思路,具体略string ls_funcode /声明一变量用于记录传进来的功能号;ls_funcode = as_funcodechoose case ls_funcode case "1" /.比如 1 代表入库管理,则去调用入库管理函数 gf_rk()等等 case "2" /.比如 1 代表出库管理,则去调用出库管理函数 gf_ck()等等 /. case else return -1end choosereturn 1/曾经在一
15、些书上看到用C语言实现动态菜单的方法,需要调用大量的API函数,但是这里我想换一种方法,借助PowerBuilder提供的属性和递归算法实现动态菜单的创建过程。需要指出的是,这里讨论的动态菜单是已经在外部数据源中定义好菜单结构,而菜单对象没有有任何菜单项,需要由程序生成各个定义好的菜单项。一、定义菜单数据结构实现动态菜单,首先设计合理的菜单数据结构,其数据源可以是任何DBMS,甚至可以是TXT文本文件(只要能建立好合理的分层结构)。菜单如同一个树形控件,有着分层的顺序结构,所以在定义数据结构时,应当选择一种能够形象地表示父子、兄弟关系的模型。而能够最好反映菜单结构的控件就是树形控件:treev
16、iew,并且定义按照二位递进的数据结构形式,即:以级别确定层数,以序号确定兄弟关系,以二位递进确定父子关系。例如,如图所示的菜单的对应数据结构如下。这样的菜单结构,在建立菜单结构时,非常适合用递归的算法,那么我们可以按照树的遍历算法建立一个树形结构的菜单对象。接下来,定义菜单数据结构。菜单数据结构应当包含以下基本元素:菜单名、菜单类型、菜单序号、菜单项文本、菜单项id、菜单项的执行代码、菜单显示风格。如下表说明:二、动态创建菜单1、流程图2、流程说明:如上图,整个建立菜单的过程分成两部分:初始化菜单和设置菜单属性。初始化菜单即是以递归的算法从数据源中读取菜单数据,每读一个菜单项建立一个菜单项对
17、象,利用powerbuilder中create方法一级一级建立菜单。首先定义一个菜单实例对象,这里的菜单是指主菜单,而不是弹出菜单,由于而者的区别,对于弹出菜单的处理在后面介绍。菜单建立的核心原理很简单,只有四句:创建菜单对象、挂接菜单项目、先隐藏后显示菜单对象。如下:integer ai_item_serial_no /序号,作为递归的函数传入参数menu am_obj /菜单对象,作为递归的函数传入参数m_menu_item lam_root /菜单对象,m_menu_item是预先定义的一/个菜单对象,该对象没有一个菜单项/创建菜单对象lam_root.itemai_item_seria
18、l_no = create m_menu_item /将新建的菜单对象,挂接到已有菜单对象上。am_obj = lam_root.itemai_item_serial_no/下面两句用于显示建立好的菜单lam_root.Hide() /隐藏菜单对象 lam_root.Show() /显示菜单对象将上面的语句放在一个递归过程中,就可以建立起整个的菜单结构。 在建立菜单的过程中需要得到菜单的itemid,该属性是用来捕获菜单响应动作的唯一标示,只有知道的菜单的itemid,才知道是触发了哪个菜单项的事件。得到菜单项itemid的方法,在不同系统经过反复测试之后,发现一个规律:父项菜单的itemid
19、是从0开始依次递增1,子项菜单的itemid是从10000开始依次递增1。由此按照递归算法,生成每层每个菜单项的itemid,并存入数据库中。设置菜单显示风格,是在菜单建立后设置三种显示风格:文字风格、图片风格、文字图片混合的显示方式。为了提高效率,在设置每个菜单风格时,不对所有父项菜单、不可视菜单项和没有定义显示图片的菜单项进行设置,因为文字风格是默认风格不必更改。这部分程序员主要用到三个API函数:Getsubmenu:用于得到指定菜单项的句柄。SetMenuItemBitmaps:用于设置文字显示风格或设置图片风格,两种情况的区别在于该函数的最后两位若为0,则是去掉菜单项上的位图;最后两
20、位若是图片句柄,则是在菜单项上添加位图。ModifyMenu:用于设置图片显示风格。经过反复测试,发现如果指定的显示图片名为“*bmp”等不合法名称,则显示出的效果是一个分割符。3、在整个菜单建立过程,需要重点设计的是程序算法、数据存取的方式和出错控制。1)、程序算法主要指递归算法,一般递归有两种算法,即FOR循环的方法和DOwhile循环方法。两者都是循环算法,但是效率不同。建议用户根据自己的能力选择方法,切忌不能写成死循环。For循环的方式比较简单直观,循环控制遍历的次数,循环内再调用本身,实现递归调用。DOwhile循环方法主要在循环内判断叶子或枝子(即父亲节点),对叶子和枝子进行分别处
21、理,内部也要调用本身,实现递归调用。2)、选择合理安全的数据存取方式,对于稳定建立菜单也很重要。定义一个datastore(数据存储)对象,在初始化菜单时候,将从数据库中提取的所有数据存入该datastore对象,然后不再对数据库进行任何操作,直到需要结束时将变更的菜单数据(如,itemid)以datastore的update形式提交数据库。在此之前所有需要从datastore得到的数据,用过滤的方式得到,即用setfilter()和filter()函数,一定要注意的是:按照结对编程的规则,在过滤并使用完datastore中数据后,一定再写一对过滤条件为空字符串的过滤,如下:setfilter
22、(“条件1”)filter()处理过程setfilter(“”)filter()这样也可以将数据及时还原到初始状态,以便下一个模块调用。利用datastore,既可以保持在菜单建立期间的数据安全,不受数据库影响;又可以提高效率,省去对数据库的反复读写操作。3)、因为菜单的重要性,使得出错控制在菜单建立尤为重要。我们在递归建立菜单时,要考虑尽可能多的潜在错误,谁也不能保证数据库中的菜单结构数据不出错,虽然正确定义不是建立模块的事。尤其菜单的二位递进的分层数据结构,若有一处错误,可能导致整个建立过程失败,更糟糕的会发生程序异常退出。所以程序在设计出错处理时,应当考虑是终止进程,还是跳过错误的环节继续进行。我建议,在设计程序时应但兼具一定的冗余度和纠错能力。即遇到错误的数据能够根据环境修正为正确的值,对于可以忽略的一些小问题,为提高效率不作处理。需要指出的是,经过反复测试,发现对于菜单的属性,如果是字符类型则不能赋空值,如果没有应当是空字符串,如果是整数类型也不能赋空值,如果没有应当是某个缺省整数。否则程序会报异常错误,然后退出。由此可见,反复测试是非常重要的,不仅能发现语法错误和确保算法的正确,更能找出许多我们难以推断的错误。三、对弹出菜单的特殊处理由于弹出菜单的对象定义和调用方式与主菜单的不同,需要进行一些特殊处理。首先定义一
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 美团外卖商家订单分成合同
- 直播活动内容补充与品牌合作协议
- 软性材料研发与市场推广合伙协议
- 网络文学有声书制作与环保公益活动合作协议
- 影视作品版权购买与版权收益分成合同
- 顶级域名所有权及商业价值转让服务合同
- 影视特效动作捕捉系统全面解决方案租赁协议
- 生物样本冷链物流与生命科学研究支持合同
- 小产权房配套设施共享及社区公共设施保养维护合同
- 电商侵权案件管辖权争议补充协议
- 智慧场馆智能化方案
- 2024版《中医基础理论经络》课件完整版
- JJG 1009-2024X、γ辐射个人剂量当量HP(10)监测仪检定规程
- 高中生物试卷讲评公开课课件模板
- 会诊制度培训课件
- 2025年经济师考试旅游经济(中级)专业知识和实务试卷及解答参考
- 安徽演艺集团有限责任公司招聘笔试题库2024
- 回收二手机免责协议书模板
- 2023年UKKA血液透析血管通路临床实践指南解读
- 2022版义务教育艺术课程标准美术新课标学习解读课件
- 完整版青少年普法宣传教育全文课件
评论
0/150
提交评论