打印本文 打印本文 关闭窗口 关闭窗口
Powerbuilder应用开发系列讲座(31)
作者:武汉SEO闵涛  文章来源:敏韬网  点击数884  更新时间:2009/4/24 21:43:50  文章录入:mintao  责任编辑:mintao
p align="center">在数据窗口中使用滚动条(续)


  在上期中我们讨论了在Master/Detail数据窗口中,当Master数据窗口没有使用RetrieveasNeeded选项时,两个数据窗口同时滚动的问题。可是当Master数据窗口使用了RetrieveasNeeded 选项时,我们却遇到了麻烦。在点击dw_2的滚动条时,如果dw_1从数据库中取得了新数据,将导致dw_2的复位,dw_2就不能显示正确的结果了。解决这个问题,我们最容易想到的解决方法就是利用dw_2在scrollvertical事件中获得的dw_2当前滚动条的位置,对dw_2进行重新赋值。
  即对dw_1的SCROLLVERTICAL事件编程如下:

integervmax_1,vpos_1,vmax_2,vpos_2
stringr_code
decimalvmax_1_percent
vmax_1=integer(dw_1.describe(datawindow.verticalscrollmaximum)) vpos_1=integer(dw_1.describe(datawindow.verticalscrollposition)) vmax_2=integer(dw_2.describe(datawindow.verticalscrollmaximum)) vmax_1_percent=vpos_1/vmax_1
vpos_2=vmax_1_percent*vmax_2
r_code=dw_2.modify(datawindow.verticalscrollposition=+string(vpos_2)) //检验是否修改成功
ifr_codethen
beep(6)
mle_1.text=dw_1scroll=+r_code+vpos_2= +string(vpos_2)
//在scrollvertical事件中无法使用MessageBox弹出错误信息框
endif
对dw_2的SCROLLVERTICAL事件编程如下:
integervmax_1,vpos_1,vmax_2,vpos_2
stringr_code
decimalvmax_2_percent
vmax_2=integer(dw_2.describe(datawindow.verticalscrollmaximum)) vpos_2=integer(dw_2.describe(datawindow.verticalscrollposition)) vmax_1=integer(dw_1.describe(datawindow.verticalscrollmaximum)) vmax_2_percent=vpos_2/vmax_2
vpos_1=vmax_2_percent*vmax_1
r_code=dw_1.modify(datawindow.verticalscrollposition=+string(vpos_1)) //检验是否修改成功
ifr_codethen
beep(6)
mle_1.text=dw_1mod+r_code
endif
r_code=dw_2.modify(datawindow.verticalscrollposition=+string(vpos_2)) //检验是否修改成功
ifr_codethen
beep(6)
sle_1.text=dw_2mod+r_code
endif

  键入上述代码后,运行时你就 ⑾值慊鱠w_2时运行的结是正常的,然而点击dw_1的滚动条却发生了错误。这是为什呢?
  首先我们还是对用户点击dw_1的滚动条向下滚动时,系统进行了哪些操作进行一下仔细地分析:当用户点击鼠标使dw_1滚动到了最后一行时,这时系统没有立即进行显示滚动的操作,它首先发现数据窗口的Primary!缓冲区的数据已经告罄,于是就向后台的数据库中攫取数据,取得新的数据后,系统会将与dw_1共享数据的dw_2复位,使之回到显示第一条记录的位置。这就触发了dw_2的scrollvertical事件(我们称之为事件一)。在这个事件中,由于此时dw_2显示的是第一条记录,它将修改dw_1的滚动条位置,使之也显示第一条记录。并立即触发dw_1的scrollvertical事件二。在事件二中,dw_1又根据自己的位置修改dw_2,但是由于dw_2修改前后的位置相同,所以没有对系统造成什么影响,又回到了事件一。在事件执行完毕后,系统开始响应用户的下滚dw_1的操作,首先将dw_1向下滚动一条记录,这样dw_1显示的是第二条记录,并触发了dw_1的scrollvertical事件三。当事件三执行时,将dw_2也滚动到第二条记录,并触发了dw_2的scrollvertical事件四,不过这一事件四也不会对任何一个数据窗口造成影响,最后返回执行完事件三。这就完成了用户点击鼠标后的一连串响应。但是最后两个数据窗口却显示的是第二条记录。有兴趣的读者可以仔细分析这一系列事件发生的顺序。
  用户点击滚动条而使得上述代码对各个事件触发及其执行过程虽然十分复杂,并不是每一个人都有兴趣对其分析清楚,但是这个代码的错误却是一目了然的,只须稍加测试就可发现。可是令人不解的是这段代码在美国却几乎被视作经典,而且向美国PowerSoft技术支持中心提出这个问题,那里的工作人员也会引用这段代码作为回答。
  事实上解决这个问题的方法并不十分复杂,我们只需将修改滚动条位置的时间稍加改变就可以得到正确的结果。首先我们在这两个数据窗口中各声明一个ue_scrollvertical的用户自定义事件事件。传递一个参数,参数名为vpos,integer型,通过传值法传递。然后键入下列代码:
  对dw_1的SCROLLVERTICAL事件编程如下:

