淺談如何利用PB實現仿QQ自動顯示/隱藏窗口(原創)

作者: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]

如有不當之處,敬盼您的指點。

發佈了32 篇原創文章 · 獲贊 1 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章