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事件的后才会把Control中Control控件释放这时各个Control控件destructor事件会被触发等所有Control控件被释放后再触发窗口Destructor完成释放过程
用流程图表示:
注意:Control控件创建先后顺序要看Control控件怎样存储在Control中Powerbuilder无论是创建过程还是释放过程都是从下表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 %
通用菜单
我们不需要解释什么叫菜单所以就直接不如正题在实际开发过程中菜单是必不可缺有时为了方便会把所有弹出式菜单都坐在个类中需要时用那个弹那个有时也会作些通用菜单作为公用组件使用
下面列出我们常见菜单编程思路方法来引出这个问题:
• 指定窗口对象:
w_.relogon
• 直接全局:
gf_relogon
• 使用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 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然后在运行时候可以把每个运行时间和次序打印到文件中
最新评论