菜单权限控制
最近用pb做了个简单需求 我在abc程序主菜单 m_main 上加了个sub_menu 然后把程序传到系统管理程序systemmger中  
systemmger的菜单权限管理中就自动出现了我新增加的sub_menu 我跟踪了下 发现systemmger的菜单控制是调用的数据库表来实现  


我很奇怪 这个sub_menu的信息事怎么传到数据库的呢? 我没有手动去insert这些权限相关的表啊 搞不懂

据说pfc有这个功能,我也是听说 反正好神奇, 我很想学习这个菜单权限管理的方式,很重要啊

在此请教各位pb的前辈

------解决方案--------------------------------------------------------
基于 PFC 构造一个灵活通用的程序框架作 MIS 开发时,更多的精力要放在分析、理解及实现业务上,而且一般的 MIS 结构和要求也是 大同小异,如果构造了一个灵活通用的程序框架,就能很快进入核心业务的开发,极大地提高了你的 “生产效率” 。 以下就结合我的实际开发经验:

一、总体考虑 程序框架既要灵活又要通用, 这就要求程序总控要尽量不涉及到具体的控制, 模块尽量独 立化。一般 MIS 需要考虑的主要是安全管理和操作命令项,而基于多用户的系统,要满足这 个要求,只能是通过数据库存储这些信息来实现。

二、安全管理

1、PFC 中提供了一套安全管理的模式,但不太实用,所以我另外设计了四个表: Security_Modules (ModuleId,ModuleName) PK: ModuleId //模块 Security_Roles(RoleId,RoleName) PK: RoleId //角色 Security_RoleRights(RoleId,ModuleId,Rights) PK: RoleId,ModuleId //角色对应权限 Security_Users(UserId,UserDes,Password,RoleId) PK: UserId //用户

2、定义一个非视化类:n_cst_securitymanager 用于安全管理,该类的定义如下: //Instance Variables: private: n_ds ids_Rights //存放指定 RoleId 对应每个模块的权限 string is_UserId //当前用户 Id Integer ii_RoleId //当前角色 Id //Member Functions: of_SetUserID(string as_UserId) Return (None) //设置当前用户名 of_GetUserId() Return String //取当前用户名 of_GetUserDes() Return string //取当前用户描述名 of_LoadRights() Return Boolean //检索当前用户对应各模块的权限 of_GetRoleName() Return String //取当前用户角色名 of_GetRights(string as_ModuleName) Return Integer //返回当前用户对应给定模块的权限 of_GetRights(Integer ai_ModuleId) Return Integer //返回当前用户对应给定模块 Id 的权限 of_CanOpen(string as_ModuleName) Return Boolean //判断当前用户是否可以进入给定模块 of_CanOpen(Integer ai_ModuleId) Return Boolean //判断当前用户是否可以进入给定模块 of_CanWrite(string as_ModuleName) Return Boolean //判断当前用户在给定模块是否有更改 的权限 of_CanWrite(Integer ai_ModuleId) Return Boolean //判断当前用户在给定模块是否有更改的 权限

3、定义 n_cst_securitymanager 的全局变量 gnv_security,并在应用对象的 Open 事件中创建, 在 Close 事件中销毁。

4、在登录成功后调用 of_SetUserId 和 of_LoadRights。

5、实际上授权和用户管理可以做成通用的模块,如:

三、操作命令

1、我们的程序模块通常由工作表(Sheet Window)、主窗体(Main Window)、对话盒(Reponse Window)构成,打开每个模块,一般通过菜单命令实现,但 PB 的菜单不便于动态管理,而且 PB 的 MDI 结构分 PowerBar(对应主菜单)和 Toolbar(对应每个 sheet),所以要实现操作命令的 维护,tb无须再修改程序,可考虑其他形式。

2、定义一个表存放操作命令的相关信息,例如(你的可能不同,按需要而定) : AppCfg_OptrItems(ItemId,ItemName,ModuleId,GroupId,GroupName,WindowName,WindowTy pe,IconFileName) //WindowType 可为 Sheet、Main 或 Response

3、表现形式: 菜单一般是具有层次的,但作为操作命令,最好不要超过两层,否则用户可能嫌麻烦,要 通过修改数据库中的数据的办法以达到修改程序操作命令集的目的,通常可用 ListView、 TreeView 或 OutLook Bar(网上流行的 OutLook 风格的控件,稍作改造即可)等形式。下面 是后两种形式的图例:

4、窗口管理: 由于最好不要打开多个窗口实例, 并且用户希望能够通过单击操作命令项切换到已经打开 的窗口上,所以要在你的 MDI Frame 窗口中定义一个tb结构体和几个函数以管理窗口: //Structure: os_Sheet (你的可能不同) Window WindowVar String WindowName String ItemName //Window Functions: of_FindSheet of_RegisterSheet //在 Sheet Window 或 Main Window 的 Open 事件中注册该窗口 of_RemoveSheet //在 Sheet Window 或 Main Window 的 Close 事件中注销该窗口

5、打开窗口 定义一个非可视类 n_cst_windowopenarguments 以传递窗口参数。 把 ListView、TreeView 或 OutLook Bar 中用户对操作命令选中的信息传到 MDI Frame 窗 口的 Pfc_Open 事件中,在此事件中统一处理: (例子代码: ) n_cst_windowopenarguments lnv_Arguments window integer lw_window li_Location lnv_Arguments=Message.PowerObjectParm If Isnull(lnv_Arguments.is_WindowName) Or Trim(lnv_Arguments.is_WindowName)="" Or & Isnull(lnv_Arguments.is_WindowType) Or Trim(lnv_Arguments.is_WindowType)="" Or & Isnull(lnv_Arguments.is_ItemName) Or Trim(lnv_Arguments.is_ItemName)="" Then Return End IF CHOOSE CASE lower(lnv_Arguments.is_WindowType) CASE "sheet" li_location=of_FindSheet(lnv_Arguments.is_WindowName,lnv_Arguments.is_ItemName) If li_location>0 Then iws_sheetlist[li_location].windowvar.SetFocus() Else Opensheetwithparm(lw_Window,lnv_Arguments.is_ItemName,lnv_Arguments.is_WindowName,this,0,Original!) End If Case "main" li_location=of_FindSheet(lnv_Arguments.is_WindowName,lnv_Arguments.is_ItemName) If li_location>0 Then if iws_sheetlist[li_location].windowvar.WindowState=Minimized! Then iws_sheetlist[li_location].windowvar.WindowState=Normal! End If iws_sheetlist[li_location].windowvar.SetFocus() Else Openwithparm(lw_Window,lnv_Arguments.is_ItemName,lnv_Arguments.is_WindowName,this) End If Case "response" Openwithparm(lw_Window,lnv_Arguments.is_ItemName,lnv_Arguments.is_WindowName) CASE ELSE //Do Nothing END CHOOSE 通过这种方式构造出来的程序框架结合你的风格和对 PFC 的扩展,相信你会成为一只“高产奶 牛”的! 以上仅作为各位参考,如有错误,请指正,如有更好的方法,请赐教。 Seasouce 2000-12-06