精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● Powerbuilder>>锦上添花 技巧大家谈>>PowerBuilder编程技巧

主题:PowerBuilder编程技巧
发信人: love1974()
整理人: flyingmist(2000-03-05 23:36:27), 站内信件
PowerBuilder编程技巧 

   随着数据库技术在各行各业的广泛应用,作为企业级数据库前端开发工具的P
owerBuilder日益成为开发人

员的得力助手。PowerBuilder以其开放的体系结构,友好的用户界面和简洁高效
的开发环境赢得了众多程序

员的喜爱,连续多年被评为美国计算机界的年度风云产品,在数据库开发工具领
域占据了高达44%的市场份额。

  在这里,笔者将自己平日用PowerBuilder作开发的一些体会整理出来,奉献给
大家。 PowerBuilder是由多个

功能模块组成的可视化集成开发环境,是面向对象的开发工具,用它可以方便地
建立起基于Windows的分布式数

据库应用。其功能模块分别完成应用管理、窗口对象设计、菜单对象设计、数据
窗对象设计和数据库查询等工作,

这些功能模块由于PowerBuilder提供的色彩丰富的工具条而被称作"Painter"(画
板)。下文便依据各模块作大

的分类介绍相

应的编程技巧。

  一、有关应用的编程技巧 

     仅让应用程序运行一次的技巧: 有时需要限制一个PowerBuilder应用同时运
行的实例(Instance)个数或

仅让应用运行一次,我们可以通过调用WindowsSDK函数或使用PowerBuilder的Ha
ndle()函数来实现。先谈调用

SDK函数的方法。为了调用SDK函数,需要在ApplicationPainter的菜单项Declar
e\GlobalExternalFunctions中

定义: FunctionuintGetModuleHandle(stringModuleName)
           Library"Kernel.exe" FunctionuintGetModuleUsage(uintModuleHa
ndle)Library"Kernel.exe" 

    下面这段程序写在Application的Open事件中。

    它先通过调用SDK函数GetModuleHandle()获得指定应用程序的句柄,然后调
用GetModuleUsage()函数确定应

