| 编程中国 | 业界新闻 | 技术文章 | 视频教程 | 下载频道 | 程序源码 | 个人空间 | 编程论坛
全能ASP/PHP/ASP.NET主机,支持月付专业 MSSQL 数据库空间,支持月付专业 MySQL 数据库空间,支持月付买域名,送MP3、MP4
高端软件开发 = 年薪十万不是梦赛孚耐:软件保护加密专家身份认证令牌USB KEY买空间,免费送域名(厦门中资源)
共有 712 人关注过本帖
标题:PFC工具
收藏  订阅  推荐  打印 
zihanchi
Rank: 1
等级:新手上路
帖子:1
积分:142
注册:2008-8-12
PFC工具

谁有PowerBuilder Foundation Class这个工具啊?请求共享一下
搜索更多相关主题的帖子: Foundation  工具  PFC  PowerBuilder  Class  
2008-8-19 08:58
freele_china
Rank: 12Rank: 12Rank: 12
来自:JiNan
等级:版主
威望:6
帖子:342
积分:3927
注册:2007-4-6
PFC编程基础


  概要:
  这一章阐述了 PFC 编程的基本技巧,同时也告诉了你如何开始运用 PFC 编写应用程序。
  设置应用程序管理器
  首先建立一个PFC应用程序的第一步就是配置应用程序以及建立应用程序管理器- -n_cst_appmanager。应用程序管理器将替代原来的应用程序对象。原来在应用程序对象中编写的脚本将全部改写在应用程序管理器中。应用程序管理器中同时还通过实例变量、函数来维护应用程序的属性。其中有框架窗口、应用程序与用户的INI文件或注册键以及帮助文件等。
  注意:
  使用分开的物理文件
  每个独立的应用程序都必须拥有自己独立的一套文件。你不可以共享父类文件,也就是那些以PFC开头的文件。这是由PFC的内部继承关系而决定的。
  例如,假设应用程序1与应用程序2都拥有它们自己的一套扩展的PFC库文件,但是它们共享父类文件(PFC库文件)。这时应用程序1在自己的PFE(PFC扩展库)的w_master中增加了一个函数名为of_SetData。这样这个函数将在w_master的所有子类中都有效,这些子类是pfc_w_main,pfc_w_frame,pfc_w_sheet 等。而这些对象恰恰在这两个应用程序共享的父类文件(PFC库文件)中。这样当应用程序2重新生成应用程序时(regenerate)由于应用程序2的PFE文件中没有of_SetData函数。这样w_master的所有子类中的关于of_SetData函数的指针都将被删除。这样当应用程序1运行时将会导致运行时错误与编译错误。
  具体步骤
  1. 打开应用程序画笔。
  2. 定义库文件列表。
PFCAPSRV.PBL
PFCDWSRV.PBL
PFCMAIN.PBL
PFCUTIL.PBL
PFCWNSRV.PBL
PFEAPSRV.PBL
PFEDWSRV.PBL
PFEMAIN.PBL
PFEUTIL.PBL
PFEWNSRC.PBL
PFCOLD.PBL(如果你的应用程序是使用老版本的PFC库那么请增加该文件到库列表 中)  
  3. 在应用程序画笔中打开脚本画笔,定义n_cst_appmanager类型的全局变量gnv _app。
  n_cst_appmanger gnv_app 这个变量名必须是gnv_app,因为PFC的对象、函数、事件都需要这个n_cst_appm anager或它的子类的全局变量-gnv_app。
  4. 增加如下代码到应用程序对象的OPEN事件中。它的用途是创建n_cst_appmanager、调用pfc_Open事件。
gnv_app = Create n_cst_appmanager
gnv_app.Event pfc_Open(commandline)  
  5. 增加如下代码到应用程序对象的CLOSE事件中。
gnv_app.Event pfc_Close()
Destroy gnv_app  
  6. 增加如下代码到应用程序对象的SystemError事件中。调用pfc_SystemError事 件。
gnv_app.Event pfc_SystemError()
  7. 关闭应用程序画笔,保存所作的修改。
  8. 打开用户自定义对象画笔。在PFEAPSRV.PBL中找到n_cst_appmanager并打开,或者是它的子类。
  9. 在n_cst_appmanager的构造事件(Constructor Event)中调用它的函数来初始化关于软件版本号、公司、和INI文件的实例变量。
  10. 在 n_cst_appmanager的pfc_Open事件中打开你所想要的应用程序Service 。
  你所想打开的Service 调用函数Application preference of_SetAppPreference DataWindow caching of_SetDWCache Error of_SetError Most recently used object of_SetMRU Transaction registration of_SetSecurity Debug of_SetDebug
  11. 在pfc_Open事件中增加打开你的初始窗口的代码,例如框架窗口(Frame Window)或者调用显示快闪窗口的of_Splash()函数。
  12. (可选)增加代码到pfc_PreAbout,pfc_PreLogonDlg,pfc_PreSplash事件中,用于定制关于对话框(About box)、登录对话框(Logon box)、快闪窗口(splash screen)。
  13. (可选)增加代码到pfc_idle,pfc_ConnectionBegin,pfc_ConnectionEnd事件中。
  l_ 在应用程序对象的idle事件中调用pfc_idle事件。
  l_ 在应用程序对象的ConnectionBegin事件中调用pfc_ConnectionBegin事件。
  l_ 在应用程序对象的 ConnectionEnd事件中调用pfc_ConnectionEnd事件。
  14. 保存n_cst_appmanager
  如何显示快闪窗口
  非常简单,只需在pfc_Open事件中,在打开第一个窗口的代码之前写上如下代码 :
  this.of_Splash(1)
  Open(w_tut_frame)(根据不同的应用程序有不同的变化!)
  如何显示登录窗口
  1. 在框架窗口的Open事件中调用of_LogonDlg函数:
Integer li_return
li_return = gnv_app.of_LogonDlg( )
IF li_return = 1 THEN
this.SetMicroHelp("Logon successful")
ELSE
MessageBox("Logon", "Logon failed")
Close(this)
End If  
  Of_LogonDlg函数将显示w_logon对话框,同时还会提示输入用户名、密码,当用 户点击OK按钮时还会触发n_cst_appmanager的pfc_Logon事件。
  同样,你也可以在n_cst_appmanager的pfc_Open事件中的打开框架窗口之后立即 调用Of_LogonDlg函数。但是绝对不要在Of_Splash之后立即调用Of_LogonDlg 。
  2. 在n_cst_appmanager的pfc_logon事件中编写登录到数据库的代码。这个例子 假设有一个INI文件,它包含了所有的需要登录到数据库的信息,除了用户名、密码以外。同时还假设你已将SQLCA的默认类型改为n_tr(PFC制定的书屋对象类型 )。
Integer li_returnString ls_inifile, ls_userid, ls_password
ls_inifile = gnv_app.of_GetAppIniFile()
IF SQLCA.of_Init(ls_inifile,"Database") = -1 THEN
Return -1
END IF
// as_userid and as_password are arguments
// to the pfc_Logon event
SQLCA.of_SetUser(as_userid, as_password)
IF SQLCA.of_Connect() = -1 THEN
Return -1
ELSE
gnv_app.of_SetUserID(as_userid)
Return 1
End If
建立应用程序
  建立一个MDI应用程序
  使用w_frame,w_sheet窗口作为你的框架窗口与表单窗口的父类。在w_sheet窗口 中增加你的应用程序中所有表单窗口需要的事件、实例变量、函数。
  你必须为每一个表单窗口定义菜单。
  具体步骤:
  1. 为应用程序在w_frame窗口中作特定的修改。最好是建立一个w_frame窗口的子类,然后再修改这子类。
  2. (可选)在w_sheet中增加实例变量、函数、用户自定义事件。
  3. 建立继承w_sheet的表单窗口。
  4. 建立一个框架窗口(frame window)用的菜单,通常是选用w_frame 。
  5. 为框架窗口指定相应的框架窗口菜单。
  6. 建立表单窗口的菜单
  7. 为表单窗口(sheet window)指定相应的表单菜单。
  8. 在n_cst_appmanager的pfc_Open事件中加入打开框架窗口的代码。
  9. (可选)在必要时候,开启框架窗口Service 。
  l_ 调用w_frame的of_SetStatusBar函数开启状态条Service 。
  l_ 调用w_frame的of_SetSheetManager函数开启表单管理Service 。
  在MDI应用程序中打开表单窗口:
  1. 在菜单项的Clicked事件中编写有关打开表单窗口的脚本。你需要将表单窗口的名称以字符串的形式传递给Message.StringParm,然后以pfc_Open为参数调用of_SendMessage函数:
n_cst_menu lnv_menu
Message.StringParm = "w_products"
lnv_menu.of_SendMessage(this,”pfc_Open”)  
  2. 在w_frame的pfc_Open事件中访问Message.StringParm,打开指定的表单窗口。
String ls_sheet
w_sheet lw_sheet
ls_sheet = Message.StringParm
OpenSheet(lw_sheet, ls_sheet, this, 0, Layered!)  
  建立一个SDI应用程序
  在使用PFC建立SDI应用程序中,你将使用w_main窗口作为你的所有main类型窗口的父类。为了使得你的事件、函数、实例变量能够在所有的窗口中都有效,只需将它们加到w_main中。
  如果你的窗口需要菜单,那么你必须为每一个窗口定义菜单。
  具体步骤
  1. 继承w_main窗口,建立一个main类型窗口,最为主窗口。最好是直接修改w_main窗口。
  2. 建立一个主菜单。
  3. 根据需要建立其他的菜单与窗口。
  4. 在n_cst_appmanager的pfc_Open事件中编写打开主窗口的脚本。
  PFC编程过程中的函数使用方法
  几乎所有的PFC函数都是对象级函数。这就意味着你必须定义POWERBUILDER对象后才可以使用函数。经过PB封装后的函数使你很轻易的看到哪个函数属于哪个对象。
  PFC使用Set/Get/Is 命名规则来控制实例变量。
  l_ of_Set函数允许你为实例变量赋值
  l_ of_Get函数允许你获得一个非布尔类型的变量的值
  l_ of_Is函数允许你确定一个布尔类型变量的真与假
  其他类型实例变量的访问规则
  PFC定义变量时同时指定为公共类型(public),那么你将可以随意直接访问。
  另外,有些变量由于只是在内部使用,因此不能通过函数进行访问。
  除了Set/Get/Is命名规则以外,PFC在为某一Service定义入口参数时使用Regist er/UnRegister规则。例如,你可以调用u_calculator对象的of_Register函数来定义Datawindow的那个列使用下拉日历。
Object qualificationPFC uses access levels (public, private, protected
) to control your access to functions designed for 内部自动调用 use.
When you call these functions from outside the object, use dot notatio
n to qualify the function name. Qualify the function name with the ref
erence variable used to create the object (in some cases you qualify t
he function name with the actual object name).  
调用PFC对象函数
  1. 确认对象是已否被创建
  PowerBuilder在当窗口打开的时候会建立窗口、菜单和可视的用户对象。你要使用函数of_Setservicename来建立大部分的不可视的用户对象。例如,下面u _dw的对象函数创建了排序Service(n_cst_dwsrv_sort user object),并且在u_dw’s中的实例变量inv_sort中保留它的引用。通常这些代码都在Datawindow的 构造事件中:
  this.of_SetSort(True)
  自动实例化对象
  某些PFC对象利用了Powerbuilder提供的自动实例化功能。这些对象没有Set函数 。PowerBuilder会在它们声明的时候自动实例化它们。
  2. 在应用程序中调用适当的对象函数
  这个例子展示了排序Service将利用DataWindow的列名、排序已显示值、 实现当用户点击后排序。同时可以在菜单栏上显示下拉对话框。
this.inv_sort.of_SetColumnNameSource(this.inv_sort.HEADER) this.inv_s
ort.of_SetUseDisplay(TRUE) this.inv_sort.of_SetColumnHeader(TRUE)
this.inv_sort.of_SetStyle(this.inv_sort.DRAGDROP)  
  函数重载PFC使用函数重载提供了一个丰富的、富有弹性的编程接口。它通过两种方法实现函数重载。
  l_ 多种语法 多个函数具有不同的参数类型、不同的参数顺序。这使得PFC的函数可以处理多种数据类型的参数。
  l_ 随意的参数数目 许多函数拥有一个具有相同数据类型、相同顺序、参数数目可以变化的参数。它同时还允许PFC为常用的参数提供默认值。
  只用于内部处理所重载的函数
  除了公有类型的重载函数以外,PFC通常还有一个保护类型的版本,一般都是用来进行内部调用的。例如,n_cst_dwsrv_report中的of_Addline函数有4个公有类型的版本、一个保护类型的版本。这个保护类型的版本是供其他4个调用的。虽然有些时候可以调用这些保护类型的版本,但是他们纯粹是为了内部调用而设计的

  关于PFC事件的编程
  PFC包括了预代码的事件、用于实现PFC Service的用户自定义事件。还有一些空的事件,你可以在其中为你的应用程序加入特定的代码,或者执行一些特定的任务。所有的事件都是公有的,你可以直接访问它们。
  “预代码事件”与其他的用户自定义事件
  预代码事件指的是那些已经在PFC层对象中编号代码的事件。PFC拥有许多具有一定功能的“预代码事件”。这意味着如果你开启了一个Service ,PFC的对象发现该Service已开启了,那么这些“预代码事件”将会执行其中的代码。
  例如:u_dw的Clicked事件就是一个“预代码事件”,它会自动调用那些开启的Service函数。你可以扩展这些事件,但是不可以覆盖它们。
  空的用户自定义事件
  PFC定义了许多空的用户自定义事件。你可以在其中为你的应用程序写入特定的代码。许多这种事件都是通过菜单而触发的。另外一些则是应用程序代码触发的。
  例如:
  在u_dw中有一个用户自定义事件pfc_Retrieve ,你可以在其中加入检索数据的代码。
  Return this.Retrieve()
  有关更多的关于PFC事件的内容请参考PFC Object Reference
  PFC中的事件是如何起作用的
  PFC是采用如下的方式调用Services中的事件的
  1. 当用户触发某个对象的某个事件时,PFC将会调用相应的Service 的自定义事件,同时传递相应的参数。例如:u_dw的clicked事件会调用n_cst_dwsrv_sort的pfc_Clicked事件,同时传递X坐标、Y坐标、DW对象(这些其实也是DW的Clicked 事件的参数)。
  2. 这些Services的事件同时还有可能调用其他对象函数。例如,n_cst_dwsrv_sort的pfc_Clicked事件中还调用了n_cst_dwsrv_sort的函数。
  尽管你可以直接调用PFC的对象函数,但是调用相应的事件显得更简单,因为这些事件中已经包括了错误检测代码。
  关于事件触发前的一些处理
  PFC有一种自定义事件名是Prename 。这意味着这些事件是发生在事件name之前的事件。我们把它叫做pre_event 。你可以随意在pre_event中增加代码用于扩充相应的事件处理能力。这些pre_event有:
