当前位置:首页>>软件教程>>聊天软件>>新闻内容
技巧:自动隐藏QQ窗体
作者:佚名 发布时间:2005-4-19 10:43:46 文章来源:CSDN

    四、进一步完善

上面的代码已经基本实现了窗体的自动隐藏效果,但是我在介绍代码的时候有两个问题是被提出但没有被解答的。

  首先是为什么触发隐藏时Fanchors中将至少有一个值而不多于两个值呢?注意代码中对Fanchors的赋值是通过四个判断进行的,那么如果触发隐藏的话,Fanchors中将毫无疑问会有一个值存在,但这种情况是针对隐藏发生在屏幕的四边而言。当窗体被推入到屏幕的四角时,那么Fanchors中便将会有两个值存在。那此时窗体会隐藏到什么地方呢?

  实际的效果告诉我们,窗体会被隐藏到屏幕的四角上。此时若我们试图让窗体重新显示,你便会发现窗体在不断的闪烁。为什么呢?这就是第二个问题提出的原因了。因为对窗体显示或隐藏的处理是根据Fanchors中的值作出的。当Fanchors中有两个值的时候,就将会引发对窗体属性的两次设置。而因为设置语句只有顺序差异而没有优先级差异,那么OnTimer事件中每次都会对窗体进行两次的属性值设置,从而导致我们看到闪烁的显示效果。

  怎么去解决这个问题呢?我们再观察一下QQ的处理。在2003 II版的QQ里面,窗体的隐藏效果作了一定的调整:当窗体在屏幕左右两边隐藏时,它会自动充满屏幕的左右两边且高度不可改变;当窗体脱离屏幕两边的隐藏区域后,窗体的大小会恢复为隐藏前的大小。(注意:窗体并非是完全充满屏幕的两边。QQ在处理这个效果时可能只注意了系统工具栏总在最前显示且位于屏幕下方的情况,所以其充满的区域也只是屏幕顶端到系统工具栏上方的一段空间。)这样的处理可以令窗体即使被推入到屏幕四角,也可以保证只会对其中的一个隐藏方向进行处理,从而避免了前面出现的闪烁现象。

  结合前面的分析,要实现如上的效果还是从拦截WM_MOVING消息入手。重写后的WMMOVING过程如下:

procedure TForm1.WMMOVING(var Msg: TMessage);
begin 
 inherited; 
 with PRect(Msg.LParam)^ do
 begin 
   if (akLeft in FAnchors) or (akRight in FAnchors) then
   begin
     if (Left > 0) and (Right < Screen.Width) then
     begin
       if rec_Position then
       begin
         Bottom := top + Lst_Height;
         Right := Left + Lst_Width;
         Height := Lst_Height;
         Width := Lst_Width;
       end;
     end else
     begin
       SetBarHeight;
       Top := Cur_Top;
       Bottom := Cur_Bottom;
       exit;
     end;
   end;
   Left := Min(Max(0, Left), Screen.Width - Width);
……
   if not Rec_Position then
   begin
     Lst_Height := form1.Height;
     Lst_Width := form1.width;
   end;
   FAnchors := [];
……
   if (akLeft in FAnchors) or (akRight in FAnchors) then
   begin
     Rec_Position := True;
     SetBarHeight;
     Top := Cur_Top;
     Bottom := Cur_Bottom;
   end else
     Rec_Position := False;
   Timer1.Enabled := FAnchors <> []; 
  end;
end;

在新的代码中,我们首先使用了三个新定义的全局变量,分别是:

