PowerBuilder作为开发数据库应用的工具,因为使用其开发方便、快捷并且实现的系统功能强大而深得程序员们的喜爱,我们可以看到越来越多优秀的数据库系统里出现它的身影。但是,随着用户界面设计的重要性被认可程度的加深,PowerBuilder在界面设计方面的缺憾就显现出来了,这也是令很多程序员伤脑筋的地方,不可否认的是规划应用图形界面是开发初期费时费力又不得不做的事情,尤其重要的是按钮的制作,笔者在开发很多的应用都面临着这种情况,经过研究,在这方面有所收获,现将这些经验整理出来,希望对同行们有所帮助。
  为了实现PowerBuilder系统中按钮功能,自制按钮一般有四种方法。
  一、纯文字按钮
    特点:按钮的背景、按钮文字的颜色都可以变换,设计时所见即所得,占用系统资源较少。
    制作过程:
    1 创建用户对象。
     单击PowerBuilder工具栏上的User Object图标,在Select User Object对话框中单击New按钮,在New User Object对话框中单击Visual组的Standard图标,单击OK。
     在Select Standard Visual Type对话框中单击列表框中的statictext项,单击Ok。
    出现自定义对象设计环境,设置好背景颜色和对象的Icon后,单击保存为uo_vo_textbutton。
    2 声明外部函数(Local External Function):
    Function Long SetCapture(  Long hwnd) Library "user32"
    Function Long ReleaseCapture() Library "user32"
    Function ulong CreateRoundRectRgn(ulong X1,ulong Y1,ulong X2,ulong Y2,ulong X3,ulong Y3) LIBRARY "gdi32.dll"
    Function ulong SetWindowRgn(ulong hWnd,ulong hRgn,boolean bRedraw) LIBRARY "user32.dll"
    3 声明实例变量(Instance Variables):
      boolean changed=false
    4 声明自定义事件:(如下图)