integerli_vmax_1,li_vpos_1,li_vmax_2,li_vpos_2
decimalld_vmax_1_percent
li_vmax_1=integer(dw_1.describe(datawindow.verticalscrollmaximum)) li_vpos_1=integer(dw_1.describe(datawindow.verticalscrollposition)) li_vmax_2=integer(dw_2.describe(datawindow.verticalscrollmaximum)) ld_vmax_1_percent=li_vpos_1/li_vmax_1
li_vpos_2=ld_vmax_1_percent*li_vmax_2
ifabs(li_vpos_2-integer(dw_1.describe
(datawindow.verticalscrollposition)))1then
//如dw_2应显示的位置与dw_2的当前位置不符,产生修改dw_2的事件
eventpostue_scrollvertical(li_vpos_2)
endif

  对dw_1的UE_SCROLLVERTICAL事件编程如下:

事件:自定义ue_scrollvertical
参数:vposinteger型
返回值:integer
stringls_ret_code
dw_2.modify(datawindow.verticalscrollposition=+string(vpos))
ifls_ret_codethen
beep(6)
sle_1.text=dw_1scroll=+ls_ret_code+ vpos=+string(vpo
s)
//在scrollvertical事件中将不能弹出错误信息框
endif
return1

  对dw_2的SCROLLVERTICAL事件编程如下:

integerli_vmax_1,li_vpos_1,li_vmax_2,li_vpos_2
stringls_ret_code
decimalld_vmax_2_percent
li_vmax_2=integer(dw_2.describe(datawindow.verticalscrollmaximum))
li_vpos_2=integer(dw_2.describe(datawindow.verticalscrollposition))
li_vmax_1=integer(dw_1.describe(datawindow.verticalscrollmaximum))
ld_vmax_2_percent=li_vpos_2/li_vmax_2
li_vpos_1=ld_vmax_2_percent*li_vmax_1
eventpostue_scrollvertical(li_vpos_1)
//由于dw_1使用了retreive-as-needed,可能会自动将dw_2
滚回第一行,表现重新设置dw_2
ls_ret_code=dw_2.modify
(datawindow.verticalscrollposition=+string(li_vpos_2))
//检验是否修改成功
ifls_ret_codethen
beep(6)
sle_1.text=dw_2mod+ls_ret_code
endif

  对dw_2的UE_SCROLLVERTICAL事件编程如下:

事件:自定义ue_scrollvertical
参数:vposinteger型
返回值:integer
stringls_ret_code
ls_ret_code=dw_1.modify(datawindow.verticalscrollposition=
+string(vpos))
//检验是否修改成功
ifls_ret_codethen
beep(6)
sle_1.text=dw_1mod+ls_ret_code
endif

  我们再分析一下上述代码执行的过程:用户点击了dw_1的动条,使dw_1将滚动到最后一行,产生了dw_1的scrollvertical事件一,但并没有立即执行,只放在了事件队列的后面。系统首先发现数据窗口的Primary!缓冲区中数据为空,向后台数据库取数据,并使dw_2复位,回到显示第一条记录的位置。这触发了dw_2的scrollvertical事件二,在首先执行的这个事件二中,PowerBuilder根据dw_2当前显示的是第一条记录这一条件,产生一个ue_scrollvertical事件三,将dw_1也滚回显示第一条记录,但是这个事件三并没有立即触发执行,而是放在了事件队列的最后。

  当事件二执行完毕后,系统响应用户对dw_1进行的向下翻页的操作,并触发dw_1事件一的执行。这时dw_1显示的是用户希望看到的正确的记录,PowerBuilder根据dw_1的当前位置,计算出dw_2与之相对应的位置,将修改dw_2位置的操作ue_scrollvertical事件四
放在了事件队列的最后。这时该执行事件三了,事件三修改dw_1滚动条的位置至第一条记录,这一操作触发了dw_1的scrollvertical事件五,此时两个数据窗口均显示的是第一条记录。

  在这一事件中,PowerBuilder经过计算,得到了dw_2应显示的位置与当前位置相等的结论,因此不产生ue_scrollvertical事件,事件五没有对系统产生任何影响。接下来执行的是事件队列中仅存的事件四,在这个事件里,系统将dw_2滚动至正确的显示位置上,并触发了dw_2的scrollvertical事件六。在事件六中,系统又产生dw_2的ue_scrollvertical事件七,但是这两个事件均没有对显示造成任何影响,这两个事件执行过程中也没有再产生新的事件,这一系列的响应便最终结束了。而最终的结果是两个数据窗口都是停在了正确的结果上了。
  同理,我们对用户滚动dw_2后系统的响应进行细致地分析,也可以看到上述代码的正确性,这里就不再赘述了。
  我们在本篇中编写的代码可能并不一定在您开发的软件中使用得上,但是如果您能够对这一代码执行的过程全部自行分析清楚,或者有足够的耐性看明白了上面文章的分析,那么您对PowerBuilder的事件一定会有更深的理解。

打印本文 打印本文 关闭窗口 关闭窗口