Powerbuilder之5年经验谈(一之3)——关键字Post
版权声明
本系列文章在博客园发表,除允许在互联网上自由转载外,不得以其它任何方式拷贝、编辑、印刷出版、制作发行及传播,包括不得未在笔者知晓的情况下制作成各种格式的电子文档并传播,更不得在未经笔者本人允许的情况下以任何形式的拷贝用于商业用途。笔者又本系列文章保留有追究其侵权责任的权利。
若需制成电子文档并用于非商业用途方式的传播,请保留以下版权信息,并与笔者联系邮寄副本一份。
作者:
网名:SummerHeart
Email:Costware@163.com
Blog:http://summerheart.cnblogs.com/
http://blog.csdn.net/summerheart
时间:2008.6.26 Copyright: 2008
当使用以下脚本调用时
w_a mywindow
Open(mywindow, "w_a_desc")
mywindow.DYNAMIC Set("hello")
程序运行并不会出错,因为它调用的是w_a_desc的set()函数。Mywindow是一个w_a的变量,但它指向了子类w_a_desc的实例。这是一种典型的装箱过程,但是在父类w_a的定义中并没有Set(String)的这个函数,在这里又能被w_a访问调用。这在程序编写的有些时候是很方便的。
通常的父类是不允许调用子类的特定函数的,因为这会破坏了父类定义的接口规则。这种方法的使用也影响了代码的维护,例如一旦改变了子类w_a_desc该函数接口,编译器并不会在第一时间报出错误,而只能到运行时才会出错。无形时即影响了软件质量,又给测试增加了测试难度。
在讲关键字Create时已经绍介过Windows的消息机制(参见关键字Create),Post与Send就用来向窗口和控件发送消息的,这些消息通过消息队列后最终被处理执行。
if isValid(w_2) then
send(handle(w_2),274,61488,0)
end if
#define WM_SYSCOMMAND 0x0112 //274
#define SC_MAXIMIZE 0xF030 //61488 最大化窗口控件
用Post发送的消息处理时间是不确定的,这取决于操作系统调度的,以及当时计算机的运行情况来决定。我们可以用个例子来测试下Post的调试时间,先创建个nvo对象ou_obj,定义2个实例变量,
int foo_a =0 // 函数执行状态。当为1时表示函数被执行
int li_t =0 //记录下执行时的时间
并定义三个函数,
public function integer of_foo () //用于测试的函数
public function integer of_getfoo () //返回函数执行状态
public function integer of_gettime ()//返回当函数被执行时的时间
global type ou_obj from nonvisualobject
end type
end forward
global type ou_obj from nonvisualobject
end type
global ou_obj ou_obj
type variables
int foo_a =0 // 当为1时表示函数被执行
int li_t =0 //记录下执行时的时间
end variables
forward prototypes
public function integer of_foo ()
public function integer of_getfoo ()
public function integer of_gettime ()
end prototypes
public function integer of_foo ();
li_t =cpu() //记录函数被执行时的时间
foo_a =1 //表示函数被执行了
return 1
end function
public function integer of_getfoo ();
//返回foo是执行标记foo_a
return foo_a
end function
public function integer of_gettime ();
//返回函数开始执行的时间
return li_t
end function
on ou_obj.create
call super::create
TriggerEvent( this, "constructor" )
end on
on ou_obj.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on
然后我们新建个窗口,定义如下的变量:
ou_obj lo_obj //对象的实例
int li_t //保存调用对象函数前的时间
并在窗口上放二个按钮cb_1和cb_2,代码分别如下:
cb_1事件代码
lo_obj =create ou_obj
li_s=cpu()
li_t =li_s
lo_obj.post of_foo()
li_e=cpu()
messagebox("","执行时间 :"+String(li_e - li_s)+"~t函数执行: "+string( lo_obj.of_getfoo()))
cb_2的事件代码
messagebox("","执行时间 :"+String( lo_obj.of_getTime() -li_t)+"~t函数执行: "+string( lo_obj.of_getfoo()))
end if
运行程序后,先点cb_1调用lo_obj.post of_foo(),再点击cb_2如果如下图:
而点cb_2结果各不相同,且相差很大
无论点击cb_1多少次,都是一样的执行时间为0,并且of_foo()是未被执行的状态。而点了cb_1后再点cb_2,此时函数才被执行过。所以用post调用的函数和事件,是不会被立即执行的,而什么时候执行,是无法确定的。 因此在使用post的时候应注意被调用的对象函数有可能在系统执行时已经被销毁,这时候系统就容易出事调用错误。这种情况往往发生在1、窗口close事件里使用了post调用窗口控件的事件;2、对象的destructor事件里使用了post调用对象函数;3、在destroy对象前使用post调用该对象的函数或事件。以上三种情况都是需要避免的。还有一种情况也应该引起注意的,例如有个函数initListbox对DropDownListBox初始化增加选项,而GetCurrentItem用来获取当前的选项值,如果post调用了initListbox,即使之后使用GetCurrentItem取值也会出错误,因为GetCurrentItem取值时iniListBox有可能还没被执行,初始化选项还没被添加进去,取值要么出错误,要么取到的并非是你想要的值,这就程序带来了隐患。所以这也是需要避免的。
另外来看看Post的几种形式:
1、 Obj.Post foo( ) 发送消息给函数
2、 Obj.Post Event eventname() 发送消息给事件
3、 Obj.PostEvent( "XXXX ",{Word},{Long})以函数形式调用XXXX事件或函数
这三种形式都是一样的原理。形式不同而已。
if dwo.name = "c_date" then
ld_date = datetime(date(data),now())
this.setitem(row,"c_date",ld_date)
accepttext()
end if
但如果你把setitem()一句写成this.Post setitem(row,"c_date",ld_date)就可以满足要求。(当然这个例子只是一种解决法,在后面讲Datawindow时笔者还是给出另一种更好的解决方法)
返回目录 返回 下页