PowerBuilder应用程序中的按钮设计_第1张图片

  5 在contructor事件中编写如下脚本:
    //本按钮为圆角按钮
    long l1
    long x1,y1,w1,h1
    x1=UnitsToPixels(this.x,XUnitsToPixels!)
    y1=UnitsToPixels(this.y,yUnitsToPixels!)
    w1=UnitsToPixels(this.width,XUnitsToPixels!)
    h1=UnitsToPixels(this.height,yUnitsToPixels!)
    l1= CreateRoundRectRgn(1,1,w1,h1,4,4)
    setwindowRgn(handle(this),lrgn,true)
  6 在mousedown事件下编写如下脚本:
    //按钮显示下陷
    this.borderstyle=StyleLowered!
  7 在Mouseover事件下编写如下脚本:
    long hand
    hand=handle(this)
    if xpos>=0 and xpos<=this.width and ypos>=0 and ypos<=this.height then
      if not changed then
       //鼠标移过时按钮文字变红,变粗
                //也可以改变背景颜色,这里没有改变
                this.weight=700
                this.textcolor=rgb(255,0,0)
                changed=true
      end if
      SetCapture(hand)
    Else
      //鼠标移出按钮时按钮文字恢复原来状态
      this.weight=400
      this.textcolor=rgb(0,64,128)
      this.borderstyle=StyleRaised!
      changed=false
      ReleaseCapture()
    end if
  7 在mouseup事件中编写如下脚本:
    //按钮恢复正常状态
    this.weight=400
    this.textcolor=rgb(0,64,128)
    this.borderstyle=StyleRaised!
    changed=false
    ReleaseCapture()
  具体应用:使用时只要在窗口设计中选择User Object 然后点选uo_vo_textbutton将它放置到窗口中即可(在程序中超级链接的文本也是依据这个原理制作而成的)。

  二、纯图片按钮
   特点:可以根据需要配置图片的个数,如Enabled状态和Disable状态,鼠标移过、鼠标左键按下,弹起,  缺点是当应用时必须为每个按钮都绘制图片,并且编译时要编写资源文件。
  制作过程:
  1 同一,只是点选对象变为Picture,保存为uo_vo_picbutton。
  2 声明外部函数:同一
  3 声明实例变量:
    boolean changed=false
    string s_normal     //正常状态下的图片路径和文件名称
    string s_over       //鼠标滑过下的图片路径和文件名称
    string s_down      //鼠标按下下的图片路径和文件名称
    string s_disable     //不能状态下的图片路径和文件名称
    string s_info        //鼠标移过的提示信息
  4 声明自定义事件:同一
  5 在contructor事件中编写如下脚本:
    //本按钮为圆角按钮
    //这里的脚本同上,为了省篇幅这里省略
    ……
    this.border=false
    this.picturename=s_normal
  6 在mousedown事件下编写如下脚本:
    this.picturename=s_down
  7 在Mouseover事件下编写如下脚本:
    long hand
    hand=handle(this)
    if xpos>=0 and xpos<=this.width and ypos>=0 and ypos<=this.height then
      if not changed then
                this.picturename=s_over
                changed=true
             end if
             SetCapture(hand)
    else
      this.picturename=s_normal
      changed=false
      ReleaseCapture()
    end if
  8 在mouseup事件中编写如下脚本:
    this.picturename=s_normal
    changed=false
  具体应用:使用时只要在窗口设计中选择User Object 然后点选uo_vo_picbutton将它放置到窗口,为它起个名字如p_uclose,然后在窗口的open事件中加入如下脚本:
  p_uclose.s_normal="G:\pb\wymis\pic\exitnormal.bmp"
  p_uclose.s_over="G:\pb\wymis\pic\exitfocus.bmp"
  p_uclose.s_down="G:\pb\wymis\pic\exitdown.bmp"
  p_uclose.s_disable="G:\pb\wymis\pic\exitdisable.bmp"
  p_uclose.s_info="关闭窗口"
  p_uclose.triggerevent(constructor!)

  三、以数据窗口为基础的按钮
  1 建立一个标准的、可视的数据窗口用户对象,并保存为u_vo_dwbutton,(操作过程同一),注意datawindow object name选择一个以外部数据源为基础的数据窗口即可(只有一个字段,建立数据窗口后删除这个字段)。
  2 声明外部函数(Local External Function):(同一)
  3 声明实例变量(Instance Variables)
    boolean changed=false
    string SbuttonName     //按钮名称
    long w1,h1            //按钮的宽度和高度,以像素为单位
  4声明自定义事件:(同一)
  5在contructor事件中编写如下脚本
          //按钮形状
    w1=UnitsToPixels(this.width,XUnitsToPixels!)
    h1=UnitsToPixels(this.height,yUnitsToPixels!)
    (其他同一)
    integer i_for
    long j_1
    string s_name,s_create
    //形成上黑下白的渐变
    for i_for=0 to h1
         s_name="line_"+string(i_for)
         j_1=rgb(i_for*255/h1,i_for*255/h1,i_for*255/h1)
         s_create="create line(band=background x1='0'"
         s_create=s_create+" y1='"+string(i_for)+"' x2='"+string(w1)+"'"
      s_create=s_create+" y2='"+string(i_for)+"' name=line_"+string(i_for)+ " pen.color='"+string(j_1)+"' pen.width='1') "
         this.Modify(s_create)
    next
      s_create="create text(band=background alignment='0' text=' "+SButtonName+"' border='0' color='16777215' name=psp x='0' y='0' height='19' width='89'  font.face='Arial' font.height='-12' font.weight='400'  font.family='2' font.pitch='2' font.charset='0' background.mode='1' background.color='553648127')"
this.Modify(s_create)
  6在Mouseover事件下编写如下脚本:
    long hand
    hand=handle(this)
    //形成上白下黑的渐变
    if xpos>=0 and xpos<=this.width and ypos>=0 and ypos<=this.height then
     if not changed then
      integer i_for
      long j_1
      string s_name,s_create
      for i_for=0 to h1
          s_name="line_"+string(i_for)
          j_1=rgb((h1 - i_for)*255/h1,(h1 - i_for)*255/h1,(h1 - i_for)*255/h1)
          s_create=s_name+".pen.color='"+string(j_1)+"'"
          this.Modify(s_create)
      next
         this.Modify("psp.color='16711680'")
      end if
      changed=true
      SetCapture(hand)
    else
      this.triggerevent("mouseup")
      changed=false
      ReleaseCapture()
    end if
  7在mouseup事件中编写如下脚本:
    integer i_for
    long j_1
    string s_name,s_create
    //形成上黑下白的渐变
    for i_for=0 to h1
    s_name="line_"+string(i_for)
    j_1=rgb(i_for*255/h1,i_for*255/h1,i_for*255/h1)
    s_create=s_name+".pen.color='"+string(j_1)+"'"
    this.Modify(s_create)
    next
    this.Modify("psp.color='16777215'")
    changed=false
  具体应用:使用时只要在窗口设计中选择User Object 然后点选u_vo_dwbutton将它放置到窗口,为它起个名字如p_uclose,然后在窗口的open事件中加入如下脚本:
  p_close.SButtonName="关闭"
  p_close.postevent(constructor!)