Lst_Height : Integer;   //记录窗体隐藏前的高度
Lst_Width : Integer;        //记录窗体隐藏前的宽度
Rec_Position : Boolean; //是否启动窗体宽高记录标志

  然后加入了三个判断代码块。

  在第一个判断中首先判定窗体在移动前是否位于屏幕左右两边的隐藏区域。若为真,则判断窗体是否从隐藏区域向屏幕中央移动(注意,存在此判断的原因是因为我们还可能将窗体往屏幕两边推动)。若再为真,则恢复窗体隐藏前的大小;反之,强制设置矩形的Top和Bottom值并退出消息的处理。

  第二个判断在于记录窗体的宽高值。Rec_Position是记录窗体宽高的标志,它的值在第三个判断中进行设置。若窗体在移动前位于屏幕两边的隐藏区域,则Rec_Position为True,此时窗体的高度已经固定,记录已经无意义。所以只在Rec_Position为False时才需要记录窗体的宽高。

  第三个判断位于Fanchors值设置之后。它根据窗体的位置对矩形的显示效果进行判断处理。判断也是基于窗体是否位于屏幕两边进行,为True则设置矩形的高度并设置Rec_Position的值为True。

  在第三个判断中使用了一个新定义的过程SetBarHeight,其代码如下:

procedure TForm1.SetBarHeight;
var
  AppBarData : TAPPBARDATA;
begin
  AppBarData.cbSize := SIZEOF(AppBarData);
  If SHAppBarMessage(ABM_GETSTATE,AppBarData) AND ABS_AUTOHIDE) <> 0 then
  begin
    Cur_Top := 1;
    Cur_Bottom := Screen.Height - 1;
  end else
  begin
    SHAppBarMessage(ABM_GETTASKBARPOS,AppBarData);
    case AppBarData.uEdge of
      ABE_TOP :    begin
                     Cur_Top := AppBarData.rc.Bottom + 1;
                     Cur_Bottom := Screen.Height - 1;
                   end;
      ABE_LEFT :   begin
                     Cur_Top := 1;
                     Cur_Bottom := Screen.Height - 1;
                   end;
      ABE_RIGHT :  begin
                     Cur_Top := 1;
                     Cur_Bottom := Screen.Height - 1;
                   end;
      ABE_BOTTOM : begin
                    Cur_Top := 1;
                     Cur_Bottom:=Screen.Height -(AppBarData.rc.Bottom - AppBarData.rc.Top) - 1;
                   end;
    end;
  end;
end;

  SetBarHeight用于计算矩形高度,计算后的结果通过Cur_Top和Cur_Bottom两个全局变量给传递矩形的Top和Bottom参数。

  在该过程中使用了一个Windows API函数SHAppBarMessage。SHAppBarMessage的作用是向系统传递系统工具栏消息,其函数原型为:

WINSHELLAPI UINT APIENTRY SHAppBarMessage(DWORD dwMessage,   PAPPBARDATA pData);

  其中dwMessage是发送给系统的工具栏消息;pData是指向PAPPBARDATA结构的指针,PAPPBARDATA结构返回的内容依据发出的消息而定。

  在过程中,我们首先传递ABM_GETSTATE参数去获取系统工具栏的状态是自动隐藏还是总在最前显示。然后我们再利用ABM_GETTASKBARPOS参数去获取系统工具栏的位置,此时AppBarData的返回值中将会是系统工具栏的位置ABE_TOP、ABE_LEFT、ABE_RIGHT、ABE_BOTTOM四者之一。最后我们利用系统工具栏自身的拖动矩形参数计算出工具栏的高度。

  使用了SetBarHeight令窗体在屏幕两边随系统工具栏的位置和高度的改动而发生相应的变化。当然,你也可以直接给Cur_Top和Cur_Bottom这两个变量设置固定值以实现QQ效果。在测试中,Cur_Top可以是1,而Cur_Bottom则是Screen.Width – 30(Windows系统工具栏的高度在默认情况下是30,这是不随分辨率改变的)。

  由于要使窗体在屏幕两边的高度与位置可以随系统工具栏的位置和高度的改动而发生相应的变化,因此OnTimer事件中的处理也要相应的改动,主要是显示窗体的时候要注意对窗体Top和Height属性的设置必须跟随与系统工具栏的位置和高度相协调,代码如下:

