作者:BALLOONMAN2002 2004年6月26日<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
本文拟结合POWERBUILDER语言,简述如何实现树型列表动态半透明提示,即鼠标移动到树型列表某一项ITEM时会动态提示,且为类似金山词霸的半透明提示效果。
效果图见:
http://blog.csdn.net/images/blog_csdn_net/balloonman2002/17312/r_BALLOON-1.JPG
本文拟分以下四部分论述分三次完成:
(一)基本思路
(二)如何获取当前鼠标坐标对应NODE结点信息
(三)半透明效果实现
(四)气泡形状效果实现
一、基本思路
(一)在POWERBUILDER语言中,TREEVIEW控件并不具备如VB等其他语言一样当鼠标未选中NODE时,直接获取当前鼠标对应X、Y坐标下所属NODE结点的方法,VB中可以直接利用HITTEST方法来获取对当前鼠标坐标对应的NODE结点。但可以通过调用API:SENDMESSAGE函数来向TREEVIEW控件发送一个TVM_HITTEST消息来间接实现上述效果。
(二)在POWERBUILDER语言中,并没有直接让控件实现半透明的方法,而目前WINDOWS2000/XP操作系统提供了一个API函数:SetLayeredWindowAttributes,但该API函数不支持WINDOWS98操作系统,考虑到系统的全面兼容性,必须同时考虑WINDOWS98下面应该如何实现半透明提示效果。因此我们必须放弃采用上述API,而采用模拟半透明的方式,即:处理WINDOW的MOUSEMOVE事件,当鼠标移动到某一位置后将鼠标附近区域用API函数BitBlt、AlphaBlend截图下来,并拷贝到气泡提示控件背景设备即可模拟实现半透明效果。
(三)如何实现微软的气泡形状控件?由于POWERBUILDER对一些控件支持并不好,而且此类控件难以寻找,我们就考虑自己动手编写。主要借助API函数:CreateRectRgn、CreateRoundRectRgn、CreatePolygonRgn、CombineRgn等。
二、如何获取当前鼠标坐标对应NODE结点信息
1、新建一窗口,内含一TREEVIEW控件;
2、声明本地外部函数:
Function ulong SendMessage1(ulong hwnd,ulong wMsg,ulong wParam,ref TVHITTESTINFO lParam) LIBRARY "user32.dll" ALIAS FOR "SendMessageA"
Function ulong SendMessage2(ulong hwnd,ulong wMsg,ulong wParam,ref TVITEM lParam) LIBRARY "user32.dll" ALIAS FOR "SendMessageA"
SUBROUTINE CopyMemory (ref string Destination , long Source, long Length) LIBRARY "kernel32" Alias for "RtlMoveMemory"
Function ulong GlobalFree(ulong hMem) LIBRARY "kernel32.dll"
Function ulong GlobalAlloc(ulong wFlags,ulong dwBytes) LIBRARY "kernel32.dll"注:上述API声明涉及到的结构请查阅MSDN或其他技术资料。
3、对于该TREEVIEW控件自定义用户事件UE_MOUSEMOVE(PBM_MOUSEMOVE),在此事件当中处理鼠标移动事件,发送TVM_HITTEST消息:
tpoint ptA
tvhittestinfo tf
TVITEM tv
ulong hItem,ll_1,ll_2,ll_3,hStr
long ret,ll_x,ll_y
string astr,bstr,ls_help
ptA.x = UnitsToPixels(xpos, XUnitsToPixels!)
ptA.y = UnitsToPixels(ypos, YUnitsToPixels!)
tf.pt = ptA
tf.flags = 4
hItem = SendMessage1(handle(tv_1),4369,0,tf)
//注:上述4369为TVM_HITTEST
//通过发送TVM_HITTEST消息来获取当前对应的NODE的句柄,,将当前NODE结点信息保存到结构变量 TF当中
If ((hItem <= 0) Or (hItem = hItemPrv)) Then return
hItemPrv = hItem
hStr = GlobalAlloc(0,1024)
If hStr > 0 Then
tv.mask = 1
tv.HTreeItem = hItem
tv.pszText = hStr
tv.cchTextMax = 1023
ret = SendMessage2(handle(tv_1), 4364, 0, tv)
//注:上述4364为TVM_GETITEM
//通过对当前NODE发送TVM_GETITEM消息,将当前NODE结点信息保存到结构变量 TV当中
astr = space(1024)
//注:此处一定要分配足够空间,否则易非法操作
CopyMemory(astr, hStr, 1024)
//bstr = Left(astr, (pos(astr, Char(0)) - 1))
ret = GlobalFree(hStr)
ids_ds.setfilter("")
ids_ds.filter()
ret = ids_ds.find("name_gn = '" + astr + "'",1,ids_ds.rowcount())
if ret > 0 then
ls_help = ids_ds.getitemstring(ret,"help")
if (isnull(ls_help) or trim(ls_help) = "") then
timer(0)
iuo_tips.hide()
else
if is_help = ls_help then
return
end if
iuo_tips.hide()
iuo_tips.uf_set_text(ls_help,astr)
ib_tipshow = false
Timer(1)
end if
is_help = ls_help
else
timer(0)
iuo_tips.hide()
end if
else
timer(0)
iuo_tips.hide()
end if
三、半透明效果实现
1、创建一个可视USER OBJECT对象,并在主窗口中创建该UO的实例变量。
2、声明本地外部函数:
Function ulong GetDC(ulong hwnd) LIBRARY "user32.dll"
Function ulong BitBlt(ulong hDestDC,ulong x,ulong y,ulong nWidth,ulong nHeight,ulong hSrcDC,ulong xSrc,ulong ySrc,ulong dwRop) LIBRARY "gdi32.dll"
Function ulong ReleaseDC(ulong hwnd,ulong hdc) LIBRARY "user32.dll"
Function ulong CreateCompatibleDC(ulong hdc) LIBRARY "gdi32.dll"
Function ulong CreateCompatibleBitmap(ulong hdc,ulong nWidth,ulong nHeight) LIBRARY "gdi32.dll"
SUBROUTINE Sleep(ulong dwMilliseconds) LIBRARY "kernel32.dll"
Function ulong SelectObject(ulong hdc,ulong hObject) LIBRARY "gdi32.dll"
Function ulong AlphaBlend(long hDestDC , long X, long Y , long nWidth , long nHeight, long hSrcDC,long xSrc,long ySrc, long WidthSrc, long HeightSrc ,long dreamAKA ) LIBRARY "msimg32"
Function ulong DeleteDC(ulong hdc) LIBRARY "gdi32.dll"
Function ulong GetSystemMetrics(ulong nIndex) LIBRARY "user32.dll"
SUBROUTINE CopyMemory2 (ref long Destination , blendfunction Source, long Length) LIBRARY "kernel32" Alias for "RtlMoveMemory"
Function ulong DeleteObject(ulong hObject) LIBRARY "gdi32.dll"
3、处理主窗口的TIMER事件,用于定期触发提示信息:
long ll_x,ll_y
if ii_tip > 0 then
if ib_tipshow then
ib_tipshow = false
iuo_tips.hide()
timer(0)
else
ib_tipshow = true
ll_x = w_main.pointerx() + 50
ll_y = w_main.pointery() - iuo_tips.height - 5
if ll_y < 2 then
ll_y = 2
end if
//wf_maketrans(iuo_tips,iuo_tips.mle_1,il_x,il_y,50)
wf_maketrans(iuo_tips,iuo_tips.mle_1,ll_x,ll_y,40)
//上述函数是用于实现半透明效果的函数
timer(6)
end if
end if
4、创建用户函数wf_maketrans,用于实现半透明效果:
Long hDCscr,bhandle,hdest,frmdc,BlendLng,copywidth,copyheight,copyleft,copytop,ret
long copywidth2,copyheight2,copyleft2,copytop2,mledc
Long xDeviation,yDeviation
blendfunction Blend
Window lw_tmp
//BlendLng = 11796480
Blend.SourceConstantAlpha = char(trans)
CopyMemory2(BlendLng, Blend, 4)
lw_tmp=frm.getparent()
//lw_tmp.setredraw(true)
copywidth = UnitsToPixels(frm.Width, XUnitsToPixels!)
copyheight = UnitsToPixels(frm.Height, YUnitsToPixels!)
copywidth2 = UnitsToPixels(mle.Width, XUnitsToPixels!)
copyheight2 = UnitsToPixels(mle.Height, YUnitsToPixels!)
//上述代码用于坐标体系转换
frm.x = xpos
frm.y = ypos
If lw_tmp.Border <> false Then
yDeviation = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME)
xDeviation = GetSystemMetrics(SM_CXFRAME)
Else
yDeviation = 0
xDeviation = 0
End If
if trim(lw_tmp.menuname) <> "" then
yDeviation = yDeviation + GetSystemMetrics(SM_CYMENU)
end if
//也可以用CLIENTTOSCREEN进行转换
copyleft = UnitsToPixels((lw_tmp.x + xpos), XUnitsToPixels!) + xDeviation
copytop = UnitsToPixels((lw_tmp.y + ypos), YUnitsToPixels!) + yDeviation
copyleft2 = UnitsToPixels(mle.x, XUnitsToPixels!)
copytop2 = UnitsToPixels(mle.y, YUnitsToPixels!)
//上述代码用于坐标体系转换
hDCscr = GetDC(0)
//获取屏幕的设备句柄
hdest = CreateCompatibleDC(hDCscr)
bhandle = CreateCompatibleBitmap(hDCscr, copywidth, copyheight)
ret = SelectObject(hdest,bhandle)
frmdc = getdc(handle(frm))
mledc = getdc(handle(mle))
//此句可加可不加,主要是起清除原来图象目的,防止图象重叠,VB中此处必须要.cls,因为它具有AUTOREDRAW能力
//frm.setredraw(true)
//mle.setredraw(true)
//'此处一定要等待一段时间,否则窗体来不及hide,就已经被重新抓屏了
Sleep(100)
ret = BitBlt(hdest, 0, 0, copywidth, copyheight, hDCscr, copyleft , copytop , 13369376)
//上述代码即将屏幕的截图拷贝到内存缓存区域
//VB中FORM具有AUTOREDRAW的属性可以自动重画,PB无此能力,只好在此处就得显示出来
if ib_first then
wf_setrgn(frm)
end if
frm.Visible = True
if ib_first then
wf_setrgn(frm)
ib_first = false
end if
ret = AlphaBlend(frmdc, 0, 0, copywidth, copyheight, hdest, 0, 0, copywidth, copyheight, BlendLng)
ret = AlphaBlend(mledc, 0, 0, copywidth2, copyheight2, hdest, copyleft2 , copytop2, copywidth2, copyheight2, BlendLng)
//上述代码将内存缓存区域中的截图拷贝到气泡UO和其上的MLE_1控件的HDC
//setnewrgn frm
wf_setrgn(frm)
ret = ReleaseDC(0, hDCscr)
ret = ReleaseDC(handle(frm), frmdc)
ret = ReleaseDC(handle(mle), mledc)
ret = DeleteDC(hdest)
ret = DeleteObject(bhandle)
//最后释放或删除获取的内存对象
四、气泡形状效果实现
1、声明本地外部函数:
Function ulong CreateRectRgn(ulong X1,ulong Y1,ulong X2,ulong Y2) LIBRARY "gdi32.dll"
Function ulong CreateRoundRectRgn(ulong X1,ulong Y1,ulong X2,ulong Y2,ulong X3,ulong Y3) LIBRARY "gdi32.dll"
Function ulong CreatePolygonRgn(ref POINTAPI lpPoint[],ulong nCount,ulong nPolyFillMode) LIBRARY "gdi32.dll"
Function ulong CombineRgn(ulong hDestRgn,ulong hSrcRgn1,ulong hSrcRgn2,ulong nCombineMode) LIBRARY "gdi32.dll"
Function ulong CreateSolidBrush(ulong crColor) LIBRARY "gdi32.dll"
Function ulong FrameRgn(ulong hdc,ulong hRgn,ulong hBrush,ulong nWidth,ulong nHeight) LIBRARY "gdi32.dll"
Function ulong SetWindowRgn(ulong hWnd,ulong hRgn,boolean bRedraw) LIBRARY "user32.dll"
2、创建用户函数wf_setrgn,用于创建气泡形状控件,该函数在上一小节的用户函数wf_maketrans中予以调用:
long rgn_1,rgn_2,myrgn,hhbr,w,h,ret
POINTAPI shapev[]
//初始化长、宽边距
w = UnitsToPixels(frm.Width, XUnitsToPixels!)
h = UnitsToPixels(frm.Height, YUnitsToPixels!)
//初始化右下脚三角顶点坐标
shapev[1].X = w * (1 / 8)
shapev[1].Y = h - 30
shapev[2].X = 0
shapev[2].Y = h
shapev[3].X = w * (3 / 8)
shapev[3].Y = h - 30
//开始创建指定图形区域
myrgn = CreateRectRgn(0, 0, 0, 0)
rgn_1 = CreateRoundRectRgn(0, 0, w, h - 20, 20, 20)
//创建椭圆角矩形区域
rgn_2 = CreatePolygonRgn(shapev[],3,1)
//创建任意多边形区域
//合并最终图形
ret = CombineRgn(myrgn, rgn_1, rgn_2, 2)
// 创建用户自定义颜色刷子
hhbr = CreateSolidBrush(16479614)
//对最终图形画边框
ret = FrameRgn(getdc(handle(frm)), myrgn, hhbr, 1, 1)
//设置当前窗体使用此区域
ret = SetWindowRgn(handle(frm), myrgn, True)
//释放各对象
ret = DeleteObject(myrgn)
ret = DeleteObject(rgn_1)
ret = DeleteObject(rgn_2)
ret = DeleteObject(hhbr)
2、利用上述代码可以轻松实现任务栏右下脚提示效果,如图:
http://blog.csdn.net/images/blog_csdn_net/balloonman2002/17312/r_BALLOON-2.JPG
至此,树型列表动态半透明效果提示全部完成,效果图见:
http://blog.csdn.net/images/blog_csdn_net/balloonman2002/17312/r_BALLOON-1.JPG
如需要进一步资料,请联系QQ:27855043,MSN:WEIYIN2001@MSN.COM
如有不当之处,敬盼您的指点。