四 自绘控件
   这种方法是借助一个标鉴控件,在上面画出想要的按钮。
   1建立一个标准的、可视的标签用户对象,保存为u_vo_stbutton。
   2声明外部函数:
      Function long DeleteObject ( long hobject ) library "gdi32"
      Function uLong SelectObject(uLong hdc,uLong hObject) LIBRARY "gdi32.dll"
      Function uLong GetDC(uLong hwnd) LIBRARY "user32.dll"
      FUNCTION ulong CreateRoundRectRgn(ulong X1,ulong Y1,ulong X2,ulong Y2,ulong X3,ulong Y3) LIBRARY "gdi32.dll"
      FUNCTION ulong SetWindowRgn(ulong hWnd,ulong hRgn,boolean bRedraw) LIBRARY "user32.dll"
      FUNCTION boolean MoveToEx(ulong hwnd,long wx, long wy,ref us_point prepos2) LIBRARY "Gdi32.dll"
      FUNCTION boolean LineTo(ulong hwnd,long wx, long wy) LIBRARY "Gdi32.dll"
      Function ulong SetTextColor (ulong hDC, ulong crColor) Library "GDI32.DLL"
      FUNCTION ulong CreatePen(ulong nPenStyle,ulong nWidth,ulong crColor)   LIBRARY "gdi32.dll"
      Function long ReleaseDC( long hWnd, long hDC ) Library "user32"
      Function boolean TextOut (ulong hdcr, integer stx, integer sty, ref string lpString, long nCount) Library "GDI32.DLL" Alias for "TextOutA"
      Function int SetBkMode (ulong hdcr, integer mode) Library "GDI32.DLL"
    3 声明实例变量
      string SbuttonName    //保存按钮名称
    4 声明自定义事件:(同一)
      另外必须声明一个用于画图的u_paint事件,对应的PB事件ID是pbm_paint.
    5 声明结构us_point如下:
      x long
      y long
    6 在contructor事件中编写如下脚本
      //按钮形状
      (同一)
      SButtonName=this.text
      this.postevent("u_paint")
      this.text=""
    7 在u_paint事件中有如下的程序:
      ulong l_handle, l_device,uPen,uOldPen
      long lwidth,lheight,lColor
      integer iFor
      us_point previouspos

      l_device = GetDC(handle(this))
      lwidth=UnitsToPixels(this.width,XUnitsToPixels!)
      lheight=UnitsToPixels(this.height,yUnitsToPixels!)
      for iFor=0 to lheight
          lColor=rgb(iFor*100/lheight+150,iFor*100/lheight+150,iFor*100/lheight+150)
          uPen=createpen(0,1,lColor) 
          uOldPen=selectobject(l_device,uPen)
          MoveToEx(l_device,0,iFor,previouspos)
          LineTo(l_device,lwidth,iFor)

          selectobject(l_device,uOldPen)
          deleteobject(uPen)
          //写上按钮名称,字符输出的背景为透明
          SetBkMode (l_device, 1)
          SetTextColor (l_device, RGB( 0,0,255 ))
          TextOut (l_device, 12, 3, SButtonName, len( SButtonName ))
      next
      ReleaseDC( handle(this), l_device )
    8 这里在mouseover和mousedown、mouseup上为了节省篇幅,没有程序,你可以按照你的想法写上你的程序。
    具体应用:使用时只要在窗口设计中选择User Object 然后点选u_vo_stbutton将它放置到窗口,在name栏上写上按钮名称即可。
    以上给出了在PB应用程序中的按钮设计方法,我认为最为理想的是第四种,在绘制按钮时可以在上面绘制图标,PB中的图标是很丰富的,这样按钮既美观大方,又很省事.