用程序同时运行的实例个数。

   uint IApplHandle int App_num IApplHandle=GetModuleHandle("c:\rem\re
m.exe") 
   if IApplHandle>0 then App_num=GetModuleUsage(IApplHandle)
       if App_num>1 then Messagebox("注意","本程序已经运行!",Stopsign!
)
           return 
       endif
   endif
  Open(w_main) 

  若需要限制应用同时运行的实例个数,比如仅允许同时运行N个实例,那么将上
述程序中的语句 

  “if App_num>1 then”改为“if App_num>N then”即可。 

  采用Handle()函数的方法更简洁一些,代码如下: 
   int hand hand=Handle(this,TRUE) 
       If hand>0 then Messagebox("注意","本程序已经运行!",Stopsign!) 

          Halt else Open(w_main)
       end if 
 
  二、有关窗口的编程技巧 
      1、提供类似中文之星的实时帮助条 中文之星2.0版的链形菜单管理器提供
了实时帮助条,增强了系统
  
  的易用性,在PowerBuilder中也可以实现类似的功能。当鼠标移动到窗口中的
某些控制(Control),如编辑
  
  器、图片等时,会在鼠标附近自动产生帮助条,实时地提示操作要领。首先在
窗口w_main中任意位置定义一

  个黄底黑字的静态文本st_help,设定st_help.visible=false,st_help.text
=&Help;然后在该窗口模块

  的Declare\WindowFunctions...下定义函数show_help(),其参数只有一个,参
数名为text,类型为string,

  通过传值方式接收参数;无返值。show_help()代码如下: 
   if st_help.visible then
       return st_help.text=text 
       st_help.width=Len(st_help.text)*38 
       st_help.x=w_main.PointerX() 
       st_help.y=w_main.PointerY()+50 
       if st_help.x+st_help.width>w_main.Workspacewidth() then 
          st_help.x=w_main.Workspacewidth()-st_help.width 
       end if 
       if st_help.y+st_help.height>w_main.Workspaceheight() then 
          st_help.y=w_main.Workspaceheight()-st_help.height
       end if
       st_help.visible=true 
   end if
   接下来,我们就可以调用show_help()函数了。但PowerBuilder提供的所有控
制均缺乏当鼠标移至其上就触发

的事件,显然,需要定义相应的用户事件。先选中准备定义用户事件的控制,如
某个单行编辑器,然后在窗口模

块的菜单Declare\UserEvents...下,双击PasteEventID:中的pbm_mousemove条目
,将其拷贝至EventID下,取

EventName为Mouseon,这样,我们就定义好了相应控制的用户事件Mouseon。我们
可以在该控制的用户事件

Mouseon下,写下调用函数show_help()的语句: 

   if st_help.visiblethenHide(st_help)  then
       show_help("瞧!这便是实时帮助条!") 
   end if

   2、“跑马灯”的实现技巧
      有时需要用一矩形条显示少量用户特别关心的信息,这条信息串首尾相连
,向一个方向循环滚动,我们通

常将其称作“跑马灯”。证券业中常用“跑马灯”来显示不断变化的股票行情;
实际应用中也常通过“跑马灯”

来监视是否死机。我们可以写一个简单的函数running_horse()来实现“跑马灯”
的显示。running_horse有两个

参数,第一个参数的参数名为textline,类型为string,传值;第二个参数的参
数名为num,类型为int,传值;

函数返值类型为string。该函数的代码仅一句: 

      returnMid(textline,(num+1))+Left(textline,num) 

      下面就可以调用running_horse()函数了。先在一个窗口里定义好单行编辑
器sle_running_horse,在该窗

口的Open事件下写上: 
                     sle_running_horse.text="Iamtestingrunning_horse!"
 
                     Timer(0.2)
      
      然后在该窗口的Timer事件下调running_horse(),代码如下: 
      
      sle_running_horse.text=running_horse(sle_running_horse.text,1) 

      
       这样,当你打开这个窗口时,“跑马灯”便会运转起来。可以在程序中加
些语句,适时地增减

sle_running_horse.text中的内容,你便会在“跑马灯”中看到相应变化的信息
。 

    三、有关菜单的编程技巧
        右键菜单的实现技巧: 当你在相应的窗口或控制上按鼠标右键时,就会
在鼠标所指位置弹出菜单,这就

是右键菜单。程序中支持右键菜单会为用户的操作带来许多方便,同时鼠标右键
可以分担部分左键的功能。在

PowerBuilder中实现右键菜单非常简单,仅两个步骤:

       1.设计相应菜单;

       2.在窗口或控制的Rbuttondown事件下写上调用语句。

       先在MenuPainter中创建菜单rbuttonpop,rbuttonpop有一个菜单条目(M
enuitem)m_choice。然后在需要

       调用该菜单的窗口或控制的Rbuttondown事件下写上: 
       
        m_rbuttonpop NewMenu 
        NewMenu=Createm_rbuttonpop 
        NewMenu.m_choice.PopMenu(PointerX(),PointerY()) 

        至此,右键菜单制作完毕。

        上述语句中的NewMenu的数据类型为m_rbuttonpop,当你在相应位置按鼠
标右键时,弹出的菜单NewMenu

是菜单m_rbuttonpop的一个实例(Instance)。

   四、有关数据窗的编程技巧 
      
       数据窗对象是PowerBuilder中最重要的概念之一,它是PowerBuilder应用
区别于其它Windows应用的重要

特征,同时也是PowerBuilder的价值所在。PowerBuilder应用通常通过数据窗对
象从数据库或其它数据源取得数

据并加以显示,其数据的输入、添加、修改和删除也大都通过数据窗对象来实现
。故理解并掌握数据窗概念对于

用好PowerBuilder具有重要意义。下面给出了有关数据窗的几个编程技巧。 
     
     1、自动调整大小的数据窗 在PowerBuilder应用运行过程中,常常会用鼠标
拖动窗口角以改变窗口大小,

尤其是在多文档窗口(MDI)中,通常有多个sheet存在的情况下,有时为了察看
后面窗口中的数据而将前面窗口

缩小,但窗口缩小了,其中的数据窗并没有缩小,由此而不能方便地使用数据窗
的卷滚条,那么怎样使前面窗口

中的数据窗大小随窗口的大小自动调整呢?很简单,我们只需要在数据窗所在窗
口的Resize事件下写上一句话:
  
        Resize(dw_datamon,this.Workspacewidth()-50,this.Workspaceheigh
t()-50) 
       
        其中dw_datamon是数据窗的名字,数字50可以调整。
        
        这样,你就拥有了一个会随窗口大小变化而自动调整大小的数据窗了。
卷滚条用起来很方便,不信试试。
   
     2、Retrieve后不回卷的数据窗 
        
        我们经常面对一大堆数据,其具体体现就是数据窗很长,需要拉动垂直
卷滚条才能看到后面的数据,当

你在包含长数据窗的窗口的Timer事件中写下Retrieve()语句后,令人气恼的事情
就会发生:Timer事件一执行,

数据窗就翻回第一页;如果Timer事件执行的时间间歇很短,那我们就永远没有足
够的时间来察看后面的数据了。

下面我们着手解决这个问题。 可能你已经注意到了,每个数据窗都拥有两个与R
etrieve有关的事件:

Retrievestart和Retrieveend,它们分别允许我们在Retrieve的前后干一些事,
这正是我们所需要的。实际上,

就这两个事件,我们已经能够提出两个解决方案了。其一,在Retrievestart事件
中,保存当前数据窗中可见的

 数据行;然后Retrieve;接着在Retrieveend事件中,恢复先前保存的数据行。其
二,在Retrievestart事件中,

保存当前垂直卷滚块的位置;Retrieve后再恢复其位置。后者使用了动态数据窗
函数,实现起来更简洁一些,

下面详细探讨。 假设你已设计好了一个在窗口w_datamon中的数据窗dw_datamon
,现在可以先定义一个保存垂直

卷滚块位置的类型为string的Globle变量old_vspos,然后在该数据窗的Retriev
estart事件下输入以下语句以保

存其位置:

         old_vspos=this.dwDescribe("DataWindow.VerticalScrollPosition"
)
         dw_datamon.SetRedraw(false) 
         
         在相应的Retrieveend事件下输入恢复垂直卷滚块位置的语句:
        
         this.dwModify("DataWindow.VerticalScrollPosition="+old_vspos)
 

         dw_datamon.SetRedraw(true) 

         这样,数据窗上的工作已做完。下面是相应窗口上的工作。

        该窗口的Open事件下: 
      
        dw_datamon.Settrans(sqlca) 

        dw_datamon.Retrieve()
       
        timer(6) 

        该窗口的Timer事件下: 

           Setfocus(w_datamon) Retrieve(dw_datamon)

       至此,Retrieve后不会回卷的数据窗dw_datamon已经可以工作了。值得注
意的是,数据窗的排序分类等

操作应在Retrieve前就在数据库表中完成,否则Retrievestart事件保存的卷滚块
位置很可能并不是你所期待的,

换句话说,Retrievestart事件应发生在所有数据窗操作之后;另外,在每次Ret
rieve后,应将处于该数据窗上

的Focus移开,以免具有焦点的数据窗的第一行第一列总要显示,故在窗口w_dat
amon的Timer事件中设置了

Setfocus(w_datamon)这条语句。 

       3、依据条件改变数据颜色 

          依据条件改变数据颜色是许多场合都要用到的重要功能,数据颜色的
改变不仅引人注目,而且能起到

暗示作用,清楚地告诉用户价位的涨跌或状态的改变等。大多数证券期货实时行
情显示软件都提供了这种功能。

在当前价位比其前一价位高时,当前价位数据颜色变红,表示价位上涨;反之,
颜色变绿,表示价位下跌;若当

前价位与其前一价位相等,则数据颜色不变。PowerBuilder没有提供解决这一问
题的捷径,但我们仍可利用动态

数据窗来实现。先考虑一下实现的步骤,在Retrieve前需要把有关列的数据先保
存起来;Retrieve后我们获得了

相应列的新数据;我们需要将上述二者作一比较,以确定颜色的变化。值得指出
的是,由于动态数据窗函数

dwModify()只能用描述数据窗的模式串作参数,不能接收变量作参数,故我们得
想法把比较的结果传递给数据窗。

为解决这个问题,可以在定义数据窗时多定义几个空列,这几列不与数据库表中
的列相对应,它们作为存放比较

结果的缓冲区。原则上若需要N列实时地变色,则需要N列缓冲区,就应该多定义
N个空列。下面给出了一个例子

具体说明。 这段程序写在某窗口的Timer事件中,该窗口内有数据窗dw_infor,
其"buy"、"sell"列分别表示买价

和卖价,需要实时地变颜色。为此,我们在数据窗dw_infor中多定义了"buybuf"
和"sellbuf"两列,分别存放

"buy"列和"sell"列Retrieve前后数据比较的结果。

 //Red=255;Green=65280 

    int i,infor_rownum decimalbuy_old[],sell_old[],buy_new[],sell_new[


    dw_infor.SetRedraw(false) 

    infor_rownum=dw_infor.RowCount() 

    FOR i=1 To infor_rownum 

       buy_old[i]=dw_infor.GetitemNumber(i,"buy")

       sell_old[i]=dw_infor.GetitemNumber(i,"sell") 

    NEXT
   
    dw_infor.retrieve()

    FOR i=1 TO infor_rownum

       buy_new[i]=dw_infor.GetitemNumber(i,"buy")

       sell_new[i]=dw_infor.GetitemNumber(i,"sell") 

    NEXT

    FOR i=1 TO infor_rownum 

       dw_infor.Setitem(i,"buybuf",buy_new[i]-buy_old[i]) 

       dw_infor.Setitem(i,"sellbuf",sell_new[i]-sell_old[i]) 
    NEXT

    dw_infor.dwModify("buy.color='0~tif(buybuf>0,255,if(buybuf<0,65280
,0))'")

dw_infor.dwmodify("sell.color="0~tif(sellbuf>0,255,if(sellbuf<0,65
280,0))'")

dw_infor.setredraw(true)

我们看到,程序在Retrieve前后分别将"buy"和"sell";列的数据写进与其类
型匹配的数组中,然后将比较

的结果分别写入"buybuf"和"sellbuf"列,最后用函数dwModify()改变有关列的颜
色。记住在该窗口的Open事

件中设置事务对象并激活Timer事件。此外,还有一些方法可以改变颜色,比如先
在某些需要变颜色的行或列

设置带颜色的长方形,同时将其上面的数据窗中的数据设置成透明的,当条件改
变时,可以通过改变数据窗后

的长方形的颜色来实现。

4、用Enter键替代Tab键切换栏目的数据窗

许多情况下,PowerBuilder应用的数据是通过数据窗输入的,而且输入的
数据是单纯的数字数据,也就是

说,输入内容完全可以通过敲击键盘右面的数字小键盘来完成。但在实际使用中
,数据窗栏目间的切换却要通过

按键盘最左边的Tab键来实现,既不方便又影响录入速度。如果能用Enter键替代
Tab键切换栏目就好了。由于按

Enter键是Windows直接支持的消息,故我们可以使用用户事件来解决问题。在用
户事件中,PowerBuilder提供的

一条pbm_事件对应Windows的一条或几条消息。我们在数据窗dw_datamon的用户事
件中选择

pbm_dwnProcessEnter并命名为Enterkeydown。在该事件下写代码:

Send(Handle(this),256,9,Long(0,0))

return 1

这将把消息传递给Tab键,同时忽略Enter键的处理。 下面是一段用数据
窗接收数据的完整的程序段,

其中采用了用Enter键替代Tab键的代码。当光标在每行最后一列时按Enter键
,光标会移至下一行第一列;

当光标在最后一行的最后一列时按Enter键,会自动产生新行并将光标置于该行的
第一列;在其它情况下按Enter

键,光标会移至当前行的下一列。这段程序仍然写在与pbm_dwnProcessEnter相对
应的用户事件Enterkeydown下:

IF This.AcceptText()<0 then

return 1
end if

if this.getcolumn()=Long(This.DwDescribe("datawindow.column.count"
)) then

if this.getrow()=This.RowCount() then

this.insertrow(0)
this.scrolltorow(this.getrow()+1)
this.setcolumn(1)
return 1
end if
end if
send(handle(this),256,9,long(0,0))
rerurn 1


--
love1974[灌水版(还未开盘)斑竹] 灌翻网易,一大快事
太太平平,不是我活着的目标;不温不火,不是我的性格。是云就该下雨,是火就该发光。
那罐星砂送給你
╭╯ ╰╮╭╯╰╮ 願你心想事成
║▃▃▃║║☆★║ 這罐海水留給我

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.96.190.124]

[关闭][返回]