……
    if akLeft in FAnchors then
    begin
      Left := -Width + cOffset;
      SetBarHeight;
      Top := Cur_Top;
      Height := Cur_Bottom;
    end;
    if akRight in FAnchors then
    begin
      Left := Screen.Width - cOffset;
      SetBarHeight;
      Top := Cur_Top;
      Height := Cur_Bottom;
    end;
……

  最后,为了保证窗体在屏幕两边隐藏后高度保持不变,我们再添加一个WMSizing过程对WM_Sizing消息进行拦截处理。WMSizing过程的代码如下:

procedure TForm1.WMSizing(var Msg: TMessage);
begin
  inherited;
  if (akRight in FAnchors) then
  begin
    with PRect(Msg.LParam)^  do
    begin
      Left := Screen.Width - Width;
      Top := Cur_Top;
      Right := Screen.Width;
      Bottom := Cur_Bottom
    end;
  end else if (akLeft in FAnchors) then
  begin
    with PRect(Msg.LParam)^ do
    begin
      Left := 0;
      Top := Cur_Top;
      Right := Width;
      Bottom := Cur_Bottom;
    end;
  end;
end;

  WM_Sizing消息的语法结构与WM_MOVING消息相似,也包含了一个对矩形的指针。通过该指针我们可以对矩形的Top、Left、Right和Bottom参数进行设置,从而保证矩形高度不受用户操作影响。

  至此,一个窗体自动隐藏的程序就基本完成了,其实际效果已经和QQ相当接近了。当然,从实际运行效果看还存在着一些小瑕疵,并且代码中并没有对窗体在隐藏后的宽度设置上进行处理,或者大家可以考虑继续进行完善此程序。


[首页]    [上一页]    [下一页]    [末页]    
最新更新
·QQ被盗之后如何找回丢失的QQ
·用MSN9(Windows Live Messen
·Live Messenger(MSN)头像设置
·如何用QQ直接上传文件到QQ中
·实现同时打开多个Windows Li
·MSN登录出现0x81000370错误的
·解决重装MSN9的“run-time e
·手动去除阿里旺旺广告的方法
·修改几个字节实现QQ2009会员
·解决Windows Live Messenger
相关信息
·QQ被盗之后如何找回丢失的QQ好友?(已解决)
·如何用QQ直接上传文件到QQ中转站?
·实现同时打开多个Windows Live Messenger 2009
·手动去除阿里旺旺广告的方法
·修改几个字节实现QQ2009会员部分功能
·如何下载手机QQ2008?QQ2008支持WiFi
·手动去除QQ2009广告和插件的方法
·腾讯QQ最新漏洞:让你免费穿红钻QQ秀
·教你备份带分组的所有QQ好友名单
·让你的电脑只能登录你的QQ号码
画心
愚爱
偏爱
火苗
白狐
画沙
犯错
歌曲
传奇
稻香
小酒窝
狮子座
小情歌
全是爱
棉花糖
海豚音
我相信
甩葱歌
这叫爱
shero
走天涯
琉璃月
Nobody
我爱他
套马杆
爱是你我
最后一次
少女时代
灰色头像
断桥残雪
美了美了
狼的诱惑
我很快乐
星月神话
心痛2009
爱丫爱丫
半城烟沙
旗开得胜
郎的诱惑
爱情买卖
2010等你来
我叫小沈阳
i miss you
姑娘我爱你
我们都一样
其实很寂寞
我爱雨夜花
变心的玫瑰
犀利哥之歌
你是我的眼
你是我的OK绷
贝多芬的悲伤
哥只是个传说
丢了幸福的猪
找个人来爱我
要嫁就嫁灰太狼
如果这就是爱情
我们没有在一起
寂寞在唱什么歌
斯琴高丽的伤心
别在我离开之前离开
不是因为寂寞才想你
爱上你等于爱上了错
在心里从此永远有个你
一个人的寂寞两个人的错