PFC的数据类型及命名规则

 

.对象名称定义     

pfcobject_type_objectname

其中,pfcobject  PFC_时,表示为PFC级别,否则为PFE级别(扩展级别)

type包含以下类型:

类型 说明 类型 说明 

m_  菜单 

n_  标准用户对象类

n_cst  可定制的用户对象类 

u_ 可视用户对象

w_ 窗口

s_ 全局结构 

.变量名称定义

<scopre><datatype>_varialbename

Scorpe为以下值之一

类型 说明  类型  说明 

全局变量  i  实例变量 

局部变量  s  共享变量 

简单变量的Type为以下值之一

类型 说明  类型 说明 

a  Any    blb  Blob 

b  Boolean   ch Character 

d  Date  dtm DateTime 

dc  Decimal  dbl Double 

e  Enumerated  i Integer 

l  Long    r Real 

s  String  tm Time 

ui UnsignedInteger ul UnsignedLong 

指针变量的Type值为以下之一

类型 说明 类型 说明 

app Application ab ArrayBounds 

cbx CheckBox cb CommandButton 

cd ClassDefinition cdo ClassDefinitionObject 

cn Connection cninfo ConnectionInfo 

cno ConnectObject cxk ContextKeyword 

cxinfo ContextInformation cpp Cplusplus 

ds DataStore dw  DataWindow 

dwc DataWindowChild drg DragObject 

drw DrawObject ddplb  DropDownPictureListBox 

ddlb DropDownListBox dwo DWObject 

dda DynamicDescriptionArea dsa  DynamicStagingArea 

ed EnumerationDefinition eid EnumerationItemDefinition 

em EditMask env Environment 

err  Error ext  ExtObject 

gr Graph go GraphicObject 

grax  GrAxis grda GrDispAttr 

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 OmObejct 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 srv Service 

st StaticText std SimpleTypeDefinition 

str Structure tab Tab 

tabpg TabPage tcan TraceActivityNode 

tcbe TraceBeginEdn 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 

trp Transport tv TreeView 

tvi TreeViewItem uo UserObject 

vrcd VariableCardinalityDefinition vrd  VariableDefinition 

vsb VerticalScrollBar wo WindowObject 

w Window   

.函数名称定义

全局函数以f_开头,成员函数以of_开头。

 

 

PFC的详细介绍

PowerBuilder Foundaction ClassPFC)是SyBase公司提供的一整套PB对象。整套对象都基于面向对象原则。PFC不同于VCMFCBCOWLDelphiVCL 

MFCOWLVCL都是较底层的类库。它们为WINDOWS编程提供了基本的控件、对话框等,它们都主要着眼于封装WINDOWSAPI,使得使用它们的人可以不必了解API以及一些Windows结构、Windows消息的细则即可以编写出WINDOWS下的应用程序。也就是说这些类库适合各种类型的WINDOWS应用程序。 PFC是专门为PB而设计,PFC专门为数据库应用软件而设计。它有明显的针对性。它提供了几乎所有作为一个数据库应用软件开发而需要的代码。举一个最简单的例子:作为数据库应用程序不可避免的都得具备保存数据的功能。如果你使用PFC,你继承PFC的窗口、PFC的菜单、PFCDataWindow Control ,将它们连在一起后,你无须编写任何代码。点击菜单上的保存,DataWindow中的数据很自然的保存起来了,并且当数据被更改后用户没有保存数据而直接关闭窗口时,窗口很自然的会出现提示框要求保存数据。所有的这一切,你都无须编码。你只要确认你的对象是PFC的子类即可,所有PFC的父类中已经替你完成。所以可以知道PFC的着重点并不是如何实现一个窗口控件,如何封装WINDOWS API(与MFCOWLVCL的不同之处),而是为了实现作为数据库软件而应该具备的各种公共的功能。因此可以说PFC是更高一级的类库(其实PB中的各种标准控件、窗体、按钮、图片框等等都是利用MFC开发出来的),它更加贴近应用程序的开发。使用PFC开发程序只需要更少的代码、更容易PFC的对象分布在Sybase公司发行的10PBLs中。因此你完全拥有PFC的所有源代码。你可以随心所欲的更改父类脚本,你还可以从中学到许多的PB高级技巧。

1 PFC的面向对象特性

PFC是一个完全面向对象的类库。它涵盖了继承、封装、多态、函数覆盖、函数重载,所有面向对象应该具备的特性它都有。它的面向对象都体现在如下几点。

继承:PFC中的对象全部都是息息相关,绝对不存在一个独立的对象,任何一个对象都是整个类库链中的一员。

封装:PFC中的所有对象都封装了许多函数、实例变量。并且设有相应的访问权限(PFC没有一个Private类型变量)。对于那些可读的变量PFC都设有of_GetVariablename 

