PowerBuilder中图形按钮的制作
章 元
由于PB图形按钮存在种种缺陷,我们不得不对其进行扩充。本文提出并实现了在PB中制作图形按钮的方法,这种图形按钮除了具有普通按钮的功能外,还具有显示提示信息(Tip)、按钮局部区域显示图形、动态改变按钮上的图形等功能。
1.图形按钮的制作
创建一个定制的(custom)可视用户对象,在其中放置一个按钮控件和一个图片控件(p—1),并且将图片控件放在按钮控件一侧,将此用户对象保存为uo_picbutton。
在此对象中声明两个实例变量:
uo—tooltip ToolTip
//显示提示信息的用户对象实例
Boolean capturemouse=false //捕获鼠标的标志,捕获时为true、释放时为false
在Local External Functions…中加入两个API函数声明:
Function ulong SetCapture(ulong hWnd) Library "USER32.DLL"//捕获鼠标
Function BOOLEAN ReleaseCapture() Library "USER32.DLL"//释放鼠标
在此用户对象的事件中加入mousedown事件、mouseup事件和clicked事件。
在constructor事件中写入如下代码:
cb—1.x=0
cb—1.y= 0
cb—1.width=This.width
cb—1.height=This.height
p—1.x=This.width / 14
p—1.y=This.height / 6
ToolTip.ControlRegister(cb—1,This.tag,0)
//按钮控件显示提示信息所用
ToolTip.ControlRegister(p—1,This.tag,0)
//图片控件显示提示信息所用
If This.Enabled=False then
cb—1.Enabled=False
p—1.Enabled=False
End if
在按钮控件事件中加入mousedown事件、mouseup事件和mousemove事件。
在mousedown事件中写入如下代码:
parent.postevent (′mousedown′)
//执行父窗口(用户对象)中的mousedown事件
在mouseup事件中写入如下代码:
parent.postevent (′mouseup′)
//执行父窗口(用户对象)中的mouseup事件
在clicked事件中写入如下代码:
parent.postevent (′clicked′)
在mousemove事件中写入如下代码:
if xpos〉p—1.x and xpos〈(p—1.x+p—1.width) and ypos〉p—1.y and ypos〈(p—1.y+p—1.height) then //当鼠标在图片控件内部时,显示指定的提示信息
ToolTip.Showtip(p—1)
//图片控件显示提示信息所用,后面解释
elseif xpos 〉 cb—1.x and xpos〈(cb—1.x+cb—1.width) and ypos〉cb—1.y and ypos〈(cb—1.y+cb—1.height) then
ToolTip.Showtip(cb—1)
//按钮控件显示提示信息所用
end if
if xpos〈p—1.x or xpos〉(p—1.x+p—1.width) or ypos〈p—1.y and ypos〉(p—1.y+p—1.height) then //当鼠标离开图片控件时
if capturemouse=true then
//当捕获鼠标标志为true时
ReleaseCapture()
//调用API函数释放鼠标捕获
capturemouse=false
//设置捕获鼠标标志为false
end if
end if
在图片控件事件中加入mousemove事件并在mousemove事件中写入如下代码:
capturemouse=true
SetCapture(handle(cb—1))
//当鼠标移入图片控件时,调用API函数捕获鼠标,并指定到按钮
2.给图形按钮加上提示信息
创建一个定制的(custom)非可视用户对象uo—tooltip,声明实例变量如下:
Private:
CONSTANT string TOOLTIPS—CLASS=′tooltips—class32′
CONSTANT ulong CW—USEDEFAULT=2147483648
CONSTANT long WM—USER=1024
CONSTANT long WS_EX—TOPMOST=8
CONSTANT long TTM—ADDTOOL=WM—USER +4
CONSTANT long TTM—RELAYEVENT=WM—USER+7
Public:
long hWndTT
long ToolID=1
CONSTANT integer TTF—CENTERTIP=2
CONSTANT integer TTF—RTLREADING=4
在“Local External Functions…”中加入几个API函数声明:
//确保动态链接库(DLL)被加载
SubRoutine InitCommonControls() library "comctl32.dll"
//创建窗口
Function long CreateWindowExA(ulong dwExStyle, string ClassName, long WindowName, ulong dwStyle, ulong X, ulong Y, ulong nWidth, ulong nHeight, ulong hWndParent, ulong hMenu, ulong hInstance, ulong lpParam) library "user32.dll"
//清除指定的窗口以及它的所有子窗口
Function integer DestroyWindow(long hWnd) library "user32.dll"
//调用一个窗口的窗口函数,将一条消息发给窗口
Function integer ToolTipMsg(long hWnd, long uMsg, long wParam, REF TOOLINFO ToolInfo) library "user32.dll" Alias For "SendMessageA"
Function integer RelayMsg(long hWnd, long uMsg, long wParam, REF MSG Msg) library "user32.dll" Alias For "SendMessageA"
//分配指定数量的内存
Function long LocalAlloc(long Flags, long Bytes) library "kernel32.dll"
//释放内存并使句柄无效
Function long LocalFree(long MemHandle) library "kernel32.dll"
//复制字符串到缓冲区
Function long lstrcpy(long Destination, string Source) library "kernel32.dll"
在constructor事件中写入如下代码:
InitCommonControls()
HWndTT=CreateWindowExA ( WS—EX—TOPMOST, TOOLTIPS—CLASS, 0, TTF—CENTERTIP, CW—USEDEFAULT, CW—USEDEFAULT, CW—USEDEFAULT, CW—USEDEFAULT, 0, 0, Handle ( GetApplication ( ) ), 0 )
在destructor事件中写入如下代码:
DestroyWindow(hWndTT)
创建两个用户对象级函数(User Object Functions…):
controlregister(dragobject controlobject, string tip, integer flag)return integer
TOOLINFO ToolInfo
ToolInfo.cbSize=40
ToolInfo.uFlags=Flag
ToolInfo.hWnd=Handle(ControlObject)
ToolInfo.hInstance=0
ToolInfo.uID=ToolID
ToolID++
ToolInfo.lpszText=LocalAlloc(0,80)
POST LocalFree(ToolInfo.lpszText)
lStrCpy(ToolInfo.lpszText,Left(tip,80))
ToolInfo.Rect.Left=0
ToolInfo.Rect.Top=0
ToolInfo.Rect.Right=UnitsToPixels(ControlObject.Width,XUnitsToPixels!)
ToolInfo.Rect.Bottom=UnitsToPixels(ControlObject.Height,YUnitsToPixels!)
If ToolTipMsg(hWndTT,TTM—ADDTOOL, 0, ToolInfo)=0 Then
MessageBox("Error","Cannot register object in the toolwindow control! " , StopSign!, Ok! )
Return(-1)
End If
Return(ToolID _ 1)
showtip(dragobject controlobject)
MSG Msg
Msg.hWnd=Handle(ControlObject)
Msg.Message=512
Msg.WParam=Message.WordParm
Msg.Lparam=Message.LongParm
RelayMsg(hWndTT,TTM_RELAYEVENT,0,Msg)
3.在窗口中使用图形按钮控件
新建一个窗口,在窗口中放置图形按钮用户对象(name=uo—1),并在constructor事件中写如下代码:
this.cb—1.text=′ 测 试(&&T)′
留几个空格是为了不让位图遮住按钮上的文字。
在mousedown事件中写如下代码:
this.p—1.picturename=按钮按下时显示的图片路径及名字
在mouseup事件中写入如下代码:
this.p_1.picturename=按钮弹起时显示的图片路径及名字
在clicked事件中写入如下代码:
messagebox(′测试′,′这是一个图形按钮')

图1
运行该程序后可显示如图1的图形按钮,且按钮还具有显示提示信息的功能。