powerbuilder:PowerBuilder 被忽略的的技术

  1.1    把Object看作类

  Completed:  100  %

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

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

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

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

  1.2    窗口Control控件创建和释放

  Completed:  100  %

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

  创建过程:

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

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

  用流程图表示:

  释放过程:

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

  在窗口收到WM_CLOSE消息前会先收到WM_CLOSEQUERY消息来给开发人员个阻止WM_CLOSE发生时机;在Powerbuilder中WM_CLOSE  <= >  Event  Close  WM_CLOSEQUERY  <= >Event  CloseQuery

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

  用流程图表示:

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

  1.3    谨慎使用Post

  Completed:  100  %

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

  Post以关键字形式出现:

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

  发送消息给以Powerbuilder形式出现消息处理:this.Post  name(  )(这种思路方法有别于  this.name)

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

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

  Post以形式出现

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

  XXXXX  是名或事件名

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

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

  这里顺便提到点:

  在Control控件代码中尤其是按钮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不是个菜单类型

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

  1.5    隐藏全局类和局部类

  Completed:  100  %

  隐藏全局类

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

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

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

  w_  w_a,w_b

  open(w_a)

  open(w_b)

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

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

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

  global  type  ww  from  window

  global  ww  ww

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

  隐藏局部类

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

  现在有个窗口w_在窗口上方防置了个按钮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_

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

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

  1.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    in  the  script  for  the  user-d  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.

  ReturnValueLong牋When  Message.Processed  is  true,  species  the  value  you  want  ed  to  Windows.  This  property  is  ignored  when  Message.Processed  is  false.

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

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

  Message对象种功能:

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

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

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

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

  Message对象第 2种功能:

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

  例如OpenWithParm(w_a, "ACB ")

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

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

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

  我们可以肯定:

  OpenWithParm

  OpenSheetWithParm

  OpenUserObjectWithParm

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

  Open

  OpenSheet

  OpenUserObject

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

  目前我只发现这些

  所以可以有结论以上 6个中任意个时就会把Message重置

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

  需要注意:第 2种功能中只会影响到DoubleParm、StringParm、PowerObjectParm 3个参数

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

  1.7    有关菜单编程

  Completed:  75  %

  通用菜单

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

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

  &#8226; 指定窗口对象:

  w_.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( " ", &apos;wm_m1 &apos;)

  Return  1  

  Case  WM_M2

  MEssageBox( " ", &apos;wm_m2 &apos;)

  Return  1  

  Case  WM_M3

  MessageBox( " ", &apos;wm_m3 &apos;)

  End  Choose

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

  弹出式菜单

  在PB帮助中这样写道

  The  coordinates  you  specy  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  PoerX  and  PoerY  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  %

  SQLCA是Powerbuilde应用中  Transobject类别个全局对象负责和数据库通讯使用方法我相信各位都在熟悉不过在这里主要讨论下存储过程使用方法;

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

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

  1.9    双向第归事半功倍

  Completed:  100  %

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

  运用第归算法写实现1到100累加

  在这份答卷中是这样写

  Long  uf_add(long  al_Start,  long  al_End)

  {

    al_Start  >  al_End  then  Return  0

    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)

  {

    aparm  =  1  Then  Return  1

  Return  aparm  +  add1(aParm  -  1)

  }

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

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

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

  Long  add2  (Long  a1,  Long  a2);

  {

    a1  >  a2  then    0

    a1  =  a2  then    a1

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

  }

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

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

  1.10    Tracing

  Completed:  100  %

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



Tags:  powerbuilder教程 powerbuilder9.0 powerbuilder powerbuilder

延伸阅读

最新评论

发表评论