pfc_PreAbout
pfc_PreClose
pfc_PreLogonDlg
pfc_PreOpen
pfc_PrePageSetupDlg
pfc_PrePrintDlg
pfc_PreRestoreRow
pfc_PreSplash
pfc_PreToolbar
pfc_PreUpdate  
  通常,这些事件中都有一个已经自动实例化了的用户对象的引用变量。这个对象的属性可以影响这个事件的运行。你可以修改这个用户对象的属性,从而达到改变事件的运行或扩展事件的运行效果。有些时候你还需要修改一些其他的对象。
  例如,当你需要控制About对话框中的一个附加控件的显示效果时,你需要:
  1. 扩展用户对象n_cst_aboutattrib ,在其中增加一个用于在w_about中代表显示效果的实例变量(一个 user ID)。
  2. 在w_about中增加控件(sle_userid)
  3. 在w_about的Open事件中编写代码,将user ID的值放入单行编辑框中(sle_userid)
sle_userid.text = inv_aboutattrib.is_userid
  4. 在n_cst_appmanager的pfc_PreAbout事件中编写初始化代码:
  inv_aboutattrib.is_userid = this.of_GetUserID()
  然后当你需要显示w_about时,调用应用程序管理器的of_About函数即可。
  如何使用属性对象
  PFC提供了许多专门的属性用户对象。这些用户对象有如下特征:
  l_ 包含公有性质的实例变量
  l_ 自动实例化
  l_ 名称以attrib结尾
  l_ 通常用于向PFC的pre_event传递信息,例如pfc_PreAbout
  l_ 可扩展,你可以在其中自己定义其他的实例变量。
  因为,你有可能会扩展这些对象。因此,PFC使用对象而不使用对象。
  同样你还可以定义对象函数,做到更随意的控制这些对象。
  这些属性对象有:
  属性对象有关的用法
n_cst_aboutattrib Pfc_Pre_About(n_cst_appmanager) 调用n_cst_appmanager的of_About函数打开about对话框
n_cst_calculatorattrib Constructor(u_calculator) 内部自动调用n_cst_dirattrib File service object 内部自动调用
N_cst_dwobjectattrib Of_Describe(n_cst_dssrv与n_cst_dwsrv) 函数Of_De scribe返回DataWindow中的对象属性。
n_cst_dwproperyattrib DataWindow Properties objects 内部自动调用 n_cst_errorattrib Error message service 用于传递显示内容到w_message窗口
n_cst_filterattrib DataWindow filter service 用于传递信息到filter对话框
n_cst_findattrib DataWindow find service 传递信息到Find对话框
n_cst_itemattrib PFC ListBox, PictureListBox, and TreeView 内部自动调用
n_cst_linkageattr b DataWindow linkage service 内部自动调用
n_cst_logonattrib Pfc_PreLogonDlg (n_cst_appman ger) 调用n_cst_appmanager的of_LogonDlg函数打开w_logon窗口
n_cst_mruattrib MRU service 用于窗体的pfc_MRUProcess和pfc_PreMRUSave事 件
n_cst_restoreroattrib DataWindow row manager service 内部自动调用
n_cst_returnattrib DataWindow filter and sort services 内部自动调用
n_cst_selectionattrib Selection service Populated with arguments to th
e n_cst_selection of_Open function
n_cst_sortattrib DataWindow sort service 用于传递信息到Sort对话框
n_cst_splashattrib Pfc_PreSplash event (n_cst_appman ger) 调用n_cst_ap pmanager的of_Splash函数打开w_splash 。
n_cst_sqlattrib SQL service 该属性对象中含有SQL语句的部分内容。
n_cst_textstyleattrib PFC RichTextEdit control 用于设置和获取text属性(黑体、斜体等)。
n_cst_toolbarattrib Pfc_PreToolbars event (w_frame) 调用w_frame的pfc_Toolbars事件打开w_toolbars 。
n_cst_zoomattrib DataWindow print preview service 内部自动调用  
  PFC的常量
  许多PFC对象都包含了常量。使用常量使得程序更加易读。例如:下面两段代码同样是设置Datawindow的linkage风格,但是第二段则显得更加容易理解:
// 1 = Filter linkage style.
dw_emp.inv_linkage.of_SetStyle(1)
// FILTER 作为一个常量
dw_emp.inv_linkage.of_SetStyle (dw_emp.inv_linkage.FILTER)  
  约定:PFC的所有常量都采用大写。
  消息路由
  消息路由器可以用于任何一个对象与窗体之间的通讯。不过,大部分时候都是用于菜单与窗体之间的消息传递。它提供了一种查找算法用于确定哪个对象来接收消息。
  使用消息路由时:
  l_ 你菜单中的代码只需要知道代用哪个事件,你无须知道当前的窗口时哪个,或者与其相关的对象名称。
  l_ 你的窗口无须维护用户事件,只需简单调用DataWindow的事件即可。从而减少了窗口需要维护的事件数量。
  Message = user event
  经过消息路由传递的消息实际上就是用户事件名。窗口、控件收到这些消息后就会调用相应的事件。
  内置的debug消息
  消息路由机制还提供了内置的debug
  函数of_SendMessage的工作流程
  当用户选择菜单项时,Clicked事件中的代码便以欲触发的用户事件名为参数(字符串的形式)调用of_SendMessage函数。Of_SendMessage调用n_cst_menu的of_SendMessage函数,n_cst_menu的of_SendMessage将会调用窗体的pfc_MessageRou ter事件,pfc_MessageRouter事件将会调用你所要触发的用户事件(即在Clicke d中传递字符串参数)。
  在MDI与SDI应用程序中,函数Of_SendMessage调用pfc_MessageRouter时将有所不同。
  消息路由是菜单与窗口之间的通讯桥梁。你不可以通过按钮来触发pfc_MessageRouter事件。因为,消息路由会调用GetFocus函数判断当前控件。这样当你按下按钮时,按钮便成了当前控件。
  PFC中的事务对象
  PowerBuilder的强大功能之一就是可以快速便利的访问多种数据库。PowerBuild er使用事务对象(Transaction Object)作为PowerBuilder与Database之间的桥梁。SQLCA就是一个默认的事务对象。
  用户自定义对象n_tr
  PFC中有一个n_tr对象。它是标准事务对象的子类。其中设有实例变量、用户自定义事件、函数,主要用于扩充与数据库的通讯能。
  N_tr提供了一套标准函数用于连接、切断、提交、回滚等数据库操作。使用这些函数代替原有的数据库语句。例如使用of_Connect代替CONNECT语句。
  两处地方使用n_tr
  l_ 替代sqlca:在应用程序的属性对话框中将SQLCA的默认数据类型设为n_tr 。
  l_ 附加的事务对象:当你需要访问多个数据库时,你可以再定义一个事务对象。
  如果你使用了多个事务对象,你可以使用事务对象的registration service ,做到一次提交全部已打开的事务对象,一次回滚所有已打开的事务对象。
  将SQLCA设置为n_tr类型
  1. 打开应用程序画笔
  2. 显示属性窗口,选中Variable页
  3. 在SQLCA框中输入n_tr
  4. 点击OK
  使用n_tr
  1. 如果你不使用SQLCA ,而是使用其他的事务对象。
  下面的例子假设itr_security是n_tr的实例变量
  itr_security = CREATE n_tr
  2. 初始化实例变量ib_autorollback 。这个变量的作用是当事务对象正处于连接状态时应用程序被关闭了或者是该事务对象被删除了的时候,该事务对象应该如何操作
  itr_security.of_SetAutoRollback(FALSE)
  关于初始化ib_autorollback的扩展你可以在n_tr的构造事件中初始化ib_autorollback 。
  3. 使用n_tr的of_Init函数初始化事务对象的属性
Integer li_return
String ls_inifile
ls_inifile = gnv_app.of_GetAppIniFile()
IF SQLCA.of_Init(ls_inifile,"Database") = -1 THEN
MessageBox("Database","Error initializing from " + ls_inifile)
HALT CLOSE
End if  
  4. 调用of_Connect进行数据库连接