函数,对于布尔类型的变量PFC都设有of_IsVariablename函数。对于可修改的变量PFC都设有of_SetVariablename函数。在某些情况下PFC还将变量直接设成Public类型的变量供我们直接修改。

多态:PFC在许多地方都用到了多态。例如PFC中的File Service就是一个典型的例子。File Service有一个祖先n_cst_filesrv。其中定义了File Service的所有函数,但是其中没有任何代码。真真的代码在pfc_n_cst_filesrv子类中实现。例如关于WIN32操作系统的文件管理函数则被在n_cst_filesrvwin32类中实现、关于UNIX的文件管理函数则被在n_cst_filesrvUnix中实现。通过这种多态的利用便实现里跨平台的代码。开发人员使用的File Service的类永远是n_cst_filesrvPFC会自动的根据不同的操作系统创建不同的n_cst_filesrv的子类来完成不同操作系统下的文件管理。而所有的这一切,PFC开发人员都不需要知道。这就是PFC的多态的一个典型的运用。

下面是PFC的一个简要的继承关系图:

2 PFC的体系结构-Service-Based Architecture

PFC采用的是一种新的体系结构-基于服务的体系结构(Service-Based Architecture)。PFC类库设计核心就是面向服务的设计。服务(也叫Service)实际上就是PFC提供的一套功能。PFC中的服务实际上都是不可视的用户自定义对象,不过有的服务也涉及到一些可视对象,例如下拉日历与下拉计算器。这些用户自定义对象中封装了许多函数、事件、属性等等。通过调用这些函数、事件即可完成我们想要的功能。例如WINDOWSResize服务。通过调用Resize服务的注册函数,注册那些需要Resize的控件,这样当窗口发生Resize事件时窗体将自动的触发Resize服务的代码。Resize服务将会依据窗口大小的变化调整那些注册过的控件的位置与大小PFCResize全部替我们完成了。而且它的实现全部在n_cst_resize用户自定义对象中。这就是PFC的服务结构,一个服务就是提供了一套完整功能的不可视用户自定义对象。而且所有的这些对象都不是孤立的,它们都在PFC的类库链

上。PFC提供的服务有很多。下面做一个简要的介绍:

 

PFC的服务分五大部分

