CSDN博客

img balloonman2002

浅谈如何利用PB实现仿QQ自动显示/隐藏窗口(原创)

发表于2004/6/25 21:48:00  4237人阅读

分类: PowerBuilder专题

作者:BALLOONMAN2002  2004年6月26日

本文拟结合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:WEIYIN2001@MSN.COM

如有不当之处,敬盼您的指点。

0 0

相关博文

我的热门文章

img
取 消
img