IF SQLCA.of_Connect() = -1 THEN
MessageBox("Database","Unable to connect using " + ls_inifile)
HALT CLOSE
ELSE
gnv_app.of_GetFrame().SetMicroHelp("Connection complete")
End if  
  5. 调用n_tr的成员函数
  调用父类的函数、事件
  在扩充父类的函数和事件时,你有可能需要先调用父类的函数或事件,然后再依据返回值进行下面的处理。这对那些具有返回值前缀是PFC的事件特别有意义。你在执行子类的代码前必须先确认父类的代码是否执行成功。
  覆盖父类的函数
  为了扩展父类的代码,获取父类的返回值。你必须覆盖父类的代码,然后显示的调用父类的函数或事件。
  采用如下的语法格式调用父类的事件,同时传递参数、获取返回值:
  Result = Super :: Event eventname(arguments
  采用如下的语法格式调用父类的函数,同时传递参数、获取返回值:
  result = Super :: Function functionname(arguments
  下面的例子则覆盖了u_dw的pfc_Update事件。当父类的事件处理成功时,子类将信息纪录到日志中。
Integer li_return
// Call ancestor event, passing
// descendant's arguments.
li_return = Super::Event pfc_Update(ab_accepttext, ab_resetflag)
IF li_return = 1 THEN
// ue_WriteLog is a user-defined event.
li_return = this.Event ue_WriteLog
END IF
Return li_return
  在应用程序中增加联机帮助
  联机帮助是应用程序中非常重要的一部分。PFC提供了许多函数、事件使得你可以方便的将联机帮助添加到你的应用程序中。
  相关信息:有关PFC的帮助对话框请参考“Deploying PFC dialog box HELP” 。
  1. 使用n_cst_appmanager的of_SetHelpFile函数设置帮助文件。通常在构造事件中:
  this.of_SetHelpFile(“c:\eis\eisapp.hlp”)
  2. pfc_PreOpen是为窗口设置帮助主题的最好的地方
Long ll_helpid
Ll_helpid = 1020 //1020是一个帮助主题的ID
Ia_helptypeid = ll_helpid  
  采用这种方式你可以为用户选中的窗口提供详细的帮助。你可以将ia_helptypeid设置成长整形(此时PFC把它解释成帮助主题的ID),或者是字符串(此时PFC将它解释成关键字)。
  3.(可选)如果你没有使用PFC的m_master的子类。那么,在你的HELP菜单项中调用窗体的pfc_Help事件。因为,pfc_Help定义在窗口w_master中,所以所有的PFC窗口都具有事件。
  4. 对于对话框,则在其中的HELP按钮的Clicked事件中编写:
  Parent.Event pfc_Help()
  PFC自动处理窗口级别的帮助
  当你从m_master的子类的菜单中选择Help->Help时,消息路由机制会自动的调用当前活动的窗口的pfc_help事件。
  PFC的升级
  PFC在发布PowerBuilder的升级版本时同时也包括了PFC的升级文件。如何升级PFC,请按如下规则:
  l_ PFC的各层(PFC层、PFE层、中间层等)没有任何被修改时:你可以直接安装新的PBLs覆盖原有的PBLs。
  注意:每次升级PFC时都保留一份原有的文件备份
  l_ 如果你修改了PFC中的某一层:你必须保证你所作的修改不会被覆盖!请按如下的步骤进行:
  将PFC升级到最新版本
  1. 将所有扩展层的PBL文件移到一个不会被安装过程覆盖的目录中。
  说明:你不应该对PFC的最基类(以PFC为前缀的对象)作任何修改,这里假设你没有对PFC的最基类作任何修改
  2. 确定你当前的PFC的版本号。你可以在Readme.txt文件中查看,或者在pfc_n_cst_debug的实例变量中查看。版本号的格式:主版本号.次版本号.修正号
  3. 执行安装程序,将PFC安装口的PBL文件放到PFC所在的目录中,覆盖原有的PFC最基类的PBLS ,即以PFC开头的库文件。
  4. 合并已存在的扩展对象与新安装的扩展对象。首先详细阅读Readme.txt中说明的新扩展对象清单。然后按照一下的两种方法合并对象:
  l_ 将新的对象COPY到你的扩展PBLS中。
  l_ 将已经存在的对象COPY到新的扩展PBLS中。
  5. 启动PowerBuilder
  6. (可选)必要的时候调整一下应用程序的库列表
  7. 打开库画笔,从新编译一边所有的对象。

雁过留声,人过留名
2008-9-24 13:36
freele_china
Rank: 12Rank: 12Rank: 12
来自:JiNan
等级:版主
威望:6
帖子:342
积分:3927
注册:2007-4-6
PFC编程快速入门

PFC编程快速入门


//------------------------------------------------------------
1前言及PFC的编程特点概述(暂不详述)
//------------------------------------------------------------

  俗话说:实践出真知。所以,笔者一开始并不打算和大家讲什么高深的理论,而是和大家从PFC的实际应用编程着手,带领大家一步一步由浅入深、由点到面地用PFC编写一个实用的MIS(信息管理系统)。至于理论方面的知识,在程序编写的过程中遇到时才结合应用中的实例给大家讲解。当你跟着笔者完成这个PFC实战之旅后,相信你已经能够系统地掌握PFC的编程思想和方法了。
  虽然现在市面上已经有一些关于PFC的书了,但它们都是着重于介绍理论的,对于实际应用于编程的方法的书则没有。由于缺少实践机会,令读者读起来比较难明。所以,我想,我们可以写一本一开始就以PFC的实际应用编程为主,带领读者一步一步由浅入深、由点到面地用PFC编写一个实用的MIS的书。至于理论方面的知识,在程序编写的过程中遇到时才结合应用中的实例给大家讲解。当读者依书完成这个PFC的应用编程后,相信已经能够系统地掌握PFC的编程思想和方法了。然后,我们可以将PFC中各个对象、服务中常用、主要、重要的功能介绍给大家(就不像那本PFC手册那样,什么都写),可能更受大家的欢迎。最后,还以介绍一些高级的编程方法及理论,如:快速开发的理论等。

  在开始编程之前,请大家先准备好以下的编程环境:
  1、PowerBuilder7.0,并且安装了最新的补丁:
  2、数据库系统:
  3、数据库:。本文所有的例子均是基于该数据库进行的。


       作为一种可视化的、面向对象的快速应用开发(RAD)工具,PowerBuilder已被广大数据库应用于开发人员所使用,并获得好评。PowerBuilder全面支持面向对象编程,是集成强大并易于使用的编程语言,内置包括数据窗口(DataWindow)在内的多种对象类,可以方便地访问数据库。
    对于一个数据库应用系统来说,选择PowerBuilder开发工具进行程序设计与开发,是一种快速、高效、省时、省力的方法。PowerBuilder以简洁、直观、实用的编程方式为程序员节约了大量的时间和精力,使得程序员可以把大部分业务放在提高程序执行效率和完善系统功能上,这样做的结果使程序开发时间缩短,开发成本降低,程序编制质量也会大大提高。
    开发一个小型的数据库应用系统,使用PowerBuilder提供的菜单编辑器、窗口编辑器、数据窗口生成器等可视化编程工具,结合PowerBuilder Script脚本语言直接开始程序的编制工作,并不会影响程序的开发效率。然而,对于一个大(中)型数据库应用系统,并使用这种原始的编程方式进行开发与充分利用PowerBuilder提供的基础类库进行开发相比,在程序开发时间、效率、成本等方面,都会有明显的差别。
    PowerBuilder基础类库(PFC)是基于面向对象程序设计的思想而设计的,PFC封装PB Script。它包含了大多数应用共有的内容,例如各种菜单、窗口、用户对象、数据窗口以及错误处理、报表预览、打印、主细录入、查询等等。通过继承,程序员可以方便地把这些类加载到自己的程序中,从而达到提高开发效率的目的。
       作为一种可视化的、面向对象的快速应用开发(RAD)工具,PowerBuilder已被广大数据库应用于开发人员所使用,并获得好评。PowerBuilder全面支持面向对象编程,是集成强大并易于使用的编程语言,内置包括数据窗口(DataWindow)在内的多种对象类,可以方便地访问数据库。
    对于一个数据库应用系统来说,选择PowerBuilder开发工具进行程序设计与开发,是一种快速、高效、省时、省力的方法。PowerBuilder以简洁、直观、实用的编程方式为程序员节约了大量的时间和精力,使得程序员可以把大部分业务放在提高程序执行效率和完善系统功能上,这样做的结果使程序开发时间缩短,开发成本降低,程序编制质量也会大大提高。
    开发一个小型的数据库应用系统,使用PowerBuilder提供的菜单编辑器、窗口编辑器、数据窗口生成器等可视化编程工具,结合PowerBuilder Script脚本语言直接开始程序的编制工作,并不会影响程序的开发效率。然而,对于一个大(中)型数据库应用系统,并使用这种原始的编程方式进行开发与充分利用PowerBuilder提供的基础类库进行开发相比,在程序开发时间、效率、成本等方面,都会有明显的差别。
    PowerBuilder基础类库(PFC)是基于面向对象程序设计的思想而设计的,PFC封装PB Script。它包含了大多数应用共有的内容,例如各种菜单、窗口、用户对象、数据窗口以及错误处理、报表预览、打印、主细录入、查询等等。通过继承,程序员可以方便地把这些类加载到自己的程序中,从而达到提高开发效率的目的。

//------------------------------------------------------------
2概述
//------------------------------------------------------------


一、PFC编程的总原则:
  1、任何时候也不能对以“pfc”开头的库文件进行修改。
  2、必须遵守PFC的命名约定。
  3、任何时候创建对象(如:菜单、窗口)时,都不要用“New”(新建),而应该用“Inherit”(继承),从PFC的扩展层中继承父类。
  4、任何时候使用控件时,都不要用标准的控件,而应该选“user object”,再从PFC的扩展层中选择相应的对象。
  5、(更多的有待补充)

二、PFC的命名约定
Naming conventions
命名约定:
Object naming conventions
对象命名约定
PFC uses the following prefix standard for object names:
PFC使用以下的前缀作为对象命名的标准:
    pfcobject_type_objectname
    Pfc_对象类型_对象名称
where:
其中:

?pfcobject indicates whether the object is part of the PFC level or the extension level. Objects that are part of the PFC level have the prefix PFC_
 “pfcobject”指出该对象是PFC层的对象。如果该对象是PFC层的,则该对象的名称必须以“PFC_”作为前缀。如果是非PFC层的对象,则可以省略该前缀。
?type indicates the object type
 “type”指出该对象的类型。

This table describes the object types.
下表列出了所有对象的命名规则:

Prefix    Description
前缀    说明
m_    Menu
m_    菜单(Menu)
n_    Standard class user object
n_    标准类用户对象(Standard class user object)
n_cst    Custom class user object
n_cst    定制类用户对象(Custom class user object)
s_    Global structure
s_    全局结构休(Global structure)
u_    Visual user object
u_    可视用户对象(Visual user object)
w_    Window
w_    窗口(Window)


For example:
例如:
?Pfc_w_master is the master window and is in the PFC level
 Pfc_w_master    代表PFC层的主窗口对象。
?Pfc_u_tvs is the TreeView visual user object and is in the PFC level
 Pfc_u_tv    代表PFC层的树状浏览(TreeView)可视用户对象。
?U_dw is the DataWindow visual user object and is in the extension level
 U_dw        代表扩展层的数据窗口(DataWindow)可视用户对象。
?N_cst_dwsrv is the custom class user object for DataWindow services and is in the extension level
 N_cst_dwsrv    代表扩展层的提供数据窗口服务(DataWindow services)的定制类用户对象。
?N_tr is the transaction standard class user object and is in the extension level
 N_tr        代表扩展层的事务处理标准类用户对象。

Variable naming conventions
变量的命名约定:
PFC uses the following standard for variable names:
PFC使用以下的前缀作为变量命名的标准:
    <scope><datatype>_variablename
    <作用域><数据类型>_变量名称
Scope is one of the following:
作用域包括了以下几种:

Prefix    Description
前缀    说明
a    Argument to an event or function
a    事件或函数的参数
g    Global variable
g    全局变量
i    Instance variable
i    实例变量
l    Local variable
l    局部变量
s    Shared variable
s    共享变量


For standard data types, datatype is one of the following:
对于标准的数据类型,<数据类型>包括了以下几种:

Prefix    Description
前缀    说明
a    Any
a    Any(and类型)
blb    Blob
blb    Blob(大二进制对象)
b    Boolean
b    Boolean(布尔类型)
ch    Character
ch    Character(字符类型)
d    Date
d    Date(日期类型)
dtm    DateTime
dtm    DateTime(日期时间类型)
dc    Decimal
dc    Decimal(带符号十进制小数型)
dbl    Double
dbl    Double(双精度类型)
e    Enumerated
e    Enumerated(枚举类型)
i    Integer
i    Integer(整型)
l    Long
l    Long(长整型)
r    Real
r    Real(实型)
s    String
s    String(字符串类型)
tm    Time
tm    Time(时间类型)
ui    UnsignedInteger
ui    UnsignedInteger(无符号整型)
ul    UnsignedLong
ul    UnsignedLong(无符号长整型)


For reference variables, datatype is one of the following:

Prefix    Description
app    Application
app         Application(应用)
ab    ArrayBounds
cbx    CheckBox
cbx       CheckBox(复选框)
cb    CommandButton
cb        CommandButtOn(命令按钮)
cd    ClassDefinition
cdo    ClassDefinitionObject
cn    Connection
cn          Connection(链接)
cninfo    ConnectionInfo
cninfo      ConnectionInfo(链接信息)
cno    ConnectObject
cno         ConnectObject(链接对象)
cxk    ContextKeyword
cxinfo    ContextInformation
cpp    cplusplus
ds    DataStore
ds        DataStore(数据存储)
dw    DataWindow
dw          DataWindow(数据窗口)
dwc    DataWindowChild
dwc         DataWindowChild(子数据窗口)
drg    DragObject
drg        DragObject(拖动对象)
drw    DrawObject
drw       DrawObject(画图对象)
ddplb    DropDownPictureListBox
ddplb        DropDownPictureListBox(下拉式图形列表框)
ddlb    DropDownListBox
ddlb        DropDownListBox(下拉式列表框)
dwo    DWobject
dwo       DWobject(数据窗口的对象)
dda    DynamicDescriptionArea
dda       DynamicDescriptionArea(动态描述区)
dsa    DynamicStagingArea
dsa         DynamicStagingArea(动态状态区)
ed    EnumerationDefinition
eid    EnumerationItemDefinition
em    EditMask
em         EditMask(编辑屏蔽框)
env    Environment
env         Environment(环境变量)
err    Error
err         Error(错误信息)
ext    ExtObject
ext         ExtObject
gr    Graph
gr         Graph(统计图)
go    GraphicObject
go        GraphicObject(统计图对象)
grax    GrAxis
grax        GrAXis
grda    GrDispAttr
grda       GrDispAttr
gb    GroupBox
gb        GroupBOx(组选框)
hsb    HorizontalScrollBar
inet    Inet
ir    InternetResult
ln    Line
lb    ListBox
lv    ListView
lvi    ListViewItem
mfd    MailFileDescription
mm    MailMessage
mr    MailRecipient
ms    MailSession
mdi    MDIClient
m    Menu
mc    MenuCascade
msg    Message
mle    MultiLineEdit
nv    NonVisualObject
oc    OleControl
oo    OleObject
ostg    OleStorage
omc    OmControl
omcc    OmCustomControl
omec    OmEmbeddedControl
omo    OmObject
omstm    OmStream
omstg    OmStorage
oval    Oval
p    Picture
pb    PictureButton
pbcpp    PBToCPPObject
plb    PictureListBox
pl    Pipeline
po    PowerObject
procall    ProfileCall
proclass    ProfileClass
proln    ProfileLine
prort    ProfileRoutine
pro    Profiling
rb    RadioButton
rec    Rectangle
rem    RemoteObject
rte    RichTextEdit
rrec    RoundRectangle
rteo    RteObject
scrd    ScriptDefinition
sle    SingleLineEdit
sle           SingleLineEdit(单行编辑器)
srv    Service
st    StaticText
st          StaticText(静态文本)
std    SimpleTypeDefinition
str    Structure
str           structrue(结构)
tab    Tab
tab         Tab(标签)
tabpg    TabPage
tabpg       TabPage(标签页)
tcan    TraceActivityNode
tcbe    TraceBeginEnd
tcerr    TraceError
tcf    TraceFile
tcln    TraceLine
tcgc    TraceGarbageCollect
tco    TraceObject
tcrt    TraceRoutine
tcsql    TraceSQL
tct    TraceTree
tctn    TraceTreeNode
tcterr    TraceTreeError
tctsql    TraceTreeSQL
tctgc    TraceTreeGarbageCollect
tctln    TraceTreeLine
tcto    TraceTreeObject
tctrt    TraceTreeRoutine
tctu    TraceTreeUser
tcu    TraceUser
td    TypeDefinition
tr    Transaction
tr          Transaction(事务对象)
trp    Transport
trp         Transport
tv    TreeView
tv          TreeView(树状浏览)
tvi    TreeViewItem
tvi         TreeViewItem(树状测览项)
uo    UserObject
uo          UserObject(用户对象)
vrcd    VariableCardinalityDefinition
vrd    VariableDefinition
vsb    VerticalScrollBar
vsb           VerticalScrollBar(垂直滚动条)
wo    WindowObject
wo          WindowObject(窗口对象)
w    Window
w           Window(窗口)


Function naming conventions
函数的命名约定:

Global functions use the f_ prefix and object functions use the of_ prefix.
全局函数(Global functions):使用“f_”作为函数的前缀。
对象函数(object functions):使用“of_”作为函数的前缀。


  三、PFC的面向对象特点
  PFC的面向对象特点是学习PFC编程中一定要重点掌握的知识。可以这么说:PFC的应用,实际上就是面向对象技术的应用。PFC的一切,就是面向对象技术。PFC是PowerBuilder面向对象技术的体现。
  由于PFC采用了面向对象的程序设计方法,程序的封装性和继承性使得程序的后期维护工作变得更为轻松,性能价格比更为优越。这完全得益于面向对象这种程序设计方法的合理性,它把一个复杂的问题分解成与该问题相关的各个部分的子模块,再把这些子模块抽象为对象。若一个由祖先继承而来的对象出现错误,可以简单地对该于对象进行修改而不必去涉及其祖先对象,反之,若对处于同一层次的全部子对象进行类似的修改,可直接修改其祖先对象。
  PowerBuilder面向对象的特点主要体现在用户对象的技术运用上。PFC基础类库把PowerBuilder的多种对象以类的形式存储在库文件中,要正确有效地利用PowerBuilder基础类库进行程序的开发设计,必须了解面向对象的编程技术,了解PFC基础类库的面向对象特点。
  PowerBuilder把一些常用的、具有共性特征的对象(例如:窗口、菜单、数据窗口、用户对象等)提炼出来,并在每个对象中封装了不同的服务,构造了PFC基本类库。
      PFC基础类库完美地体现了面向对象程序设计的三方面重要特征:
  ·继承性(Inheritance)
  ·封装性(Encapsulation)
  ·多态性(Polymorphism)

  用户对象是PFC面向对象的具体表现,PFC的面向对象特点完全在用户对象中表现出来。
  以下着重介绍PFC中常用的用户对象:
  用户对象有两种类型:可视的用户对象(Visua1 user object)和类用户对象(Class user object)。
  (1)可视用户对象指的是一个可重用的可视控件或一个含有预定义行为的可视控件。
  PFC包含了两种类型的可视用户对象:
  标准可视用户对象
  PFC标准可视用户对象由PowerBuilder的标准可视控件继承而来,通过扩充标准控件的定义,完成特定的功能。每个PFC的标准可视用户对象都与窗口控件进行通信,这些对象中包含了预定义的程序,实现各种PFC应用服务。
  定制可视用户对象
  PFC定制的可视用户对象是将几个可视控件打包成一组的对象,它将多种服务有计划地组合在一起,完成一个复杂的功能。
  (2)类用户对象指的是在不使用可视用户对象时,完成一个执行过程而定义的可重用的不可视控制,它是不可见的,无法在窗口上直接看到,需通过程序来调用。
  PFC包含了两种类型的类用户对象:
  标准的类用户对象
  PFC标准的类用户对象由PowerBuilder的不可视标准控件继承而来,通过扩充标准控件的定义,完成特定的功能。  PFC为事务传输、错误处理和其他所有的扩展系统对象都提供了标准的类用户对象。
  定制的类用户对象
  从PowerBuilder的非可视对象类中继承了各种定义,封装了数据和代码。
  定制的类用户对象允许程序员定义自己的对象类。
  PFC使用定制的类用户对象执行多种服务,它还提供了一些接口参数,程序员可以通过这些接口参数与对象内部的实例变量、函数和事件进行通信。


  应用PFC编程时,在面向对象程序设计的三方面主要特征中,我们接触最广泛的是“继承”特征了。可以这么说:在构成应用界面的每一个元素,如:窗口、菜单、控件等等,无一不是从PFC的对象中继承而来的。所以,在这里,将给大家详细讲下PFC中的继承特性,请大家一定要注意体会掌握,因为,在以后的编程中,你无时无刻不都在与“继承”打交道。
  继承是一对象获取另一对象之性质的过程,它使得那些与基本类共享的性质能很方便地进行延续和扩展。继承对象类具备被继承对象类的所有属性、变量、函数、结构、控件和程序。对祖先对象的修改会使其所有子孙对象做相应的修改,子孙对象可修改或扩充祖先对象的属性和服务,但不能对祖先对象的控件进行删减。正是这种继承机制才使得一个对象成为某一基础类的实例。
  继承具有以下优点:
  ·可充分利用系统资源,减少程序的重复开发,大大提高了开发效率;
  ·使应用的对象保持一致,维护了系统的整体一致性;
  ·减少了人为程序错误的发生概率;
  ·使程序更易于维护。
  在PFC基础类库中,各种基础类的对象均可以被继承,如窗口、菜单、结构、数据窗口、用户对象等等。由继承而来的子孙对象包含了祖先对象的所有属性、变量、函数、结构、控件和程序,并可对它们进行修改和扩充。对于一个通过继承创建的后代窗口,可以进行如下进一步的处理:改变窗口的属性;在窗口中增加新的控件;在窗口中修改现存控件;改变窗口的大小和位置;改变窗口中控件的大小和位置;为窗口及控件编制新的处理程序;为窗口和控件扩展继承来的处理程序;用新的处理程序覆盖继承来的处理程序;引用祖先的函数、结构和变量;为该窗口定义新的函数、结构和变量。
  对于一个通过继承创建的后代菜单,可以进行如下进一步的处理:改变菜单项的属性;在菜单中插入菜单项;修改菜单项;为没有处理程序的菜单项增加处理程序;扩展继承来的处理程序;用新的处理程序覆盖继承来的处理程序。
  对于一个通过继承创建的后代用户对象,可以进行如下进一步的处理:改变属性和变量的值;为没有事件处理程序的事件增加处理程序;扩展继承来的事件处理程序;用新的处理程序覆盖继承来的处理程序;为可视用户对象添加控件;引用祖先的函数、事件和结构。
  值得注意的是,对于继承来的可视对象不能对其包含的控件进行删减,若某一控件确实不用,可通过修改其属性使之不可用或不可见。


  四、PFC的结构是一种基于服务的结构(Service-Based Architecture),PowerBuilder提供了各种类库和它们的源代码,程序员可以很方便地对类中的程序和控件进行修改和扩充,使之符合自己的需求。
  PFC基础类库基于服务的结构模式为基础类库的扩展提供了广阔的空间,它包含了PowerBuilder提供的多种对象以及它们各自所封装的多种服务,分别完成特定的功能。
  在PFC对象内封装的函数、事件和实例变量能够完成许多与应用环境无关的操作,称之为服务。程序员通过调用基础类对象来获得封装在对象中的服务。
  具体的服务有以下几种:应用服务;数据窗口服务;菜单服务;窗口服务;尺寸调整服务;转换服务;日期/时间服务;文件服务;INI文件服务;数据服务;平台服务;选择服务;SQL解析服务;字符串处理服务;元类服务;逻辑单元服务等。




//------------------------------------------------------------
03基本准备
//------------------------------------------------------------

四、实战之旅:
  一、更新库的搜索路径。
  1、为应用程序创建一个新的库文件。打开库管理面板(Library),点击工具条上的“Create Library”图标,并从弹出的“Create Library”对话框(如图所示)中选择新库的保存路径,输入新库的名称。这里我们假设将库保存到D:根目录下,并命名为:Design.pbl。
  2、创建应用对象。点击工具条上的“New”图标,从弹出的对话框中选择“Start Wizards”页面,双击“Application”图标。我们将看到如图所示的界面,在“Application Name”下输入应用对象的名称,我们这里命名为:design;并在“Library”下选择将该应用对象保存到什么库中。我们这里当然是将其保存到D:根目录下的Design.pbl中。单击“Finish”完成应用对象的创建。
  3、选择“File”菜单下的“Library List...”命令,在弹出的“Library List”窗口中单击“Browse...”按钮,如图所示。
  4、从弹出的“Select Library”对话框中选择需要的库文件:进入存放PFC库文件的目录下,按下[Ctrl]键并点击鼠标来选中下列文件:Pfcapsrv.pbl、PfcDwsrv.pbl、Pfcmain.pbl、Pfcutil.pbl、Pfcwnsrv.pbl、Pfeapsrv.pbl、Pfedwsrv.pbl、Pfemain.pbl、Pfeutil.pbl、Pfewnsrv.pbl。如图所示。
  5、点击“Open”按钮,选中的库文件就显示到库文件的搜索路径列表中。
  6、点击“Apply”按钮,PowerBuilder将上述PFC文件添加到应用文件列表中。

  ***理论知识:(这里要介绍的知识比较多,主要涉及到PFC的面向对象的特点、PFC各个库文件所包含的内容及作用、如何扩展PFC、如何升级PFC等,我还没整理好。)
  根据基础类实现的阶段划分为如下两类:
  ·基础类库文件:放置基础类对象的原始设计;
  ·扩展基础类库文件:放置继承基础类进行扩展设计后的扩展对象。
  没有任何一种类库能够包容用户所有的需求,典型的做法是把PFC库中的对象进行修改和扩充,使它和应用中的函数、对象融合为一体,如果没有基础类库的扩展层,就会导致这样一个问题:如何升级一个新版的PFC库,新版的应用将覆盖以前定制的类,迫使你重新进行手工改动以适应新的版本。
  PFC利用其继承性建立了扩展层,如下表所示。所有的扩展对象都放置在相对独立的PBL文件中,对扩展层可方便地进行升级和更新,而不会对其祖先层产生任何影响。
    表 PFC提供的服务在PBL库文件中的分布
内容            祖先层            扩展层
应用和全局性服务        PFCAPSRV.PBL        PFEAAPSRV.PBL
数据窗口服务        PFCDWSRV.PBL        PFEDWSRV.PBL
可视的和标准的类用户对象    PFCMAIN.PBL        PFEAMIN.PBL
实用程序的服务        PFCUTIL.PBL        PFEUTIL.PBL
窗口服务            PFCWNSRV.PBL        PFEWNSRV.PBL

  祖先层类库中的对象包含了所有的实例变量、事件和函数;扩展层类库中的对象是祖先库中相应对象的子孙对象,通过继承它们可以调用祖先对象的实例变量、事件和函数。可以使用PowerBuilder Browse浏览子孙对象内含的实例变量、事件和函数。
  使用扩展层有两个突出的优点:
  ·可以增加控件、部件和特殊逻辑的应用到扩展层对象;
  ·对扩展层进行升级不会影响类库程序的兼容性。
  需要注意的是:
  (1)为保持与旧版程序的兼容,在PFCOLD.PBL中存放了新版已放弃使用的对象。如果运行一个旧版的PFC程序,需要将PFCOLD.PBL加入到应用的搜索路径中去;
  (2)程序员可以通过修改扩展层的对象来定制PFC应用,但不能去修改祖先层的对象。例如:应用程序可以使用扩展层的用户对象并且从扩展层继承一个窗口。


        基础类库的部件
  PFC由以下几个部件构成:
  ·一组PBL类库文件;
  ·一个PFC数据库;
  ·一组支持快速开发的PBL库(Quickstart PBLS);
  ·PFC编程示例;
  ·一个简单的应用。

        PFC基础类库的库结构及其存放位置
  PowerBuilder的基础类库文件和扩展基础类库文件共有十三个,根据所包含基础类的不同功能进行了划分,其中以PFC开头的是基础类库文件,以PFE开头的是扩展基础类库文件,具体说明如下表所示。
                          表  PowerBuilder基础类库在PBL文件中的分布
库文件名            说    明                    安装路径
PFCMAIN.PBL    包含标准类用户对象、窗口对象、菜单            ..\pb6\adk\pfc
PFEMAIN.PBL    对象和标准可视类用户对象                ..\pb6\adk\pfc

PFCAPSRV.PBL    包含提供应用服务所必须的定制类用            ..\pb6\adk\pfc
PFEAPSRV.PBL    户对象                        ..\pb6\adk\pfc

PFCDWSRV.PBL    包含提供数据窗口服务需要的定制类            ..\pb6\adk\pfc
PFEDWSRV.PBL    用户对象                        ..\pb6\adk\pfc

PFCWNSRV.PBL    包含窗口服务需要的定制类用户对象            ..\pb6\adk\pfc
PFEWNSRV.PBL                            ..\pb6\adk\pfc
                                                   
PFCUTIL.PBL    其他服务需要的对象,例如DEBUG服            ..\pb6\adk\pfc
PFEUTIL.PBL    务和SQL测试服务等                ..\pb6\adk\pfc

PFESECAD.PBL    包含安全管理服务需要的各类对象            ..\pb6\adk\pfc\security

PFCECSC.PBL    包含安全检测需要的各类对象            ..\pb6\adk\pfc\security

PFCOLD.PBL    存放新版PB基础类库淘汰的各种对象            ..\pb6\adk\pfc

  注:基于PowerBuilder5.0版基础类库开发的应用升级到6.0版时,用户必须将PFCOLD.PBL添加到检索路径当中才能够顺利地实现升级。
  以上是PowerBuilder基础类库在PBL文件中的分布。


        如何安装PFC的升级版
  在PowerBuilder从一个正式版本升级到另一个正式版本时,还定期发布一些修正版本。作为PowerBuilder升级版的附加部份,每个修正版也包括了新的PFC升级版,对使用旧版PFC编制的应用程序来说,将面临一个PFC的升级问题。但由于PFC这种将不同层次的对象存放在不同的库文件中给我们的升级带来了极大的方便。
  这可能出现以下两种情况:
  (1)使用旧版PFC时,并没有对PFC的祖先层和扩展层做任何扩充和修改,只是直接通过继承使用PFC。如果是这种情况,简单地安装新版的文件覆盖旧版的文件。
  (2)使用旧版PFC时,创建了一个或多个中间扩展层,或对PFC的扩展层进行了修改和扩充。如果是这种情况,需确保新建的中间层和所做的扩充不被新版程序覆盖。可以按以下步骤进行版本升级:
  a. 将所有的PFC扩展文件备份到另外一个目录,确保新程序安装时不被覆盖。
  b. 查看当前的版本信息。可以在当前PFC的Readme.txt文件中找到有关的版本信息,或者在pfc_n_cst_debug中定义的实例变量majorrevision . minorrevision . fixesrevision中得到当前的版本信息。
  c. 运行新版的安装程序,用新的PFC文件覆盖旧的文件,PFC祖先层得到更新。
  d. 合并新的扩展层对象和旧的扩展层对象。查看新版PFC的Readme.txt文件,有一个新增扩展层对象的列表,可用以下两种方法进行合并:
  <1>把新增的扩展层对象全部全部复制到以前定制的PFC扩展层PBL文件中。从新版的PFC扩展层PBL文件中找出新添加的对象,并反它复制到以前定制的PFC扩展层PBL文件中。然后将新版的PFC扩展层文件移走,将备份的扩展层文件恢复到PFC路径下;
  <2>将定制的对象复制到新版的PFC扩展层中。将备份的PFC扩展层PBL文件中的所有对象复制到新版PFC的扩展层PBL文件中。
  e 启动PowerBuilder。
  f (可选地)根据情况更新应用物搜索路径。
  g 打开库管理面板,将应用重建。



  二、使用n_tr与SQLCA建立链接。
  1、打开应用对象面板,打开“Properties”(属性)设置窗口。
  2、点击“General”页面的“Additional Properties”按钮,我们将看到如图5所示的设置窗口。
  3、切换到“Variable Types”标签页,,如图6所示。
  4、将“SQLCA”下的输入框中的“transaction”改为“n_tr”。
  5、点击“OK”按钮,返回到应用对象设计面板,保存修改。

  ***理论知识:关于n_tr
  n_tr是一个从系统事务对象继承而来的定制的事务对象。这个定制的事务对象中包含了实例变量、事件和函数,扩展并封装了数据通信服务。
  n_tr提供了一套标准的函数完成数据库的链接、断开、提交和恢复,可帮助程序员管理事务对象。
  程序员可用n_tr内的函数代替原先的SQLCA事务对象管理命令。例如:链接数据库用of_Connect函数取代CONNECT命令语句。
  假设应用程序使用了多个事务对象,程序员可以使用事务对象注册服务提供的函数,完成对多个事务对象的管理。如:提交所有打开的事务或回滚所有打开的事务。

  三、创建一个应用管理器。
  ㈠关于应用管理器:
  PFC在应用管理器中控制各种应用的处理过程。这策略的优点有:1、可扩充性;2、可重用性。

  ㈡我们通过继承n_cst_appmanager创建应用管理器。具体步骤如下:
  1、点击工具条上的“Inherit”(继承)按钮,弹出“Inherit From Object”对话框,如图所示。
  2、在“Application Libraries:”下的库文件列表中选中Pfeapsrv.pbl,在显示的用户对象列表中选中。然后,在显示的用户对象列表中选中“n_cst_appmanager”,点击“OK”按钮,将出现如图所示的用户对象设计面板。
  3、保存该用户对象:将其保存到Design.pbl库中,命名为:n_cst_designmanager。    

  ㈢应用管理器一般用于完成以下功能:
  1、初始化应用程序的全局变量,如:帮助文件名;INI文件名;注册信息等等。(在Constructor事件中完成)
  2、(可选)控制用户的登录。(在pfc_open事件中完成)
  3、使用事务对象注册服务注册SQLCA。如果需要控制用户的登陆,则该事件在pfc_LogonDlg事件中写,否则在pfc_open中写。
  4、打开应用程序的初始化窗口。这一事件一般就在pfc_open事件中完成。

  具体分析及代码:
  1、Constructor事件的代码:
    this.of_SetAppIniFile("Design.ini")
    this.of_SetHelpFile("Design.hlp")
    this.of_SetLogo("Design.bmp")
    this.of_SetCopyRight("CopyRight by BS2001")
    this.of_SetVersion("版本  0.1")

  ***理论知识:
  注意以述代码,这里使用了调用PFC对象里封装了服务、功能的最基本、直接的方法:通过调用PFC函数启用相应功能。
  几乎所有的PFC函数都是对象函数,这些函数都定义在PowerBuilder的对象(如:窗口、菜单和用户对象)中。封装在PowerBuilder的对象中的函数可以使用户很快地明白该对象提供了什么样的功能。
  PFC函数使用了Set/Get/Is的命名规则来控制对实例变量的访问:
  of_Set    函数可设置实例变量的值
  of_Get    函数可访问非布尔型的实例变量
  of_Is    函数可确定布尔型的实例变量的状态值

  对于其他类型的实例变量,例如公用的实例变量,可以直接对它们进行操作。此外,还有一些变量仅供内部使用,外部函数不需也不能对它们进行操作。

  调用PFC对象函数的注意事项:
  (1)首先要确信已创建了该对象的一个实例
  PowerBuilder在窗口打开时创建窗口、菜单和可视用户对象,还可以使用of_Setservicename函数(定义在u_dw、n_cst_appmanager和w_master中)创建更多的类用户对象。例如,u_dw对象函数产生一个排序的服务并在实例变量inv_sort中存入一个该服务的引用,程序员可以把调用这个函数的代码写在数据窗口的Constructor事件中。如:
    this.of_Setsort(TURE)
  一些PFC对象使用了PowerBuilder的自动实例化特性,这些对象没有设置实例化函数,PowerBuilder在使用它们定义一个变量时自动为其创建实例对象。

  (2)在应用程序中正确地调用对象函数
  下面的例子使用了排序服务,指定了按数据窗口的列名进行排序、按显示的值或点击的列进行排序,当用户选择菜单条的“View”-“Sort”项时,显示一个具有拖动风格的对话框:
    this.inv_sort.of_SetColumnNameSource(This.inv_sort.HEADER)
    this.inv_sort.of_SetUseDisplay(TRUE)
    this.inv_sort.of_SetColumnHeader(TRUE)
    this.inv_sort.of_Style(This.inv_sort.DRAGDROP)




  2、控制用户的登陆:
  在应用管理器的pfc_open中写如下代码:
    integer li_rc
    li_rc=of_LogonDlg()
    if li_rc=1 then        //写成功登陆的代码...
        open(w_design_frame)    //这是最常见的成功登陆后的事件:完成上述第4步的工作:打开应用程序的初始化窗口。具体分析见下面的“创建一个框架(frame)窗口”部份。
    end if

  代码分析:
  of_LogonDlg函数的使用:该函数会调用w_logon(PFC中的登陆窗口)。当用户输入的必要信息:用户名称及登陆密码后,并按下该窗口中的“确定”按钮,程序会调用该窗口的pfc_default事件,其中一行关键代码会调用应用管理器中的pfc_Logon事件,并会传递两个参数:sle_userid.text和sle_password.text给pfc_Logon事件。而且,w_logon的pfc_default事件会接收pfc_Logon的返回值作相应的处理,主要是:用户输入信息合法的处理及如果用户输入的信息不合法,还可以重试的次数(详见以下的代码分析)。当w_logon关闭时,它会返回一个整型的值给of_LogonDlg:返回值为1时,代表用户信息合法;为0时,表示用户按了“取消”按钮,取消登陆;为-1时,表示用户信息不合法。所以,在调用of_LogonDlg后,可以作相应的处理,见上述代码。

  注意:如果你调用了of_LogonDlg函数,一定要在应用管理器的pfc_Logon事件中写相应的连接数据库的代码,也就是完成第3步的工作:使用事务对象注册服务注册SQLCA。of_LogonDlg执行的第一个代码就是调用pfc_Logon事件初始化登陆参数。见以下代码:
  在应用管理器的pfc_LogonDlg中写如下代码:
    SQLCA.DBMS = "ODBC"
    SQLCA.AutoCommit = False
    SQLCA.DBParm = "ConnectString='DSN=New_City;UID=' " + as_userid + " ' ;PWD=' " + as_password + " ' '"

    //以下4行代码就是判断是否成功登陆,如果是,则返回1给w_logon,否则,返回-1。
    if SQLCA.of_Connect() <> 0 THEN
        Return -1
    else
        Return 1
    end if

  ***小技巧:在用户登陆数据库时,当用户输入的信息不合法时,如何控制用户重试的次数?
  w_logon中的pfc_default事件是通过一个变量:ii_logonattempts来控制的。要设置该变量的值,可以在应用管理器的pfc_prelogondlg事件中写如下代码:
    anv_logonattrib.ii_logonattempts = 3    //“3”就代表用户可以重试的次数是3次。
    anv_logonattrib.is_logo ="logo.bmp"    //指定显示在登陆窗口上的图片。
  anv_logonattrib是一个n_cst_logonattrib类型的对象,是pfc_prelogondlg事件的一个参数,当调用(触发)pfc_prelogondlg事件时,会传递这个参数过来。n_cst_logonattrib中封装了如下的变量:
    Public:
    integer    ii_rc = -99
    integer    ii_logonattempts = 1
    string    is_userid
    string    is_password
    string    is_logo
    string    is_appname
    powerobject    ipo_source
  以上各个参数一般都于pfc_prelogondlg事件中设置。以上各个参数的含义及作用请参阅n_cst_logonattrib的帮助。

  ***触类旁通:
  与n_cst_logonattrib相类似的结构还有很多,它们主要用于控制一些属性的设置。具体请参阅PB的在线帮助:PowerBuilder Foundation Class Library (PFC)下的Global Structures and Structure Objects项。
  这些结构对象统称为属性对象(attribute object)。PFC包含了一些专门提供属性服务的用户对象。这些用户对象特有以下特点:
  a. 内含共有的实例变量;
  b. 可自动实例化;
  c. 对象名以attrib结尾;
  d. 经常被用来为pfc_pre事件处理程序传递消息,如:pfc_preAbout事件;
  e. 具备了可扩充性。可以追加自定义的实例变量。

  鉴于这些对象可以灵活方便地进行扩展,PFC使用它们代替了结构。
  除了可定义附加的公共实例变量以外,还可以使用可存取级控制和对象函数进一步定制对象的行为,如下表所示:







  一般来说,还经常在应用管理器中设置的的全局变量还有:
  ①n_cst_aboutattrib:在pfc_preabout事件中设置,主要用于控制“关于”的信息。要在程序启动时调用“关于”窗口,请于pfc_open中调用函数of_about。(下文还有详细介绍“关于”窗口的使用的内容)
  ②n_cst_splashattrib:在pfc_presplash事件中设置,主要用于控制“启动屏幕”的信息。要在程序启动时显示“启动屏幕”,请于pfc_open中调用函数of_splash。(下文还有详细介绍“启动屏幕”窗口的使用的内容)

  四、定义全局变量。
  PFC在程序运行时使用全局变量gnv_app来实现应用管理器的功能,具体步骤如下:
  1、打开应用对象设计面板。
  2、定义全局变量,并将其类型设为:n_cst_designmanager(即第三步里设计的用户自定义对象):
    n_cst_designmanager gnv_app
  注意:这个全局变量的名称一定要为gnv_app,不可更改。定义gnv_app为n_cst_designmanager的类型后,程序员可以象访问n_cst_designmanager一样访问在n_cst_designmanager中新增的变量、用户事件和函数。
  3、在“Open”事件中加入如下代码:
    gnv_app = CREATE n_cst_designmanager
    gnv_app.Event pfc_open(commandline)
  4、在“close”事件中加入如下代码:
    gnv_app.Event pfc_Close()
    DESTROY gnv_app
  5、保存修改。

  至此,前期的准备工作已经完成了,下面,我们将进入利用PFC进行正式的程序界面、功能的设计。

//------------------------------------------------------------
04创建框架
//------------------------------------------------------------
        第二部份 程序框架的构建

一、创建应用界面的第一步:创建一个框架(frame)窗口
  创建一个典型的多文档应用,先要定义一个多文档的frame窗口。在这个frame窗口中可以打开多个sheet窗口。PFC提供了w_frame类,它包括了许多文档的特征,如:状态提示条和sheet窗口管理。
  一个MDI应用程序的典型方案:使用w_frame,w_sheet窗口作为你的框架窗口与表单窗口的父类。在w_sheet窗口中增加你的应用程序中所有表单窗口需要的事件、实例变量、函数。你必须为每一个表单窗口定义菜单。
  第一步:通过继承w_frame创建一个后代frame窗口
  具体步骤:
  1、点击工具条上的“Inherit”(继承)按钮,弹出“Inherit From Object”对话框,如图所示。在“Object Type”处选“Windows”。
  2、在“Application Libraries:”下的库文件列表中选中pfemain.pbl。然后,在显示的窗口对象列表中选中“w_frame”,点击“OK”按钮,将出现如图所示的窗口对象设计面板。
  3、修改一些必要的属性:如,可以将窗口的“Title”的属性改为:“PFC设计实战”。
  4、保存该窗口对象:我们一般将其保存到Design.pbl库中,命名为:w_design_frame。

  第二步:根据需要添加一些必要的代码。
  一般地,框架窗口(frmae)主要是用来调用实际的功能模块的,也就是打开相应模块的表单窗口(Sheet)。所以,我们一般要在frmae窗口的pfc_open中写入如下代码:
    string ls_sheet
    w_sheet lw_sheet
    ls_sheet = Message.Stringparm
    OpenSheet(lw_sheet,ls_sheet,this,0,Layered!)

  这段程序打开了一个由Message.StringParm参数指定的sheet窗口,这么参数一般是由菜单的clicked事件触发时传递过来,这在创建菜单对象的章节再详述。请大家注意:在第3行代码中,出现了一个PowerBuilder中一个非常重要、应用非常广泛的概念:消息路由(Message Router),在以后的应用中,经常要使用到Message.StringParm来传递信息,例如窗口的名称。
  PFC使用消息路由控制窗口和菜单之间的通信,这个定制的消息传送结构被加载到所有的PFC菜单和窗口中。消息路由可以在任何类型的对象和窗口之间实现通信,但常用的还是在菜单和窗口之间传送信息。它根据定义好的规则将消息传递给正确的接收对象。
  使用信息路由,有以下的优点:
  a. 在菜单的脚本程序中只需知道需调用的事件,而不必关心当前的窗口或其他链接对象的名称;
  b. 窗口中的用户事件简单地调用数据窗口中的事件,这样减少了对窗口事件的维护。

  通过消息路由传递的信息实际上就是包含了用户事件名称的一个字符串,窗口或其他的控件接收到传来的信息后,触发相应的事件。
  信息路由还内置了调试信息,可以在出现错误时自动提示错误信息。
  当用户选择了某一菜单项,这个菜单项的Click事件被触发,调用菜单的of_SendMessage函数传送要调用的用户事件名。of_SendMessage函数又调用了n_cst_menu中的of_SendMessage函数,该of_SendMessage函数调用了窗口的pfc_MessageRouter事件,在这里激活指定的事件。

  针对MDI和SDI这两种不同风格的程序设计方式,PFC调用消息路由年度计划芤有所不同。如图所示。

  pfc_MessageRouter用户事件调用传来的指定事件,该事件可以是定义在窗口、当前的控件或激活的数据窗口中。如图所示。

  消息路由是进行菜单和窗口间通信的主要工具。除数据窗口外,不能使用命令按钮调用pfc_MessageRouter事件。这是因为消息程序调用了GetFocus事件访问当前的控件,如果点击了一个命令按钮,将访问它本身。


  还可以根据需要,在pfc_PreOpen事件中开启框架窗口提供的服务,如:
    this.of_SetSheetManager(TRUE)    //开启sheet窗口管理服务,它提供了最小化所有sheet窗口和恢复最前一个sheet窗口排列的命令。
    this.of_SetStatusBar(TURE)        //开启状态提示服务。
    this.inv_statusbar.of_SetTimer(TRUE)    //把时间和日期显示在状态条上。

  第三步:修改应用管理器,在n_cst_designmanager的pfc_Open事件中加入打开框架窗口w_design_frame的代码。详见第一部份第三章:创建一个应用管理器里关于控制用户的登陆的代码。

  二、创建菜单
  在PFC应用程序中,所有菜单都是由m_master或它的后代窗口继承而来的,程序员根据需要增加、修改或隐藏一部份菜单项。m_master为所有PFC窗口、数据窗口和可视化控件提供了相应的菜单项。
  在pfewnsrv.pbl库内,有两个菜单对象:m_master和m_frmae。m_master直接继承自菜单对象的最原始祖先:pfc_m_master,自m_master后的菜单都是继承m_master所得。一般典型的应用是:使用m_master作为应用程序Sheet窗口的祖先菜单,使用m_frame作为应用程序的Frame窗口菜单。程序员可以在m_master菜单中加入所有应用菜单都要使用的特定菜单项,然后创建一个由m_master继承而来的Sheet窗口菜单,并在恰当的时候控制这些菜单项是否有效。m_frame由m_master继承而来,作为Frame窗口菜单,一般只具有调用相应的功能模块的功能,其它菜单项都可以隐藏起来。。
  m_master中包含了一些标准的菜单项,可调用相应窗口中的事件处理,使用时应注意以下几点:
  1、如果某一菜单项对当前窗口无效,应使之不可见;
  2、如果菜单项支持对当前窗口的操作,应查看当前-窗口中相应的用户事件处理程序。
  每一个m_master菜单项都会触发相应的事件,但有些事件中并没有编写任何程序代码。程序员必须添加事件处理程序以完成特定的功能。

  具体步骤及代码分析:
  下面将为应用程序创建一个主菜单,由m_master继承而来,具体步骤如下:
  1、点击工具条上的“Inherit”(继承)按钮,弹出“Inherit From Object”对话框,如图所示。在“Object Type”处选“Menus”。
  2、在“Application Libraries:”下的库文件列表中选中pfewnsrv.pbl。然后,在显示的菜单对象列表中选中“m_master”,点击“OK”按钮,将出现如图所示的菜单对象设计面板。
  3、保存该菜单对象:我们一般将其保存到Design.pbl库中,命名为:m_design_master。

  下面将通过继承m_design_master创建一个frame菜单。注意:frame菜单仅用于frame窗口,而frame窗口的功能仅仅用于调用相应的功能模块的sheet窗口,所以,frame菜单中有很多功能是没用的,所以,需要将那些不用的菜单项隐藏起来。具体步骤如下:
  1、点击工具条上的“Inherit”(继承)按钮,弹出“Inherit From Object”对话框,如图所示。在“Object Type”处选“Menus”。
  2、在“Application Libraries:”下的库文件列表中选中Design.pbl。然后,在显示的菜单对象列表中选中“m_design_master”,点击“OK”按钮,将出现如图所示的菜单对象设计面板。
  3、将没用的菜单项隐藏起来。
  4、保存该菜单对象:我们一般将其保存到Design.pbl库中,命名为:m_design_frame。

  以上创建的m_design_master菜单将作为整个应用程序的菜单祖先,以后凡是用到菜单的地方都将从m_design_master中继承而来。


  三、将菜单链接到窗口上。
  目前,我们只是创建了一个窗口:w_design_frame。它将是应用程序运行后看到的第一个窗口,应用程序的所有功能模块的sheet窗口都将从它的菜单项里调用。我们将菜单m_desing_frame链接到该窗口上。
  步骤如下:
  1、打开w_design_frame窗口。
  2、在“Properties(属性)”窗口里设置“General”页面里的“MenuName”属性,点击选择图标,选择Design库中的m_design_frame作为窗口的菜单。
  3、保存修改。

  好了,现在请按下工具条上的“Run”(运行)按钮,你将可以看到如图的运行界面。注意:如果此时你还没有必要连接数据库,请将应用管理器的pfc_Open事件中的这一行代码注释掉:li_rc=of_LogonDlg()。



//------------------------------------------------------------
05功能模块
//------------------------------------------------------------

        第三部份 功能模块的设计
  一、建立一个数据窗口对象。
  1、点击工具条上的“New”(新建)按钮,从弹出的对话框中选择“DataWindow”页面,再选择“Grid”,按“OK”按钮,开始创建一个风格风格的数据窗口对象。
  2、在如图的“Choose Data Source for Grid DataWindow”窗口中,选择“Quick Select”,按“Next”按钮。
  3、在如图的“Quick Select”窗口,在“Tables”列表框中选择“employee”表,然后,点击“Add All”按钮,全部选中“Columns”列表中的所有字段。单击“OK”按钮。
  4、在如图的“Select Color and Border Settings”窗口中,单击“Next”按钮。
  5、在如图的“Ready to Create Grid DataWindow”窗口中,单击“Finish”按钮。
  6、我们将看到如图的数据窗口对象设计面板。将该数据窗口对象保存到Design.pbl库中,命名为:d_employee。

  二、建立第一个sheet窗口
  本节将通过继承PFC的w_sheet窗口创建一个多文档sheet窗口。
  具体步骤:
  1、点击工具条上的“Inherit”(继承)按钮,弹出“Inherit From Object”对话框,如图所示。在“Object Type”处选“Windows”。
  2、在“Application Libraries:”下的库文件列表中选中pfemain.pbl。然后,在显示的窗口对象列表中选中“w_sheet”,点击“OK”按钮,将出现如图所示的窗口对象设计面板。
  3、修改一些必要的属性:如,可以将窗口的“Title”的属性改为:“员工资料”。
  4、保存该窗口对象:我们一般将其保存到Design.pbl库中,命名为:w_employee。

  三、在窗口上增加一个数据窗口控件
  注意:应用PFC编程时,我们不应再用PowerBuilder的标准控件了,而应该用PFC中的用户对象。
  具体步骤:
  1、点击工具条上选择控件的图标旁边的倒三解按钮,从弹出的下拉选择框中选择“Create User Object control”,将弹出“Select Object”对话框,如图所示。
  2、在“Application Libraries:”下的库文件列表中选中pfemain.pbl。然后,在显示的用户对象列表中选中“u_dw”,点击“OK”按钮返回。
  3、在窗口设计面板上点一下,将在窗口上增加一个数据窗口控件。
  4、修改数据窗口控件的名称:在“Properties”(属性)窗口的“General”页面设置“Name”属性为:dw_employee。
  5、修改数据窗口控件连接的数据窗口对象:在“Properties”(属性)窗口的“General”页面设置“DataObject”属性:点击“DataObject”下的输入框旁的按钮,将弹出如图的数据窗口对象选择框。首先在“Application Libraries:”下的库文件列表中选中Design.pbl。然后,在显示的数据窗口对象列表中选中“d_employee”,点击“OK”按钮返回。
  6、修改一些常用的属性:在“Properties”(属性)窗口的“General”页面的“HScrollBar”属性前的复选框打勾,为数据窗口控件增加一个水平滚动条(默认只有垂直滚动条)。
  7、保存窗口对象的修改。

  四、创建w_employee窗口的菜单
  1、点击工具条上的“Inherit”(继承)按钮,弹出“Inherit From Object”对话框,如图所示。在“Object Type”处选“Menus”。
  2、在“Application Libraries:”下的库文件列表中选中Design.pbl。然后,在显示的菜单对象列表中选中“m_design_master”,点击“OK”按钮,将出现如图所示的菜单对象设计面板。
  3、保存该菜单对象:我们一般将其保存到Design.pbl库中,命名为:m_employee。

  五、将菜单链接到w_employee窗口上
  1、打开w_employee窗口设计面板。
  2、修改w_employee窗口的属性:在“Properties”(属性)窗口的“General”页面设置“MenuName”属性:点击“MenuName”下的输入框旁的按钮,将弹出如图的菜单对象选择框。首先在“Application Libraries:”下的库文件列表中选中Design.pbl。然后,在显示的菜单对象列表中选中“m_employee”,点击“OK”按钮返回。
  3、保存修改。

  六、代码的编写
  1、在数据窗口控件的Constructor事件中写入如下的代码:
    this.of_SetRowSelect(TRUE)    //激活数据窗口控件的行选择功能。
    this.of_SetRowManager(TRUE)    //激活数据窗口控件的行管理功能。
    this.of_SetSort(TRUE)    //激活数据窗口控件的排序功能。
    this.of_SetProperty(TRUE)    //激活数据窗口控件的属性选择功能。
    this.of_SetTransObject(SQLCA)    //设置数据窗口控件的事务对象。

    this.inv_rowselect.of_SetStyle(dw_employee.inv_rowselect.EXTENDED)    //对行选择服务进行初始设置。
    this.inv_sort.of_SetStyle(dw_employee.inv_sort.DRAGDROP)    //对排序服务进行初始设置。
    this.inv_sort.of_SetColumnHeader(TRUE)

    //以下代码用于完成数据的检索。
    If this.of_Retrieve() = -1 Then
        SQLCA.of_Rollback()
        Messagebox("错误","数据不能正确查询!")
    Else
        SQLCA.of_Commit()
        this.SetFocus()
    End If

  2、在数据窗口控件的pfc_retrieve事件中写入如下的代码:
    Return this.Retrieve()    //从数据库中检索出需要的数据。

  3、在窗口的pfc_preopen事件中写入如下的代码:
    this.of_SetResize(TRUE)    //激活窗口对象的调整大小的服务。
    this.inv_resize.of_Register(dw_employee,0,0,100,100)        //对dw_employee控件设置调整大小服务,并进行初始设置。

  4、保存修改。

  这样,一个具有基本功能的MIS的应用程序已经编写完成了。下面,让我们来看一看它可以完成什么工作吧:

//------------------------------------------------------------
06报表
//------------------------------------------------------------
        第四部份 报表的设计

  作为一个信息管理系统,报表输出是不可或缺的一部份。PFC对报表输出也提供了强大的支持。下面,让我们齐来看一看怎样用PFC设计一张报表。
  一、设计报表窗口
  为了方便起见,我们就将第三部份所做的w_employee窗口对象修改一下,改成一个报表窗口。
  1、打开w_employee窗口设计面板。
  2、修改数据窗口控件的Constructor事件的代码,将原来的代码全部删除,修改为:
    this.of_SetReport(TRUE)    //激活报表服务
    this.of_SetPrintPreview(TRUE)    //激活打印预览服务
    this.of_SetTransObject(SQLCA)    //设置事务对象
    this.of_SetUpdateable(FALSE)    //将数据窗口控件设置为不可更新

    //以下代码用于完成数据的检索。
    If this.of_Retrieve() = -1 Then
        SQLCA.of_Rollback()
        Messagebox("错误","数据不能正确查询!")
    Else
        SQLCA.of_Commit()
        this.SetFocus()
    End If
  3、保存修改。



  一个以PFC为开发基础,具有一定数据管理能力的信息管理系统就编写完成了。回头看一看:程序代码写了还不够一百行,但却可以实现大部份信息管理系统的功能,是不是为PFC的强大威力而叹服呢?不过,PFC的应用博大精深,以上介绍的只是PFC的入门知识。要想掌握PFC的精髓,还要你不断地深入学习,同时,将你学到的新元素加到上面那个程序里面,实际应用一下,看一看运行的效果,不断地探索、尝试。

雁过留声,人过留名
2008-9-24 13:37
freele_china
Rank: 12Rank: 12Rank: 12
来自:JiNan
等级:版主
威望:6
帖子:342
积分:3927
注册:2007-4-6
关于PFC

关于PFC

这一章介绍的是PFC的基础,PB的首要概念,面向对象的内容,并附有一个PFC的
组成图。

理解PFC:
PFC是一组PowerBulider的对象,它可以由用户自己定制,扩充。你可以象搭积木
一样使用它,使程序紧密的连接起来。PFC还包括许多有用的对象,例如:debug对
象。
PFC是由PowerBuilder提供的PB对象,并支持PowerScript 源代码。它使用的是先
进的PowerBuilder面向对象技术,其一个特征是面向服务设计。确使你的程序占
用最少的计算机资源。
PFC使用了许多先进的编码技巧,你可以使用PowerBuilder的PowerScript编译器
来检查对象,实例,事件,和继承PFC父类的函数。
这本书说的是PFC的概念(PFC是什么东西和你为什么使用它)还有使用信息(如何计
划.使用PFC)
为了更详细的了解PFC的对象,实例,事件,和继承PFC父类的函数,请看PFC Object
Reference 。

理解PowerBuilder:
使用PFC可以创建先进的面向对象式的PowerBuild类库。要想掌握PFC和它的面向
对象特征,首先需要了解PowerBuilder和它的面向对象特征。这一节将告诉你应
该熟悉PowerBuilder的基本概念。
PFC原是为建类库准备的,但并不是不让你用它创建应用程序。通过看PowerBuild
er User's Guide可以完全了解的PowerBuilder的概念。

PowerBuilder类库和对象:
PFC是作为PowerBuilder Libraries(PBLS)发行的。PBLs包括你用于写程序的父类
和派生类对象。在使用任何PFC对象之前,你一定要在你的应用程序库的搜索路径
中把PFC类库加进去。PowerBuilder在执行程序时通过搜索路径找到程序所引用的
对象。

PB标准对象 用途
Windows PowerBuilder应用程序和它的用户之间的联系界面。
Menus 用户在当前活动窗口用来搜索命令的表。
DataWindow objects 用于接收,实时处理数据。
User objects 由用户自己定义的对象(一次定义可以重复使用)。
User objects 有两种类型:
(一):Visual user objects (可视化用户对象)
一个可视化用户对象是一个可以重复使用的可视化控制,或者是一批预先确定的可
视化控制.PFC包括两种可视化用户对象类型.
1.标准的可视化用户对象类:
PFC提供了一套丰富的标准的可视化用户对象.每个PFC的标准的可视化用户对象都
相当于一个PowerBuilder的窗口控件.这些对象包括以PFC服务预想确定完全的综
合操作。 特别值得一提的是u_dw DataWindow 用户对象,这是以PFC服务来提供
广泛的综合功能。
2.用户自定义的可视化用户对象
PFC也提供了用户自定义的可视化用户对象,这些对象包括一组窗口控件,并提供
先进的函数用在某些特别情况。 (PFC没有使用外部用户对象和VBX用户对象,要
想进 一步了解可视化用户对象,请看"PowerBuilder User's Guide")
(二):Class user objects(非可视用户对象类)
一个非可视用户对象是一个用来实现非可视的处理时使用的控件。PFC包括两种非
可视用户对象类型。
1.标准的非可视用户对象:
标准的非可视用户对象是继承 PowerBuilder内嵌的系统对象而来。PFC提供了许
多标准的非可视用户对象,例如:处理事务,错误对象,和其他所有的扩展系统对
象。
2.用户自定义的非可视用户对象:
用户自定义的非可视用户对象是继承 PowerBuilder非可视对象类而来,它把数据
和代码进行封装。这种类型的用户对象允许你从SCRATCH定义一个对象。
PFC用Class user objects来执行它的许多服务以及提供这些服务对象的函数。它
也提供?reference variables(引用变量),何谓 rdference variables呢?即是
一个对象指针。你可以用它来存取一个对象的实例变量,函数,事件。

Functions(函数):
PowerBuilder支持全局函数和对象函数。PFC通过user_object function执行它的
处理。一个函数就是执行一些处理的PowerScript语句的集合,你可以传递数据或
者是什么也不传,它来返回一个值。
详细信息册参考PFC Object Reference。

Events and user events(事件和用户事件):
PowerBuilder的Windows,user objects,contols,都有一些预先设定的事件。PFC
通过定义用户事件为许多PFC 对象增加事件。事件可以接受数据和返回值。共有
三种PFC 事件:

事件类型 触发时间
PowerBuilder预先设定的事件 某个动作导致操作系统调用事件
预先编好代码的用户事件 某个动作(例如选择一个菜单)导致PFC触发用户事件

空的用户事件(可以加入代码) 某个动作(例如选择一个菜单)导致PFC触发用
户事件
除非另有说明,本书的event都指的是这三种。

Function and events compared (函数和事件比较)

函数和事件在许多方面都是相似的:
(1)他们都可以接收数据,返回值;
(2)他们都由PowerBuilder语句构成;
(3)他们都可以被调用,触发,传递。
但他们还是有些不同的:
使用特征 函数 事件
调用一个不存在的 将会出现运行时错误 TriggerEvent返回-1
覆盖父类脚本 直接覆盖父类脚本 可以扩展或者覆盖
访问 可以是Public、Private、Protected 永远是Public
重载 可以重载 不可以重载

面向对象式的设计
面向对象的编程工具支持三个基本规则:inheritance(继承),encapsulation
(封装),polymorphism(多态)。

如何使用PFC扩展层:
在PFC中没有类库完全适合你的需要,你可以代表性的修改PFC来满足你的程序的
需要。假如没有PFC扩展层,就会出现一个问题:当PFC版本升级时,新版本的PF
C恢复该这些修改,而你不得不用手工改变。

一个特别的扩展层:
PFC产生一个扩展层是通过继承所有的层实现的。所有的扩展对象都在单独的PBL
S,这在PFC升级时不会影响。

内容 祖先层
Application and global services PFCAPPSRV.PBL
DataWindow services PFCDWSRVPBL
Visual and standard class user objects PFCMAIN.PBL
Utility services PFCUTIL.PBL
Window services PFCWNSRV.PBL

祖先层的类库中的对象包括所有的实例变量,事件,函数;扩展层的类库中的对
象是相应祖先层类库中的对象的不可修改的子类。即使是继承,也可以访问祖先
的实际变量,事件和函数。
通过PowerBuilder Bowser来察看子类的对象的实际变量,事件和函数。

使用扩展层有二个优点:
1. 你可以增加一些点,部门,还有程序逻辑。
2. 不会影响版本升级。

旧版本对象:
PFCOLD。PBL Library包含旧的对象。如果你有一个存在的PFC程序,你有可能需
要把他加在你的library list.

注意:
你要通过修改扩展层的对象来定制PFC程序。千万不要轻易修改祖先对象。你的程
序中的对象要使用扩展层的对象并且继承扩展层的窗口。

迅速开始:
在用PFC编程时,程序经常需要修改,存取,以及从扩展层中继承对象。PFC装置
中有一套扩展库(PFC Quickstart Libraries)。它包括扩展层的基本功能,使
你的程序快速发展。

PFC命名规则:
PFC遵循以下命名规则:
Level Name
PFC层对象 用前缀pfc_
扩展层对象 和它的祖先有同样的名字但没有前缀pfc_

例如:DataWindow selection service object的祖先是pfc_n_cst_dwsrv,扩展层
的子类是
n_cst_dwsrv.Pfc_n_cst_dwsrv 包括所有服务的代码。n_cst_dwsrv 是不可修改
的子类(你可以在假如程序指定的实例变量和代码。)。

PFC定义的用户事件:
PFC定义用户实践也用前缀pfc_prefix.这使得你的应用程序的用户事件和PFC 的
用户事件更加容易。

PFC文档使用扩展层名字
当指定一个服务对象时,PFC文档总是用扩张层命名。例如:当论述基类窗口时这
书指向w_master不是pfc_w_master.但要记住,w_master的实际变量,事件和可用
函数实际上是在pfc_w_master定义的。
PFC命名习惯详细资料请看PFC Object Reference

我们不难想到:
PFC的对象继承允许你在每一层假如扩展逻辑。例如:pfc_w_sheet是从w_master
继承的,w_master的实际变量,函数,你加在它的事件在它的子类窗口中都已存
在。

如何加扩展层
扩展层通过PFC升级类有效的实现应用程序内部的重用和单个程序的重用。但是,
在大部门或者是多部门合作时,一定要考虑好扩展的标准,方法,注意部门的规
则和商业规律。
如果你是在一个组织里使用PFC,你要考虑创建一个新层(包括这个组织的所有的
变量函数,事件)。应用程序还是使用PFC扩展库的对象,可是调用实例变量,事
件,函数的祖先变了。

PFC构成:
PFC是由以下构成的:
l 一套PBLS
l 一个数据库
l Quickstart PBLS
l 实例代码
l 一个简单的应用程序
Localized PFC(局部化的PFC)
局部化的PFC 将会在PFC新版本公布后升级。

The PFC PBLs
PFC是分布在PBLS包含的祖先对象和PBLS扩展层包含的对象。每个祖先对象扩张层
包含提供以下服务的对象
Libraries Contents
PFCAPSRV.PBLPFEAPSRV.PBL 应用程序管理器,应用程序服务对象和全局服务对象

PFCMAIN.PBLPFEMAIN.PBL 标准可视化用户对象,自定义可视化用户对象,标准用
户对象类。
PFCUTIL.PBLPFEUTIL.PBL 有用的对象和服务。
PFCWNSRV.PBLPFEWNSRV.PBL 窗口服务,包括用户对象和有用的窗口。
PFCOLC.PBL 旧的用户对象。(基层和扩展层的对象)

使用library画笔:
使用library画笔来看到PFC中所有对象

PFC 数据库
PFC装载了pfc.db本地数据库。这个数据库包括以下几个表:
Table Usage
Messages 错误信息服务。
Security_apps 安全服务。
Security_groupings 安全服务。
Security_info 安全服务。
Security_template 安全服务。
Security_users 安全服务。
PFC本地数据库是由开发者预先设定的,如果你要使用错误信息服务和安全服务一
定要在你的数据库中复制指定的表。连接”Deploying database tables”

The PFC Quickstart PBLs
使用PFC Quickstart libraries用来是程序配置和运行迅速。他们包括经过挑选
的PFC扩展层对象的保护子集。
做一个PFC Quickstart libraries备份,你就有了后援了。

The PFC code example
使用它是为了了解PFC的对象和服务。学习如何编码并且实现PFC的基本功能。Th
e PFC Quickstart有广泛的参照和使用资料。

The PFC sample application
使用PEAT可以看到PFC的例子是如何进行工程预算和跟踪系统的。


PFC编程基础


概要:
这一章阐述了 PFC 编程的基本技巧,同时也告诉了你如何开始运用 PFC 编写应
用程序。


设置应用程序管理器
首先建立一个PFC应用程序的第一步就是配置应用程序以及建立应用程序管理器-
-n_cst_appmanager。应用程序管理器将替代原来的应用程序对象。原来在应用程
序对象中编写的脚本将全部改写在应用程序管理器中。应用程序管理器中同时还
通过实例变量、函数来维护应用程序的属性。其中有框架窗口、应用程序与用户
的INI文件或注册键以及帮助文件等。

注意:
使用分开的物理文件
每个独立的应用程序都必须拥有自己独立的一套文件。你不可以共享父类文件,
也就是那些以PFC开头的文件。这是由PFC的内部继承关系而决定的。
例如,假设应用程序1与应用程序2都拥有它们自己的一套扩展的PFC库文件,但
是它们共享父类文件(PFC库文件)。这时应用程序1在自己的PFE(PFC扩展库)
的w_master中增加了一个函数名为of_SetData。这样这个函数将在w_master的所
有子类中都有效,这些子类是pfc_w_main,pfc_w_frame,pfc_w_sheet 等。而这
些对象恰恰在这两个应用程序共享的父类文件(PFC库文件)中。这样当应用程序
2重新生成应用程序时(regenerate)由于应用程序2的PFE文件中没有of_SetDat
a函数。这样w_master的所有子类中的关于of_SetData函数的指针都将被删除。这
样当应用程序1运行时将会导致运行时错误与编译错误。


具体步骤

1. 打开应用程序画笔。

2. 定义库文件列表。
PFCAPSRV.PBL
PFCDWSRV.PBL
PFCMAIN.PBL
PFCUTIL.PBL
PFCWNSRV.PBL
PFEAPSRV.PBL
PFEDWSRV.PBL
PFEMAIN.PBL
PFEUTIL.PBL
PFEWNSRC.PBL
PFCOLD.PBL(如果你的应用程序是使用老版本的PFC库那么请增加该文件到库列表
中)

3. 在应用程序画笔中打开脚本画笔,定义n_cst_appmanager类型的全局变量gnv
_app。
n_cst_appmanger gnv_app
这个变量名必须是gnv_app,因为PFC的对象、函数、事件都需要这个n_cst_appm
anager或它的子类的全局变量-gnv_app。

4. 增加如下代码到应用程序对象的OPEN事件中。它的用途是创建n_cst_appmana
ger、调用pfc_Open事件。
gnv_app = Create n_cst_appmanager
gnv_app.Event pfc_Open(commandline)

5. 增加如下代码到应用程序对象的CLOSE事件中。
gnv_app.Event pfc_Close()
Destroy gnv_app

6. 增加如下代码到应用程序对象的SystemError事件中。调用pfc_SystemError事
件。
gnv_app.Event pfc_SystemError()

7. 关闭应用程序画笔,保存所作的修改。

8. 打开用户自定义对象画笔。在PFEAPSRV.PBL中找到n_cst_appmanager并打开,
或者是它的子类。

9. 在n_cst_appmanager的构造事件(Constructor Event)中调用它的函数来初
始化关于软件版本号、公司、和INI文件的实例变量。

10. 在 n_cst_appmanager的pfc_Open事件中打开你所想要的应用程序Service 。

你所想打开的Service 调用函数
Application preference of_SetAppPreference
DataWindow caching of_SetDWCache
Error of_SetError
Most recently used object of_SetMRU
Transaction registration of_SetSecurity
Debug of_SetDebug

11. 在pfc_Open事件中增加打开你的初始窗口的代码,例如框架窗口(Frame Wi
ndow)或者调用显示快闪窗口的of_Splash()函数。

12. (可选)增加代码到pfc_PreAbout,pfc_PreLogonDlg,pfc_PreSplash事件
中,用于定制关于对话框(About box)、登录对话框(Logon box)、快闪窗口
(splash screen)。

13. (可选)增加代码到pfc_idle,pfc_ConnectionBegin,pfc_ConnectionEnd
事件中。
l_ 在应用程序对象的idle事件中调用pfc_idle事件。
l_ 在应用程序对象的ConnectionBegin事件中调用pfc_ConnectionBegin事件。

l_ 在应用程序对象的 ConnectionEnd事件中调用pfc_ConnectionEnd事件。

14. 保存n_cst_appmanager

如何显示快闪窗口
非常简单,只需在pfc_Open事件中,在打开第一个窗口的代码之前写上如下代码

this.of_Splash(1)
Open(w_tut_frame)(根据不同的应用程序有不同的变化!)

如何显示登录窗口
1. 在框架窗口的Open事件中调用of_LogonDlg函数:
Integer li_return
li_return = gnv_app.of_LogonDlg( )
IF li_return = 1 THEN
this.SetMicroHelp("Logon successful")
ELSE
MessageBox("Logon", "Logon failed")
Close(this)
End If
Of_LogonDlg函数将显示w_logon对话框,同时还会提示输入用户名、密码,当用
户点击OK按钮时还会触发n_cst_appmanager的pfc_Logon事件。
同样,你也可以在n_cst_appmanager的pfc_Open事件中的打开框架窗口之后立即
调用Of_LogonDlg函数。但是绝对不要在Of_Splash之后立即调用Of_LogonDlg 。


2. 在n_cst_appmanager的pfc_logon事件中编写登录到数据库的代码。这个例子
假设有一个INI文件,它包含了所有的需要登录到数据库的信息,除了用户名、密
码以外。同时还假设你已将SQLCA的默认类型改为n_tr(PFC制定的书屋对象类型
)。
Integer li_returnString ls_inifile, ls_userid, ls_password
ls_inifile = gnv_app.of_GetAppIniFile()
IF SQLCA.of_Init(ls_inifile,"Database") = -1 THEN
Return -1
END IF
// as_userid and as_password are arguments
// to the pfc_Logon event
SQLCA.of_SetUser(as_userid, as_password)
IF SQLCA.of_Connect() = -1 THEN
Return -1
ELSE
gnv_app.of_SetUserID(as_userid)
Return 1
End If

建立应用程序
建立一个MDI应用程序
使用w_frame,w_sheet窗口作为你的框架窗口与表单窗口的父类。在w_sheet窗口
中增加你的应用程序中所有表单窗口需要的事件、实例变量、函数。
你必须为每一个表单窗口定义菜单。
具体步骤:
1. 为应用程序在w_frame窗口中作特定的修改。最好是建立一个w_frame窗口的子
类,然后再修改这子类。
2. (可选)在w_sheet中增加实例变量、函数、用户自定义事件。
3. 建立继承w_sheet的表单窗口。
4. 建立一个框架窗口(frame window)用的菜单,通常是选用w_frame 。
5. 为框架窗口指定相应的框架窗口菜单。
6. 建立表单窗口的菜单
7. 为表单窗口(sheet window)指定相应的表单菜单。
8. 在n_cst_appmanager的pfc_Open事件中加入打开框架窗口的代码。
9. (可选)在必要时候,开启框架窗口Service 。
l_ 调用w_frame的of_SetStatusBar函数开启状态条Service 。
l_ 调用w_frame的of_SetSheetManager函数开启表单管理Service 。

在MDI应用程序中打开表单窗口:
1. 在菜单项的Clicked事件中编写有关打开表单窗口的脚本。你需要将表单窗口
的名称以字符串的形式传递给Message.StringParm,然后以pfc_Open为参数调用
of_SendMessage函数:
n_cst_menu lnv_menu
Message.StringParm = "w_products"
lnv_menu.of_SendMessage(this,”pfc_Open”)

2. 在w_frame的pfc_Open事件中访问Message.StringParm,打开指定的表单窗口

String ls_sheet
w_sheet lw_sheet

ls_sheet = Message.StringParm
OpenSheet(lw_sheet, ls_sheet, this, 0, Layered!)

建立一个SDI应用程序
在使用PFC建立SDI应用程序中,你将使用w_main窗口作为你的所有main类型窗口
的父类。为了使得你的事件、函数、实例变量能够在所有的窗口中都有效,只需
将它们加到w_main中。
如果你的窗口需要菜单,那么你必须为每一个窗口定义菜单。
具体步骤
1. 继承w_main窗口,建立一个main类型窗口,最为主窗口。最好是直接修改w_m
ain窗口。
2. 建立一个主菜单。
3. 根据需要建立其他的菜单与窗口。
4. 在n_cst_appmanager的pfc_Open事件中编写打开主窗口的脚本。

PFC编程过程中的函数使用方法
几乎所有的PFC函数都是对象级函数。这就意味着你必须定义POWERBUILDER对象后
才可以使用函数。经过PB封装后的函数使你很轻易的看到哪个函数属于哪个对象


PFC使用Set/Get/Is 命名规则来控制实例变量。
l_ of_Set函数允许你为实例变量赋值
l_ of_Get函数允许你获得一个非布尔类型的变量的值
l_ of_Is函数允许你确定一个布尔类型变量的真与假
其他类型实例变量的访问规则
PFC定义变量时同时指定为公共类型(public),那么你将可以随意直接访问。

另外,有些变量由于只是在内部使用,因此不能通过函数进行访问。
除了Set/Get/Is命名规则以外,PFC在为某一Service定义入口参数时使用Regist
er/UnRegister规则。例如,你可以调用u_calculator对象的of_Register函数来
定义Datawindow的那个列使用下拉日历。

Object qualificationPFC uses access levels (public, private, protected
) to control your access to functions designed for 内部自动调用 use.

When you call these functions from outside the object, use dot notatio
n to qualify the function name. Qualify the function name with the ref
erence variable used to create the object (in some cases you qualify t
he function name with the actual object name).

调用PFC对象函数
1. 确认对象是已否被创建
PowerBuilder在当窗口打开的时候会建立窗口、菜单和可视的用户对象。你
要使用函数of_Setservicename来建立大部分的不可视的用户对象。例如,下面u
_dw的对象函数创建了排序Service(n_cst_dwsrv_sort user object),并且在
u_dw’s中的实例变量inv_sort中保留它的引用。通常这些代码都在Datawindow的
构造事件中:
this.of_SetSort(True)
自动实例化对象
某些PFC对象利用了Powerbuilder提供的自动实例化功能。这些对象没有Set函数
。PowerBuilder会在它们声明的时候自动实例化它们。

2. 在应用程序中调用适当的对象函数
这个例子展示了排序Service将利用DataWindow的列名、排序已显示值、
实现当用户点击后排序。同时可以在菜单栏上显示下拉对话框。

this.inv_sort.of_SetColumnNameSource(this.inv_sort.HEADER) this.inv_s
ort.of_SetUseDisplay(TRUE) this.inv_sort.of_SetColumnHeader(TRUE)
this.inv_sort.of_SetStyle(this.inv_sort.DRAGDROP)

函数重载PFC使用函数重载提供了一个丰富的、富有弹性的编程接口。它通过两种
方法实现函数重载。
l_ 多种语法 多个函数具有不同的参数类型、不同的参数顺序。这使得PFC的函数
可以处理多种数据类型的参数。
l_ 随意的参数数目 许多函数拥有一个具有相同数据类型、相同顺序、参数数目
可以变化的参数。它同时还允许PFC为常用的参数提供默认值。

只用于内部处理所重载的函数
除了公有类型的重载函数以外,PFC通常还有一个保护类型的版本,一般都是用
来进行内部调用的。例如,n_cst_dwsrv_report中的of_Addline函数有4个公有类
型的版本、一个保护类型的版本。这个保护类型的版本是供其他4个调用的。虽然
有些时候可以调用这些保护类型的版本,但是他们纯粹是为了内部调用而设计的


关于PFC事件的编程
PFC包括了预代码的事件、用于实现PFC Service的用户自定义事件。还有一些空
的事件,你可以在其中为你的应用程序加入特定的代码,或者执行一些特定的任
务。所有的事件都是公有的,你可以直接访问它们。

“预代码事件”与其他的用户自定义事件
预代码事件指的是那些已经在PFC层对象中编号代码的事件。PFC拥有许多具有一
定功能的“预代码事件”。这意味着如果你开启了一个Service ,PFC的对象发现
该Service已开启了,那么这些“预代码事件”将会执行其中的代码。
例如:u_dw的Clicked事件就是一个“预代码事件”,它会自动调用那些开启的S
ervice函数。你可以扩展这些事件,但是不可以覆盖它们。

空的用户自定义事件
PFC定义了许多空的用户自定义事件。你可以在其中为你的应用程序写入特定的
代码。许多这种事件都是通过菜单而触发的。另外一些则是应用程序代码触发的

例如:
在u_dw中有一个用户自定义事件pfc_Retrieve ,你可以在其中加入检索数据的
代码。
Return this.Retrieve()
有关更多的关于PFC事件的内容请参考PFC Object Reference

PFC中的事件是如何起作用的
PFC是采用如下的方式调用Services中的事件的
1. 当用户触发某个对象的某个事件时,PFC将会调用相应的Service 的自定义事
件,同时传递相应的参数。例如:u_dw的clicked事件会调用n_cst_dwsrv_sort的
pfc_Clicked事件,同时传递X坐标、Y坐标、DW对象(这些其实也是DW的Clicked
事件的参数)。
2. 这些Services的事件同时还有可能调用其他对象函数。例如,n_cst_dwsrv_s
ort的pfc_Clicked事件中还调用了n_cst_dwsrv_sort的函数。
尽管你可以直接调用PFC的对象函数,但是调用相应的事件显得更简单,因为这些
事件中已经包括了错误检测代码。

关于事件触发前的一些处理
PFC有一种自定义事件名是Prename 。这意味着这些事件是发生在事件name之前的
事件。我们把它叫做pre_event 。你可以随意在pre_event中增加代码用于扩充相
应的事件处理能力。这些pre_event有:

pfc_PreAbout
pfc_PreClose
pfc_PreLogonDlg
pfc_PreOpen
pfc_PrePageSetupDlg
pfc_PrePrintDlg
pfc_PreRestoreRow
pfc_PreSplash
pfc_PreToolbar
pfc_PreUpdate

通常,这些事件中都有一个已经自动实例化了的用户对象的引用变量。这个对象
的属性可以影响这个事件的运行。你可以修改这个用户对象的属性,从而达到改
变事件的运行或扩展事件的运行效果。有些时候你还需要修改一些其他的对象。
例如,当你需要控制About对话框中的一个附加控件的显示效果时,你需要:
1. 扩展用户对象n_cst_aboutattrib ,在其中增加一个用于在w_about中代表显
示效果的实例变量(一个 user ID)。
2. 在w_about中增加控件(sle_userid)
3. 在w_about的Open事件中编写代码,将user ID的值放入单行编辑框中(sle_u
serid)
sle_userid.text = inv_aboutattrib.is_userid
4. 在n_cst_appmanager的pfc_PreAbout事件中编写初始化代码:
inv_aboutattrib.is_userid = this.of_GetUserID()
然后当你需要显示w_about时,调用应用程序管理器的of_About函数即可。

如何使用属性对象
PFC提供了许多专门的属性用户对象。这些用户对象有如下特征:
l_ 包含公有性质的实例变量
l_ 自动实例化
l_ 名称以attrib结尾
l_ 通常用于向PFC的pre_event传递信息,例如pfc_PreAbout
l_ 可扩展,你可以在其中自己定义其他的实例变量。
因为,你有可能会扩展这些对象。因此,PFC使用对象而不使用对象。
同样你还可以定义对象函数,做到更随意的控制这些对象。
这些属性对象有:
属性对象 有关的 用法
n_cst_aboutattrib Pfc_Pre_About(n_cst_appmanager) 调用n_cst_appmanag
er的of_About函数打开about对话框
n_cst_calculatorattrib Constructor(u_calculator) 内部自动调用
n_cst_dirattrib File service object 内部自动调用
N_cst_dwobjectattrib Of_Describe(n_cst_dssrv与n_cst_dwsrv) 函数Of_De
scribe返回DataWindow中的对象属性。
n_cst_dwproperyattrib DataWindow Properties objects 内部自动调用
n_cst_errorattrib Error message service 用于传递显示内容到w_message窗口

n_cst_filterattrib DataWindow filter service 用于传递信息到filter对话框

n_cst_findattrib DataWindow find service 传递信息到Find对话框
n_cst_itemattrib PFC ListBox, PictureListBox, and TreeView 内部自动调用

n_cst_linkageattr b DataWindow linkage service 内部自动调用
n_cst_logonattrib Pfc_PreLogonDlg (n_cst_appman ger) 调用n_cst_appmana
ger的of_LogonDlg函数打开w_logon窗口
n_cst_mruattrib MRU service 用于窗体的pfc_MRUProcess和pfc_PreMRUSave事

n_cst_restoreroattrib DataWindow row manager service 内部自动调用
n_cst_returnattrib DataWindow filter and sort services 内部自动调用
n_cst_selectionattrib Selection service Populated with arguments to th
e n_cst_selection of_Open function
n_cst_sortattrib DataWindow sort service 用于传递信息到Sort对话框
n_cst_splashattrib Pfc_PreSplash event (n_cst_appman ger) 调用n_cst_ap
pmanager的of_Splash函数打开w_splash 。
n_cst_sqlattrib SQL service 该属性对象中含有SQL语句的部分内容。
n_cst_textstyleattrib PFC RichTextEdit control 用于设置和获取text属性(
黑体、斜体等)。
n_cst_toolbarattrib Pfc_PreToolbars event (w_frame) 调用w_frame的pfc_T
oolbars事件打开w_toolbars 。
n_cst_zoomattrib DataWindow print preview service 内部自动调用

PFC的常量
许多PFC对象都包含了常量。使用常量使得程序更加易读。例如:下面两段代码同
样是设置Datawindow的linkage风格,但是第二段则显得更加容易理解:
// 1 = Filter linkage style.
dw_emp.inv_linkage.of_SetStyle(1)

// FILTER 作为一个常量
dw_emp.inv_linkage.of_SetStyle (dw_emp.inv_linkage.FILTER)
约定:PFC的所有常量都采用大写。

消息路由
消息路由器可以用于任何一个对象与窗体之间的通讯。不过,大部分时候都是用
于菜单与窗体之间的消息传递。它提供了一种查找算法用于确定哪个对象来接收
消息。
使用消息路由时:
l_ 你菜单中的代码只需要知道代用哪个事件,你无须知道当前的窗口时哪个,或
者与其相关的对象名称。
l_ 你的窗口无须维护用户事件,只需简单调用DataWindow的事件即可。从而减少
了窗口需要维护的事件数量。
Message = user event
经过消息路由传递的消息实际上就是用户事件名。窗口、控件收到这些消息后就
会调用相应的事件。

内置的debug消息
消息路由机制还提供了内置的debug

函数of_SendMessage的工作流程
当用户选择菜单项时,Clicked事件中的代码便以欲触发的用户事件名为参数(字
符串的形式)调用of_SendMessage函数。Of_SendMessage调用n_cst_menu的of_S
endMessage函数,n_cst_menu的of_SendMessage将会调用窗体的pfc_MessageRou
ter事件,pfc_MessageRouter事件将会调用你所要触发的用户事件(即在Clicke
d中传递字符串参数)。
在MDI与SDI应用程序中,函数Of_SendMessage调用pfc_MessageRouter时将有所不
同。如图:

pfc_MessageRouter的工作流程
如图:
菜单与窗口之间的消息传递
消息路由是菜单与窗口之间的通讯桥梁。你不可以通过按钮来触发pfc_MessageR
outer事件。因为,消息路由会调用GetFocus函数判断当前控件。这样当你按下按
钮时,按钮便成了当前控件。


PFC中的事务对象
PowerBuilder的强大功能之一就是可以快速便利的访问多种数据库。PowerBuild
er使用事务对象(Transaction Object)作为PowerBuilder与Database之间的桥
梁。SQLCA就是一个默认的事务对象。

用户自定义对象n_tr
PFC中有一个n_tr对象。它是标准事务对象的子类。其中设有实例变量、用户自定
义事件、函数,主要用于扩充与数据库的通讯能力。
N_tr提供了一套标准函数用于连接、切断、提交、回滚等数据库操作。使用这些
函数代替原有的数据库语句。例如使用of_Connect代替CONNECT语句。

两处地方使用n_tr
l_ 替代sqlca:在应用程序的属性对话框中将SQLCA的默认数据类型设为n_tr 。

l_ 附加的事务对象:当你需要访问多个数据库时,你可以再定义一个事务对象。

如果你使用了多个事务对象,你可以使用事务对象的registration service ,做
到一次提交全部已打开的事务对象,一次回滚所有已打开的事务对象。

将SQLCA设置为n_tr类型
1. 打开应用程序画笔
2. 显示属性窗口,选中Variable页
3. 在SQLCA框中输入n_tr
4. 点击OK

使用n_tr
1. 如果你不使用SQLCA ,而是使用其他的事务对象。
下面的例子假设itr_security是n_tr的实例变量
itr_security = CREATE n_tr
2. 初始化实例变量ib_autorollback 。这个变量的作用是当事务对象正处于连接
状态时应用程序被关闭了或者是该事务对象被删除了的时候,该事务对象应该如
何操作
itr_security.of_SetAutoRollback(FALSE)
关于初始化ib_autorollback的扩展
你可以在n_tr的构造事件中初始化ib_autorollback 。
3. 使用n_tr的of_Init函数初始化事务对象的属性
Integer li_return
String ls_inifile
ls_inifile = gnv_app.of_GetAppIniFile()
IF SQLCA.of_Init(ls_inifile,"Database") = -1 THEN
MessageBox("Database","Error initializing from " + ls_inifile)
HALT CLOSE
End if
4. 调用of_Connect进行数据库连接
IF SQLCA.of_Connect() = -1 THEN
MessageBox("Database","Unable to connect using " + ls_inifile)
HALT CLOSE
ELSE
gnv_app.of_GetFrame().SetMicroHelp("Connection complete")
End if
5. 调用n_tr的成员函数

调用父类的函数、事件
在扩充父类的函数和事件时,你有可能需要先调用父类的函数或事件,然后再依
据返回值进行下面的处理。这对那些具有返回值前缀是PFC的事件特别有意义。你
在执行子类的代码前必须先确认父类的代码是否执行成功。
覆盖父类的函数
为了扩展父类的代码,获取父类的返回值。你必须覆盖父类的代码,然后显示的
调用父类的函数或事件。
采用如下的语法格式调用父类的事件,同时传递参数、获取返回值:
Result = Super :: Event eventname(arguments叄?
采用如下的语法格式调用父类的函数,同时传递参数、获取返回值:
result = Super :: Function functionname(arguments叄?
下面的例子则覆盖了u_dw的pfc_Update事件。当父类的事件处理成功时,子类将
信息纪录到日志中。
Integer li_return
// Call ancestor event, passing
// descendant's arguments.
li_return = Super::Event pfc_Update(ab_accepttext, ab_resetflag)
IF li_return = 1 THEN
// ue_WriteLog is a user-defined event.
li_return = this.Event ue_WriteLog
END IF
Return li_return

在应用程序中增加联机帮助
联机帮助是应用程序中非常重要的一部分。PFC提供了许多函数、事件使得你可以
方便的将联机帮助添加到你的应用程序中。
相关信息:有关PFC的帮助对话框请参考“Deploying PFC dialog box HELP” 。

1. 使用n_cst_appmanager的of_SetHelpFile函数设置帮助文件。通常在构造事件
中:
this.of_SetHelpFile(“c:\eis\eisapp.hlp”)
2. pfc_PreOpen是为窗口设置帮助主题的最好的地方
Long ll_helpid
Ll_helpid = 1020 //1020是一个帮助主题的ID
Ia_helptypeid = ll_helpid
采用这种方式你可以为用户选中的窗口提供详细的帮助。你可以将ia_helptypei
d设置成长整形(此时PFC把它解释成帮助主题的ID),或者是字符串(此时PFC将
它解释成关键字)。
3. (可选)如果你没有使用PFC的m_master的子类。那么,在你的HELP菜单项中
调用窗体的pfc_Help事件。因为,pfc_Help定义在窗口w_master中,所以所有的
PFC窗口都具有事件。
4. 对于对话框,则在其中的HELP按钮的Clicked事件中编写:
Parent.Event pfc_Help()
PFC自动处理窗口级别的帮助
当你从m_master的子类的菜单中选择Help->Help时,消息路由机制会自动的调用
当前活动的窗口的pfc_help事件。

PFC的升级
PFC在发布PowerBuilder的升级版本时同时也包括了PFC的升级文件。如何升级PF
C,请按如下规则:
l_ PFC的各层(PFC层、PFE层、中间层等)没有任何被修改时:你可以直接安装
新的PBLs覆盖原有的PBLs 。
注意:每次升级PFC时都保留一份原有的文件备份
l_ 如果你修改了PFC中的某一层:你必须保证你所作的修改不会被覆盖!请按如
下的步骤进行:

将PFC升级到最新版本
1. 将所有扩展层的PBL文件移到一个不会被安装过程覆盖的目录中。
说明:你不应该对PFC的最基类(以PFC为前缀的对象)作任何修改,这里假设你
没有对PFC的最基类作任何修改
2. 确定你当前的PFC的版本号。你可以在Readme.txt文件中查看,或者在pfc_n_
cst_debug的实例变量中查看。版本号的格式:主版本号.次版本号.修正号
3. 执行安装程序,将PFC安装口的PBL文件放到PFC所在的目录中,覆盖原有的PF
C最基类的PBLS ,即以PFC开头的库文件。
4. 合并已存在的扩展对象与新安装的扩展对象。首先详细阅读Readme.txt中说明
的新扩展对象清单。然后按照一下的两种方法合并对象:
l_ 将新的对象COPY到你的扩展PBLS中。
l_ 将已经存在的对象COPY到新的扩展PBLS中。
5. 启动PowerBuilder
6. (可选)必要的时候调整一下应用程序的库列表
7. 打开库画笔,从新编译一边所有的对象。


PFC的服务

 

概要:

这一章主要介绍了什么是PFC的Services ,以及如何使用它们。

1 应用程序服务

PFC提供了以下各种应用程序Services :

DataWindow caching

Debugging

Error

Application preference

Most recently uesed object

Security

Transaction registration

你必须通过n_cst_appmanager(应用程序管理器)来控制这些Services (这些S

ervices实际上是应用程序管理器的是数据成员)。应用程序管理器(applicati

on manager)通过调用成员函数来开启与关闭Services 。由于它们在应用程序管

理器的范围内有效。而应用管理器是全局变量,因此你可以在你的应用程序的任

何地方是使用应用程序Services 。

1. DataWindow caching service

概要:

Datawindow caching service为Datawindow提供了数据缓冲。它将数据保存在内

存中,从而减少了程序访问数据库的频率,加快了程序的执行速度。Datawindow

caching service支持如下的数据源:

l_ Datawindow对象,它的数据可以来自于数据库表也可以来自存储过程。

l_ SQL语句

l_ Datawindow控件

l_ DataStore对象

l_ 数组中的数据

l_ 文件

PFC使用Powerbuilder的Datastore来实现Datawindow caching service 。它对应

的对象是n_cst_dwcache 。

PFC的代码实际只在父类对象中

这本书讲述的都是扩展类的对象,就像n_cst_dwcache 。而实际上PFC的代码全在

父类的对象中(pfc_n_cst_dwcache)。

使用方法

使用DataWindow caching 可以将数据库访问频率降到最低,可以加快程序运行速

度。

2 开启DataWindow caching

l_ 调用n_cst_appmanager的of_SetDWCache函数

gnv_app.of_SetDWCache(TRUE)

2 使用Datawindow caching :

1. 调用of_Register函数进行数据缓存,同时依据不同的数据提供相应的参数。

l_ 缓存Datawindow对象从数据库中检索出的数据时:你需要传递标识符(ident

ifier)、事务对象、Datawindow对象名、其他参数(如果存在的话)。

l_ 缓存SQL语句从数据库中检索出的数据时:你需要传递标识符(indentifier)

、事务对象、SQL语句。

l_ 将数据缓存到数组中:传递标识符(identifier)、Datawindow对象名、数据



l_ 缓存DataWindow控件中的数据:传递标识符(identifier)、Datawindow控件



l_ 缓存DataStore中的数据:传递标识符(identifier)、DataStore对象。

l_ 缓存文件中的数据:传