应用程序服务(Application Services

窗口服务(Window Services

数据窗口服务(DataWindow Services

数据存储服务(DataStore Services

全局服务(Global Services)。

2.1     应用程序服务

A.错误消息服务(Error Message Service

错误消息的处理是所有应用程序都必须具备的功能。好的错误处理可以提高软件的可靠性、稳定性、加快软件的测试速度等等。PFC提供的错误消息处理就非常好。它允许开发人员为各种错误消息定义级别,当程序出现大于某一级别的消息时错误消息服务将会自动将错误消息记录到错误日PFC的错误消息服务现在还具备邮件功能。这样当用户在使用软件是出现了错误后,PFC的错误消息处理将会把发生的错误消息邮寄给开发人员。这种错误消?BR>⒌拇矸浅J视糜谌禾蹇ⅰ?⑷嗽庇氩馐匀嗽倍荚谝桓鼍钟蛲匣蛟贗nternet上,软件发生的错误将会及时传到开发人员的手中。PFC的错误消息服务还提供了一种预定义消息的机制。开发人员可以利用数据库保存预定义的消息。将各种消息预先在数据库中定义好,定义好显示的内容、标题、图表、按钮等。当要显示时只需指定要显示的消息ID。这种预定义消息机制为应用程序显示一种统一的消息而提供了方便。同一类型的消息显示的都是类似的提示(可能具体参数不一样)。同时消息的修改也方便了许多。不必再需要从大量的代码中寻找需要修改的消息。这就是PFC提供的一个非常有用的服务之一,PFC中存在大量的这种服务。

B.应用程序安全服务(Security Service  

大部分的数据库应用软件都必须得进行应用程序的安全控制。PFC的应用程序安全服务为你完成了大步部分的安全管理。你可以使用PFC提供的安全扫描器定义你为了实现安全控制而涉及的对象。安全扫描器会将需要进行安全控制的对象记录到数据库中(PFC提供了5个用于实现安全控制的表

)。PFC还提供了用于设置用户使用权限的模块,你只需针对具体的应用稍做修改即可使用。然后你只需开启安全服务,在需要进行安全控制的窗体、菜单、数据窗口的构造事件中调用gnv_app.inv_security. of_SetSecuritythis)即可。当然PFC的安全服务仍然存在缺陷,例如PFC提供的用户管理没有密码的设置。

C. 数据窗口缓存服务(DataWindow Caching

数据窗口的缓存服务为应用程序提供了一个缓存数据的功能。可以有效的减少对数据库的访问。提高应用程序的响应速度。使用该服务非常简单只需将DataWindow或者SQL语句注册一边即可。

2.2     窗口服务

A.偏爱服务(Preference Service

PFC的窗口偏爱服务提供了自动保存与恢复用户设置的功能。偏爱服务一旦被开启,它会自动的记录窗体的大小、位置、工具条状态等与窗体相关的信息,当窗口再次被打开时偏爱服务会自动的恢复这些设置。所有这一切只需调用窗体函数This.of_SetPreferenceTrue)即可。

B.状态条服务(Status bar Serice

PB MDI窗口提供的状态条非常简单。为此PFC专门提供了一个状态条服务。利用状态条服务,可以设计出功能强大的状态条。例如你可以在状态条上显示图标,并可以响应事件。可以在状态上显示时间,可以显示进度条等,还可以显示其他的一些与系统相关信息,例如:剩余内存。

2.3     数据窗口服务

数据窗口是PFC最重要的一部分也是使用得最多的服务。

A.下拉数据窗口查询服务(DropDown DataWindow Search Service

下拉数据窗口查询服务提供了一种自动滚动到首字符与用户输入的字符相同的数据项上。例如:当用户输入A时,下拉数据窗口查询服务会自动的滚到以字符A开头的数据项上。

B. 高级查询服务(Filter Service

高级查询服务提供了一种非常灵活的查询方式给用户。它还可以提供类似SQL语句查询给那些高级用户。一般的用户通过使用高级查询几乎可以完成所有的查询操作。在配合DataWindow的计算列、汇总函数等,各种情况下的汇总、统计功能也都完成了。在本次项目中我就大量的使用了高级的dataWindow控件的of_SetFilterTrue)函数,再调用of_SetStyle设置高级查询窗口的样式,即完成高级查询功能的制作。

C.改变大小服务(Resize Service

Resize Service提供了一种功能使得DataWindow控件的大小发生变化相应的调整其中的控件的大小与位置。Resize Service使用起来与使用窗口的Resize服务一样方便、简单。

D.行管理服务(Row Manager Service

行管理服务提供了一种对数据行进行有效管理的服务。例如:行管理服务提供的恢复删除的功能。你只需调用事件pfc_RestoreRow即可恢复用户已删除的数据。为数据库应用软件的开发提供了极大的方便。

2.4     全局服务

全局服务提供了一些在任何场合、任何环境中都可以使用的服务。

菜单服务(Menu Service

菜单服务提供了一种方便的机制供菜单与窗口通讯。本次项目中的所有的菜单都使用了的菜单服务。使用菜单服务提供菜单的重用性、减少重复的代码。

A. 改变尺寸服务(Resize Service

Resize Service为许多可视的容器对象都提供了Resize服务的功能。例如窗口的Resize功能就是由该服务提供的。可视用户自定义对象的祖先类u_base也使用了Resize Service 。因此,如果你遵循PFC的继承策略。那么你自定义的User Object也将具备Resize功能。Resize 

Service还大量的运用在其他场合,例如u_tabpage对象中。你也完全可以在其他自定义对象或其他场合使用Resize Service,因为它是全局的。

B. 文件服务(File Service

PFC的文件服务提供了一种与平台无关的文件服务。也就说使用PFC的文件服务中的关于文件的函数可以不必考虑具体的操作系统,PFC会自动的根据应用程序所在的操作系统进行相应的API调用。

小结:PFC的服务还有许多,而且都很有用,使用起来也很方便。例如INI文件服务提供了一种非常便利的方式访问INI文件。DataWindow的排序服务,日历、计算器服务等。 由于篇幅有限,只做了简单的介绍。

C.PFC分层的概念与用意

PFC中层的概念是PFC非常重要的一大特色。也正是PFC的层的概念吸引了我,使我开始学习PFCPFC中层的设计使得软件开发与维护变得非常方便。下面就详细的讲述以下PFC层的概念。

3.1     PFC中的PFE层(也叫扩展层)

PFC它是一套类库。PFC的设计是为了制作一套可以提供所有使用PB开发数据库应用软件所需要的功能。但是我们都知道这是不可能的。因为,任何应用软件都可能存在一些特别情况,需要特别的运用。如果不存在PFC的扩展层或者说PFC没有分层的概念。那么我们为了具体的应用需要做修改

时,我们将会直接修改PFC的代码。如果真的是这样的话,那么便会出现一个问题,那就是当Sybase公司升级PFC时,你又不得不再次重新修改一遍,因为新版的PFC覆盖了原来的PFC文件你所做的修改也全部丢失。但是如果存在一个独立的扩展层,那么扩展层就是一整套完全继承PFC对象的全部对象集合。扩展层的对象保存在独立的PBLs中。PFCPFC对象定义为PFC层对象,所有PFC层对象的前缀都带有"pfc_"(例如pfc_w_main),并且都保存在PFCxxxxx.PBL中。PFC将扩展层对象定义为PFE层,所有的PFE层对象都没有前缀(例如w_main),并且PFE层对象全部保存在PFExxxx.PBL中。PFE层中其实没有任何代码,只是简简单单的继承了PFC层中的对象。这样做的好处就是假设开发人员需要为特定的应用而修改PFC对象时,这时改去修改PFE中的对象就可以了。这样当Sybase公司升级PFC时,便不会再有冲突了。引入PFE层后我们的对象也就全部改为继承PFE对象,这样如果我们需要增加一个整个应用程序都具备的特性时只需修改PFE中的对象即可完成。例如:我们程序的窗体全部继承W_Main。如果我们要在令到我们的应用程序中的全部窗口的图标都会变化(一张会笑的脸!),我们只需在W_Main窗口增加代码就可以令到整个应用程序的所有窗口都具备这种特性。由此可以看到扩展层为我们的开发带来了极大的灵活性。其实PFC扩展层的设计也是PFC面向对象设计的一个重要特点。也正是PFC的面向对象的设计使得我们修改整个应用程序如此容易(上例中修改W_Main窗口)。

3.2     PFC的中间层

PFE层是一套完全继承PFC层对象的对象集合。按照这种思路Sybase公司又提出了中间层的概念。中间层对象就是那些继承PFC层的对象,PFE层的对象又继承中间层的对象。也就说中间层的对象是位于PFCPFE层对象之间的对象。中间层有时也叫企业层、部门层对象。中间层提供了供开发人员设计一种企业级或者部门级软件特色的功能。我们都知道一个软件企业或者一个软件部门开发的软件往往不止一套。而往往一个软件企业或者软件部门开发的软件都具备自己的一套特色(从外观上、功能上、操作方式上等)。如果每个企业或者每个部门做每套软件是都要在PFE层的对象,PFC层、中间层、PFE层对象

3.3     PFC的继承结构

由于PFC的分层的特点,使得PFC对象之间的继承关系也带有一些特点。图1中描述的继承关系只是一个大概的样式,PFC中的对象的真真继承关系并非如此。下面图2描述的则是PFC真真的继承关系:

4 PFC中跨平台的设计

PFC非常注重跨平台的设计。在讲述多态时曾提到PFC利用多态实现跨平台的文件管理。与文件管理类似,PFC的平台服务(提供了一些关于操作系统调用的API)也是一个跨平台的服务。下面将着重讲述一下PFC如何实现跨平台的文件管理。PFC首先定义了一个抽象基类n_cst_filesrv 

。该基类中定义了所有PFC提供的文件管理函数,但是这些函数都没有任何实质性的代码。源代码如下:

Public Function String of_GetCurrentDirectory ()

//      Function could found in descendent

Return ""

其他的省略…

然后PFC定义一个n_cst_filesrv类的一个子类n_cst_filesrvwin32。类n_cst_filesrvwin32的作用就是在WIN32操作系统下实现of_GetCurrentDirectory()函数以及其他函数。同样PFCMAC操作系统定义了n_cst_filesrvMAC类,类n_cst_filesrvMAC的作用就是在MAC操作系统下实现of_Get

CurrentDirectory()函数以及其他函数。为了方便说明我只据两个操作系统的例子,至于跨多个操作系统与跨两个操作系统没有任何本质区别。

        PFC程序员在使用PFC的文件服务时是这样使用的:

1 定义n_cst_filesrv类型的变量。

n_cst_filesrv   lnv_filesrv

2 调用全局函数f_SetFilesrvn_cst_filesrv anv_filesrv, Boolean ab_switch)开启文件服务

f_SetFilesrvlnv_filesrvTrue

3 这样PFC的文件服务便会根据不同的操作系统调用相应的文件API。对PFC的程序员来讲编写跨平台的软件的真是非常方便。

其实真真的PFC跨平台的代码就在函数f_SetFilesrv中,源代码(稍做修改):

Function f_SetFilesrvn_cst_filesrv anv_filesrv, Boolean ab_switch

// Argument and error checking.

If IsNull(ab_switch) Then Return -1

If IsNull(gnv_app) Or Not IsValid(gnv_app) Then Return -1

 

if ab_switch then

        if IsNull (anv_filesrv) or not IsValid (anv_filesrv) then

                // create file service object based on platform

        Choose Case gnv_app.ienv_object.ostype

                Case macintosh!

                        anv_filesrv = create n_cst_filesrvmac

                Case windows!, windowsnt!

                                anv_filesrv = create n_cst_filesrvwin32

        end choose

                return 1

        end if

else

        if IsValid (anv_filesrv) then

                destroy anv_filesrv

                Return 1

        end if

end if

 

Return 0

 

请注意粗体字部分,这就是PFC利用多态实现跨平台的设计。

 

总结

以上也只是对PFC作了一番介绍。并没有讲述如何着手PFC开发。对PFC开发应用程序感兴趣的朋友可以参考我们站点中的其他文章。

PowerBuilder被忽略的的技术

1.1       Object看作类

Completed:   100   %

(Class),仅仅在概念的层次上,是不能直接使用的,类只有在具体化(实例化)后才能使用,实例化的类我们称之为对象(Object);

PB的帮助中常常出现Object这个词,例如介绍菜单时使用的名称是Menu   Object   而不是   Menu   Class(我认为严格讲,在帮助中这样叫有不妥之处;Sybase可能会有它自己的说法,这些我们暂且不管),为了能合理解释Powerbuilder的面向对象的继承、多态、封装等特性,现在我们作如下假设:

我们暂且把Powerbuilder中的Object统一称作Class

本次约定在接下来的几次讨论中都有效,如果我能记得我会每次都强调一下;

1.2       窗口的控件创建和释放

Completed:   100   %

控件是我们在开发中最常用的了,但是放在窗口上的控件何时被创建,何时有被销毁?

创建过程:

windows中,控件被创建时必须指明用来承载控件的窗口对象,所以可以肯定的是窗口的创建过程肯定在所有准备使用它来承载的控件之前完成创建;

细心的话你会注意到控件的Constructor事件会在窗口的Open之前执行,事情就是这样子的,那是因为窗口Open事件并不是窗口的Constructor事件,窗口在完成自己的创建后,再把Control[]中的对象一一创建,在这时控件的Constructor事件会被触发,在所有的控件成功创建完毕后窗口才会触发Open事件。

用流程图表示:

释放过程:

释放过程正好跟创建顺序相反;

在窗口收到WM_CLOSE消息前会先收到WM_CLOSEQUERY消息,来给开发人员一个阻止WM_CLOSE发生的时机;在PowerbuilderWM_CLOSE   <=>   Event   Close()   WM_CLOSEQUERY   <=> Event   CloseQuery()

所以在窗口关闭时首先触发自己的CloseQuery事件,在CloseQuery同意后触发Close事件,之后才会把Control[]中的控件一一释放,这时各个控件的destructor事件会被触发。等所有的控件被释放后,再触发窗口的Destructor。完成释放过程。

用流程图表示:

 

注意:控件创建的先后顺序要看控件怎样存储在Control[]中,Powerbuilder无论是创建过程还是释放过程,都是从下表1开始循环创建的,可以查看源码知道各个控件的下标。一般规律是后放入的控件县创建。

 

1.3       谨慎使用Post

Completed:   100   %

谈到Post,就会想起来是用来向控件消息队列发送消息,通过Post发送的消息处理时间是不能确定的,这由操作系统是如何调度的,以及当时计算机的运行情况来决定。在PowerScriptPost的语法很灵活,表现形式多种多样。

Post以关键字的形式出现:

发送消息给以Powerbuilder事件形式出现的消息处理函数:this.post   event   open()

发送消息给以Powerbuilder函数形式出现的消息处理函数:this.Post   classname(   )(这种方法有别于   this.classname()

以关键字形式出现一般用在有参数的消息处理函数中;

并且使用Post是不能得到函数或事件的返回值的;

 

Post以函数形式出现

this.postevent( "XXXX ",{Word},{Long})

XXXXX   是函数名或事件名

 

Windows是消息驱动的操作系统,所以Windows下的Powerbuilder程序也不例外,Powerbuilder中使用Post()Send()来完成消息的发送。熟悉SDK编成的可以直接使用PostSend来发送消息,Send发出的消息会立即被处理,所以这个我们不讨论,但是Post是我们的导论范围.

通常情况下Post发送的消息在被对应的消息处理函数处理的时刻要比直接调用消息处理函数晚一些。这就会存在潜在危险,如果发出消息对应的消息处理函数所在的对象已经被释放,这时将可能会出现运行错误或者消息不被处理的危险;所以在使用了Post之后应该注意目标对象是否存在对象提前被释放的情况。特别需要注意的是在窗口的Close中使用Post,因为发出Post时没有办法知道消息何时会被处理。所以在Close中尽量不要使用Post

这里顺便提到一点:

在控件的代码中,尤其是按钮的Clicked事件中,写了如下代码将会出现运行错误:

CLose(Parent)

this.text   =   " "

如果出现下面代码则不会出现运行错误:

CLose(Parent)

MessageBox( " ", " ")

如果出现下面代码则不会出现运行错误:

Post   CLose(Parent)

MessageBox( " ", " ")

这些就是Post应用的一些临届情况。

 

1.4       避免类重名

Completed:   100   %

这里主要讨论两种情况的重名:

1、不同的PBL重名类

Powerbuilder允许在同一个Target中出现多个Powerbuiler   Library   (PBL文件),在不同的PBL中间出现相同的类别名称,就算是出现同一种类型的类,Powerbuiler不会作出判断,这样就存在了一个潜在的危险,PBL(PBD)Target中出现的先后顺序将会影响在运行时引用的对象;并且产生编译警告。所以这种一定要避免。

2、同一个PBL中出现重名

如果是相同类型的重名出现在同一个PBL中,Powerbuiler会作出提示,询问是否要覆盖。但如果出现同名的类不是同一种类型,Powerbuilder不会作出提示,这样就会带来许多不必要的麻烦。例如:在同一个PBL中出现了ww窗口,同时也出现了ww菜单,在ww窗口引用ww菜单时编译器会提示ww不是一个菜单类型。

综上所述第一种重名情况比较致命,不易被发现。第二种情况也应该坚决避免。好在Sybase在引导开发时,都提倡加前缀,这样就可以避免第二种问题。所以要强调的就是手误。

 

1.5       隐藏的全局类和局部类

Completed:   100   %

隐藏的全局类

打开Powerbuilder相关资料,很容易看到“Powerbuilder一个面向对象的开发工具”之类的话。绝大多数人写过的第一个程序就是在从window建立一个w_main,然后在Application中调用Open(w_main),这样一个程序就产生了

如果有面向对象编成的思想,那么这个时候应该有个疑问,我建立的w_main是个什么东西啊,类?对象?

众多书籍上会说建立一个window对象,那么这时Open(w_main)没有任何疑问,因为w_main是一个全局对象阿,作为参数传给Open当然没有任何疑问。可以你还可能会看到过一下代码:

w_main   w_a,w_b

open(w_a)

open(w_b)

上面的代码不但不会产生编译错误,并且能够执行成功。执行后你会看到两个窗口。

你可能会以为对象也能作类别使用,难道Powerbuilder超越了面向对象?

这时应该怀疑的是w_main也是个类,并且有一个与w_main同名的全局w_main对象。只有这样能解释上面提到的两种代码。带着疑问打开w_main的源码:

global   type   ww   from   window

global   ww   ww

看到这里,应该可以证实我们之前的猜测是正确的,Powerbuilder确实创建了window的子类w_main,并且同时又声明与类(Class)同名的全局变量(全局对象   Object)w_main。除了structure(不是类)之外都所有出现在PBL中的类都具有这样的特性。

隐藏的局部类

更深入的编程尤其是写通用代码时,会需要使用ClassName()来判断对象的类别,然后根据类别做出判断。接下来我们仍然以一个具体的例子来展开讨论。

现在有一个窗口w_main,在窗口上方防置了一个按钮cb_1,通常我们写代码都是象下面一样的写法:

cb_1.Text   =   "XXXX "

cb_1.Enabled   =   False

String   ls_clsNm  

ls_clsNm   =   cb_1.ClassName()

这时就会发现ls_clsNm是“cb_1”,怎么不是CommandButton?难道ClassName()不是取的类别名?查一下帮助,可以证实ClassName()的功能,就是取类名。所以我们又要有猜测,是不是又有局部的类被   cb_1,由于cb_1可以直接用,所以也应该有一个与cb_1同名的局部对象存在。为了证实我们的想法,让我们打开源码分析:

cb_1   cb_1

type   cb_1   from   commandbutton   within   w_main

需要注意:如果控件是动态创建的,则ClassName()得到的将是CommandButton

拨云见日,知道了这些隐藏的类和对象,至少可以肯定Poswebuilder面向对象的特性,我们在以后的编码中巧妙的使用这些类或对象。

.6       全局Message对象

Completed:   100   %

首先可以肯定的是   Message是一个Message类型的全局变量(讲到这里我们也许可以理解PowerBuilder帮助中出现的Object是可以理解的,因为很多类都是以全局对象出现的)。这里我们不讨论Message类,而是在讨论Message对象。Message对象在程序启动时自动被创建。首先我们看一下Message类的成员变量:

----------------------------------

Handle     Long     //消息目标对象句柄

Number     UnsignedInt//消息

WordParm     Long     //参数

LongParm     Long     //参数

ClassDefinition   owerObject     //暂不讨论

DoubleParm     Double   //用来传递数字

StringParm   String   //用来传第字符   ,字符在传递过程中是复制的

PowerObjectParm   owerObject   //用来传暂且递人意的Powerbuilder对象

Processed   BooleanA   boolean   value   set   in   the   script   for   the   user-defined   event   or   the   Other   event.   Values   are:TRUE   -   The   script   processed   the   event;   do   not   call   the   default   window   process   (DefWindowProc)   after   the   event   has   been   processed.FALSE   -   (Default)   Call   DefWindowProc   after   the   event   has   been   processed.

ReturnValueLongWhen   Message.Processed   is   true,   specifies   the   value   you   want   returned   to   Windows.   This   property   is   ignored   when   Message.Processed   is   false.

----------------------------------

从上面的成员变量可以看出,蓝色标出的最上面的四个成员变量和Send函数中的参数是一致的,帮助上也是这么声明的.如果Message向我们原来设想的那样,是用来在不同对象之间传递,那么这些成员就显得有些多余(相信有很多人在传递参数过程中会误用Message.Number,Message.WordParm,Message.LongParm,用这些来接收数字,结果都失败了),所以他一定有其他用途,那么它是如何和windows消息联系到一起的呢?这个暂且放一下,我们继续看下面的成员变量,绿色标出的是我们最为熟悉的参数了,我就不做详细解释,最后面的两个我对他的功能有些质疑,待会儿我会验证我的说法。

Message对象的第一种功能:

经过Debug你会发现,Powerbuilder程序受到任何一个消息以后Message内容都有变化,仔细观察就会发现变化的只是前四个参数,这样我们就可以确定这个全局对象就像一个梭子一样跟着每个消息在程序中传来传去,Powerbuilder在接收到消息后会先初始化Message对象,然后再把消息继续传递。这种特性对于自定义消息也同样有效。

我上面提到,最后两个成员变量的功能我有质疑,原因是我在实际测试中发现,当我把Processed设置为False时,ReturnValue仍然会起作用。还有,事件中的返回值回覆盖ReturnValue中的值,即便是使ProcessedTrue。这个有兴趣可以做一个测试看看。

注意接收Message的返回值需要使用函数Send,而不能使用Post

在这种情况下,DoubleParmStringParmPowerObjectParm是不会被修改的,这个是肯定的,要不然我们就会因消息过多而不能使用燤essage传递参数了。

Message对象的第二种功能:

这种功能也是Powerbuilder开发人员常用的功能。

例如OpenWithParm(w_a, "ACB ")

w_a的窗口中可以使用Message.StringParm来得到ABC

可是我们在实际的工作中,尤其在经过多次封装后的窗口中会发现得到的Message不是我们需要的,可能是一个空的(不是非法),也许有了其他的内容,到底何时把全局Message对象重置又何时把Message对象填充?

问题已经引出,这就是我们要讨论的内容:

我们可以肯定:

OpenWithParm

OpenSheetWithParm

OpenUserObjectWithParm

但是会不会清空我们可以作一些测试来验证:

Open

OpenSheet

OpenUserObject

经过验证发现他们都可以把Message对象清空的;

目前我只发现这些。

所以可以有结论,当调用以上六个函数中任意一个时,就会把Message重置。

理清楚这些,就很容易把Message被偷天换日的情况彻底杜绝。

需要注意:第二种功能中只会影响到DoubleParmStringParmPowerObjectParm三个参数。

综合来讲Message分为了两个部分,一部分用在系统传递消息时,一部分用在开发程序中传递参数。

1.7       关于菜单编程

Completed:   75   %

通用菜单

我们不需要解释什么叫菜单,所以就直接不如正题,在实际的开发过程中菜单是必不可缺的,有时为了方便会把所有弹出式菜单都坐在一个类中,需要时用那个弹那个。有时也会作一些通用菜单作为公用组件使用。

下面列出我们常见的菜单编程方法来引出这个问题:

&#8226; 调用指定窗口对象的函数:

w_main.relogon()

&#8226; 直接调用调用全局函数:

gf_relogon()

&#8226; 使用Parentwindow动态调用:

Parentwindow.Dynamic   relogon()

这几种做法的灵活性从上而下,可是这些做法都不足以保证灵活性,并且业务处理代码相对分散,并且如果发菜单放到没有定义相对应的函数的窗口中会出现运行错误。这种也是通用菜单不应该出现的错误;

受系统菜单的启发

为了解决代码分散,容易出现运行错误等问题,我们采用Windows的消息路有机制来完成菜单的功能。

具体做法:

1、可以定义好一些全局常量,如:

CONSTANT   UINT   WM_USER   =   1024

CONSTANT   UINT   WM_M1   =   WM_USER   +   1

CONSTANT   UINT   WM_M2   =   WM_USER   +   2

CONSTANT   UINT   WM_M3   =   WM_USER   +   3

为了跟windows消息区别,一定要在WM_USER上增加。

在需要处里该消息的窗口上写好处理代码就行了:

Choose   Case   Message.number

      Case   WM_M1        

            MEssageBox( " ", 'wm_m1 ')

            Return   1  

      Case   WM_M2

            MEssageBox( " ", 'wm_m2 ')

            Return   1  

      Case   WM_M3

            MessageBox( " ", 'wm_m3 ')

End   Choose

这样只要会发送这样消息的过来,就会自动处理。最大限度的让菜单代码灵活。

弹出式菜单

PB帮助中这样写道

The   coordinates   you   specify   for   PopMenu   are   relative   to   the   active   window.   In   an   MDI  

application,   the   coordinates   are   relative   to   the   frame   window,   which   is   the   active   window.  

To   display   a   menu   at   the   cursor   position,   call   PointerX   and   PointerY   for   the   active   window  

(the   frame   window   in   an   MDI   application)   to   get   the   coordinates   of   the   cursor.   (See   the  

examples.)

右键菜单弹出时系统管理的,所以需要屏幕坐标才能准确;

所以怎样能够快速准确的找到父窗口对象就成了解决问题的关键。

 

未解决问题

菜单动态禁用的代码可能会比较分散,不便于管理;如果Powerbuilder能够支持   ON_UPDATE_COMMAND_UI这样的功能就好处理了。

 

1.8       SQLCA对象

Completed:   100   %

SQLCAPowerbuilde应用程序中   Transobject类别的一个全局对象,负责与数据库通讯,一般的用法我相信各位都在熟悉不过,在这里主要讨论一下存储过程的用法;

自己定义用户对象Transobject   的子类My_Trans;然后再定义外部函数的地方打开右键菜单。使用如下菜单项可以在这里定义存储过程和函数;把需要的存储过程都在这里做声名;

然后把全局对象SQLCA的类改称My_Trans,这样就可以像使用SQLCA的一般方法一样来使用存储过程;

1.9       双向第归,事半功倍

Completed:   100   %

想法是在该面试人员的PB答卷中被激发的,答卷最后一题是这样的:

运用第归算法写一个函数实现1100的累加。

在这份答卷中是这样写的

Long   uf_add(long   al_Start,   long   al_End)

{

  if   al_Start   >   al_End   then   Return   0

  if   al_Start   =   al_End   then   Return   al_End     //或者   al_End

  Return   al_Start   +   uf_add(al_Start   +   1,   al_End)

}

初一看以为是的错误的算法,当即我给了0分。

给分后心理已知不踏实,便仔细看了一下,才发现这是个正确的算法,算法很简练,只是在写法上有别于我下面给出的算法:

Long   add1   (Long   aparm)

{

  if   aparm   =   1   Then   Return   1

  Return   aparm   +   add1(aParm   -   1)

}

单从形式上看这两种写法,后者可能更简单些;

随后我把这两种算法都上级做了测试,结果都是5050,第归次数都是100次。

在我准备删除这些测试函数时,试卷上的函数突然给了我启发:al_Start   能加   ,   那么al_End为和不能减,两端都向中间靠拢,这样第归次数就可以减少一倍,再看看试卷上函数的第归结束条件,不正好满足这样的要求吗?于是便有了下面的经典(我自封的)第归算法:

Long   add2   (Long   a1,   Long   a2);

{

if   a1   >   a2   then   return   0

if   a1   =   a2   then   return   a1

return   a1   +   add2(a1+   1,   a2   -   1)   +   a2

}

经测试结果为5050,第归次数为51

虽然这种算法在我们的编码中可能很少用到,但是这种“双向第归”的方法却可以让效率按倍数提升;

 

1.10       Tracing

Completed:   100   %

使用如图所示的Profiling,然后在程序运行的时候可以把每个函数的运行时间和次序打印到文件中。

 

源文档 <file:///E:/资料/Doc/PB100.doc>

 

PFC3D是一种用于粒子流动仿真的软件工具,它可以模拟颗粒之间的相互作用和运动,可以用于分析颗粒流的特性和优化流动过程。在进行PFC3D仿真时,可能需要定义多个函数来描述颗粒的运动规律或模拟特定的行为。如果要定义多个函数并将它们按照一定规则命名,就需要批量命名函数。 在PFC3D中,可以通过使用编程语言来定义和命名函数,这个编程语言叫做PFC扩展语言(PFC Extension Language)。可以先定义一个模板函数,然后使用循环语句和字符串拼接操作来动态生成函数名。 具体步骤如下: 1. 定义一个模板函数,给函数取一个统一的前缀和后缀。例如,定义一个名为“set_velocity”的模板函数。 2. 使用循环语句来遍历需要生成的函数数量,根据每个函数的序号来动态生成函数名。例如,假设要生成10个函数,可以使用一个for循环来遍历10次,设置一个变量 i 来记录循环次数,每次循环时使用字符串拼接将前缀、序号和后缀拼接成函数名。 3. 在循环中,使用PFC扩展语言的函数定义语句来定义函数,将生成的函数名作为函数名参数传入。例如,使用下面的代码来生成10个函数: for (i=0; i<10; i++) { setvelocity("func_" + i); } 这里的 setvelocity 函数是模板函数,"func_" + i 是动态生成的函数名。 通过这种方法,就可以批量命名PFC3D函数了。注意,在定义函数时,需要根据具体应用场景确定函数参数和返回值的类型和值域范围,以保证函数的正确性和可用性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值