作者:BALLOONMAN2002 2004年6月26日<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
本文擬結合POWERBUILDER語言,簡述如何實現類似QQ的自動顯示/隱藏窗口,即:鼠標移入時自動彈出窗口,鼠標移出後自動隱藏窗口,同時當隱藏窗口後實現WINDOWS操作系統啓動畫面時顯示的不同顏色條滾動效果以提示用戶。
本文擬分以下四部分論述分三次完成:
(一)基本思路
(二)基礎準備工作
(三)自動顯示/隱藏窗口功能實現
(四)顏色條滾動效果實現
一、基本思路
(一)利用API:TrackMouseEvent函數捕獲Wm_MouseLeave消息,來獲取並處理鼠標移出事件;利用WINDOW的MOUSEMOVE事件來處理鼠標移入事件。
(二)利用API:CreateSolidBrush、FillRect函數來動態創建顏色漸變區域,以實現不同顏色條滾動效果。
注:
(1)通過調用TrackMouseEvent函數能夠捕獲到WM_NCMOUSEHOVER、WM_NCMOUSELEAVE、WM_MOUSEHOVER、WM_MOUSEHOVER四類消息;
(2)同樣也可以捕獲WM_MOUSEHOVER消息來處理鼠標移入事件,本例爲簡單起見直接處理MOUSEMOVE事件;
二、基礎準備工作
1、新建一窗口,爲便於說明問題,本例將窗口的WINDOW TYPE屬性設置爲POPUP類型,同時將TITLE BAR屬性設置爲無,這樣可以減少鼠標進入非客戶區域時也觸發Wm_MouseLeave消息的影響;
2、聲明本地外部函數:
function integer TrackMouseEvent(ref str_Track_Mouse str_Trm) library 'user32.dll'
function integer GetCursorPos(ref str_Point lppoint) library 'user32.dll'
function integer GetWindowRect(long ll_hwnd,ref str_Rect lpRect) library 'user32.dll'
function ulong PtInRect(ref str_Rect lpRect,ulong Pt_x,ulong Pt_y) library "user32.dll"
subroutine Sleep(ulong dwMilliseconds) library "kernel32.dll"
function ulong GetClientRect(ulong hwnd,ref str_Rect lpRect) library "user32.dll"
function ulong ClientToScreen(ulong hwnd,ref str_Point lpPoint) library "user32.dll"
function ulong OffsetRect(ref str_Rect lpRect,ulong Pt_x,ulong Pt_y) library "user32.dll"
Function ulong ReleaseCapture() LIBRARY "user32.dll"
Function ulong SendMessage(ulong hwnd,ulong wMsg,ulong wParam,ref ulong lParam) LIBRARY "user32.dll" ALIAS FOR "SendMessageA"
Function ulong GetDC(ulong hwnd) LIBRARY "user32.dll"
Function ulong DeleteObject(ulong hObject) LIBRARY "gdi32.dll"
Function ulong CreateSolidBrush(ulong crColor) LIBRARY "gdi32.dll"
Function ulong ReleaseDC(ulong hwnd,ulong hdc) LIBRARY "user32.dll"
Function ulong FillRect(ulong hdc,ref str_rect lpRect,ulong hBrush) LIBRARY "user32.dll"
注:上述API聲明涉及到的結構請查閱MSDN或其他技術資料。
3、聲明實例變量(Instance Variables):
boolean ib_onform = false,ib_display = true,ib_first_display = true,ib_first_hide = true
constant integer wm_mouseleave = 675
constant integer WM_NCLBUTTONDOWN = 161
constant integer HTCAPTION = 2
三、自動顯示/隱藏窗口功能實現
1、處理該WINDOW的OTHER事件,藉助此事件來捕獲Wm_MouseLeave消息,來獲取並處理鼠標移出事件:
str_Rect ls_rect
str_Point ls_point,ls_tmp
//注:Wm_MouseLeave消息一旦離開窗口的CLIENT區域就會發送,如:當鼠標移至窗口上的控件時也會發送此消息,當鼠標移到窗口的CAPTION或者MENU或者BORDER時也會發送此消息,故不能不加任何判斷而直接隱藏窗口,並且此消息只發送一遍,若需繼續跟蹤鼠標,則需再次調用TRACKMOUSEEVENT函數;
if Message.number = Wm_MouseLeave then
ib_onform = false
GetCursorPos(ls_point)
GetClientRect(handle(this),ls_rect)
ls_tmp.x = ls_rect.left
ls_tmp.y = ls_rect.top
ClientToScreen(handle(this),ls_tmp)
OffsetRect(ls_rect,ls_tmp.x,ls_tmp.y)
//判斷鼠標如果超出客戶區,則自動隱藏窗口
//只能使用客戶區判斷,不能使用整個窗口RECT,否則當鼠標移至BORDER時可能會無法隱藏窗口
if (PtInRect(ls_rect,ls_point.x,ls_point.y) = 0) and ((this.x <= 0) or (this.y <= 0)) then
if this.y <= 0 then
wf_hide_v(this) //首先保證在V方向收縮滑動
else
wf_hide_h(this) //其次保證在H方向收縮滑動
end if
ib_display = false
end if
end if
2、處理該WINDOW的MOUSEMOVE事件來處理鼠標移入事件:
if ib_onform = false then
ib_onform = true
if ib_display = false then
if this.y <= 0 then
wf_display_v(this)
else
wf_display_h(this)
end if
ib_display = true
end if
wf_capmouse(this)
end if
3、創建該窗口的OPEN事件,以設置該窗口運行的初始位置:
this.backcolor = 16574393
this.title = "自動隱藏窗口示例___雙擊關閉窗口"
this.setposition(TopMost!)
this.width = p_1.width
this.height = p_1.height
this.x = 100
this.y = -this.height
wf_display_v(this)
4、創建相應的窗口函數wf_capmouse以調用鼠標消息捕獲函數:
str_Track_Mouse str_trm
str_trm.nSize = 16
str_trm.hwndTrack = handle(ag_dest)
str_trm.nFlags = 2
TrackMouseEvent(str_trm)
5、創建相應的窗口函數wf_display_h以設置窗口如何在水平方向滑動顯示:
integer li_left
str_Rect ls_rect1,ls_rect2
str_Point ls_tmp
GetWindowRect(handle(this),ls_rect1)
GetClientRect(handle(this),ls_rect2)
ls_tmp.x = ls_rect2.left
ls_tmp.y = ls_rect2.top
ClientToScreen(handle(this),ls_tmp)
OffsetRect(ls_rect2,ls_tmp.x,ls_tmp.y)
li_left = ls_rect2.left - ls_rect1.left //計算出窗口邊框寬度
//計算窗口邊框還可以用GetSystemMetrics+SM_CXBORDER/SM_CYBORDER/SM_CXFRAME/SM_CYFRAME,但是需要判斷窗口狀態是可變邊框還是不可變邊框還是無邊框,因此不如直接採用上述方法
do while as_win.x < -15
as_win.x = as_win.x + 10 //這裏的10主要用於控制窗口滑動速度
if ib_first_display then
p_1.draw(0,0) //這裏主要防止第一次滑動窗口時不顯示圖象
end if
sleep(0.01) //這裏的SLEEP函數主要用於控制窗口滑動速度
loop
as_win.x = -3*li_left //這裏值不能太小否則,鼠標移到左側時易出邊界
ib_first_display = false
注:用於設置窗口如何在垂直方向滑動顯示的wf_display_v函數不再贅述,修改as_win.y屬性即可。
6、創建相應的窗口函數wf_display_h以設置窗口如何在水平方向滑動隱藏:
do while as_win.x > -as_win.width + 25
as_win.x = as_win.x - 10
if ib_first_hide then
p_1.draw(0,0) //這裏主要防止第一次隱藏窗口時不顯示圖象
end if
sleep(0.005)
loop
as_win.x = -as_win.width + 10 //這裏的10用於控制最後窗口隱藏後留在外側的邊距
ib_first_hide = false
注:用於設置窗口如何在垂直方向滑動顯示的wf_display_v函數不再贅述,修改as_win.y屬性即可。
7、由於該窗口爲NO TITLEBAR窗口,因此無法拖動,需要專門編寫腳本來實現拖動效果,方法爲處理窗口的MOUSEDOWN事件:
ulong ll_arg
ReleaseCapture() //釋放對MOUSE消息的捕獲,故在拖動期間不會發生WM_MOUSELEAVE事件
ll_arg = 0
SendMessage(handle(this),WM_NCLBUTTONDOWN,HTCAPTION,ll_arg)
//即發送WM_NCLBUTTONDOWN消息,模擬用戶拖動TITLEBAR效果
四、顏色條滾動效果實現
1、獲取該窗口的HDC(設備句柄),即在窗口的OPEN事件當中編寫:
聲明全局變量:long gl_hdc
聲明外部函數:Function ulong GetDC(ulong hwnd) LIBRARY "user32.dll"
gl_hdc = getdc(handle(this))
2、創建一個TIMING類型用戶對象USER OBJECT,用於動態繪製彩色矩形:
(1)首先聲明該對象實例變量:
integer ii_turn
str_rect is_rect_all,is_rect_form
long il_hbrush,il_target_height,il_target_width,il_target_pace,il_height_base
(2)初始化該用戶對象,編寫其CONSTRUCTOR事件:
ii_turn = 1
il_target_width = UnitsToPixels(w_function.width , XUnitsToPixels!)
//設置整個目標區域的寬度
il_target_height = UnitsToPixels(w_function.height , YUnitsToPixels!)
//設置整個目標區域的高度
il_target_pace = 15 //設置彩色顏色條滾動步距
il_height_base = 100 //設置彩色顏色條寬度
is_rect_all.left = il_target_width - UnitsToPixels(30 , XUnitsToPixels!)
is_rect_all.right = il_target_width
is_rect_form.top = 0
is_rect_form.bottom = il_target_height
is_rect_form.left = is_rect_all.left
is_rect_form.right = is_rect_all.right
il_hbrush = CreateSolidBrush(gl_backcolor)
(3)開始具體編寫動態顏色條滾動效果代碼,即處理該對象的TIMER事件:
str_rect ls_rect_tmp
long ll_tmp,ll_ret,ll_hbrush
integer li_red,li_green,li_blue
if ii_turn = 1 then
if is_rect_all.top < il_target_height - il_height_base - il_target_pace then
is_rect_all.top = is_rect_all.top + il_target_pace
else
is_rect_all.top = il_target_height - il_height_base
ii_turn = -1
end if
else
if is_rect_all.top > il_target_pace then
is_rect_all.top = is_rect_all.top - il_target_pace
else
is_rect_all.top = 0
ii_turn = 1
end if
end if
is_rect_all.bottom = is_rect_all.top + il_height_base
//w_function.backcolor = gl_backcolor
ll_ret = FillRect(gl_hdc, is_rect_form, il_hbrush) //注:這樣比上面一句效率高
li_red = mod(gl_backcolor,256)
li_green = Truncate(mod((gl_backcolor - li_red),65536) / 256 , 0)
li_blue = Truncate(gl_backcolor / 65536 , 0)
ls_rect_tmp.left = is_rect_all.left
ls_rect_tmp.right = is_rect_all.right
if ii_turn = 1 then
ls_rect_tmp.bottom = is_rect_all.top
do while ls_rect_tmp.bottom < is_rect_all.bottom
li_red = li_red - 20 //注:這裏的20決定了顏色的深淺程度 li_green = li_green - 20
li_blue = li_blue - 20
if li_red < 0 then
li_red = 0
end if
if li_green < 0 then
li_green = 0
end if
if li_blue < 0 then
li_blue = 0
end if
ll_hbrush = CreateSolidBrush(rgb(li_red,li_green,li_blue))
ls_rect_tmp.top = ls_rect_tmp.bottom
ls_rect_tmp.bottom = ls_rect_tmp.top + 25 //注:這裏的25決定了漸變的快慢程度
ll_ret = FillRect(gl_hdc, ls_rect_tmp, ll_hbrush)
ll_ret = Deleteobject(ll_hbrush)
loop
else
ls_rect_tmp.top = is_rect_all.bottom
do while ls_rect_tmp.top > is_rect_all.top
li_red = li_red - 20
li_green = li_green - 20
li_blue = li_blue - 20
if li_red < 0 then
li_red = 0
end if
if li_green < 0 then
li_green = 0
end if
if li_blue < 0 then
li_blue = 0
end if
ll_hbrush = CreateSolidBrush(rgb(li_red,li_green,li_blue))
ls_rect_tmp.bottom = ls_rect_tmp.top
ls_rect_tmp.top = ls_rect_tmp.bottom - 25
ll_ret = FillRect(gl_hdc, ls_rect_tmp, ll_hbrush)
ll_ret = Deleteobject(ll_hbrush)
loop
end if
3、在主WINDOW窗口中調用此TIMING對象:
(1)處理OPEN事件:iuo_timer = create uo_timer
(2)處理wf_hide_h/v事件:iuo_timer.start(0.2)
(3)處理CLOSE事件:destroy iuo_timer
至此,仿QQ自動顯示/隱藏加顏色條滾動效果窗口全部完成。
由於我自己是分在兩個程序當中實現上述兩種效果,故無法給出完整的示意圖,僅以如下兩圖示例:
http://blog.csdn.net/images/blog_csdn_net/balloonman2002/17312/r_AUTOHIDE.JPG
http://blog.csdn.net/images/blog_csdn_net/balloonman2002/17312/r_SCROLL_EFF.JPG
如需要進一步資料,請聯繫QQ:27855043,MSN:[email protected]
如有不當之處,敬盼您的指點。