程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi下實現QQ窗體自動隱藏探索簡介

Delphi下實現QQ窗體自動隱藏探索簡介

編輯:Delphi

騰訊QQ是當前流行的網絡聊天工具之一,由於它在應用設計上有很多獨特之處,所以也吸引了很多程序員對之進行研究和模仿。在這裡,我將利用Delphi對QQ的窗體自動隱藏效果提出自己的實現方法。

一、問題的提出

熟悉QQ使用的朋友都知道,當QQ窗體區域超出屏幕四邊時,窗體就會自動“消失”,只留下窗體一邊的小部分顯露在桌面上。當用鼠標移動到顯露部分之上,窗體就會在隱藏位置重新完整顯示;但當鼠標離開窗體區域後,窗體便會重新進入隱藏狀態。

對隱藏的全過程進行分析,可以得出兩點推測:第一,窗體隱藏的處理是與窗體移動過程有關;第二,窗體隱藏的觸發條件。

對第一點推測,可以通過對窗體移動時產生的Windows消息進行攔截處理加以實現。對第二點推測,如何去表示“窗體區域已經超出屏幕可視范圍”這一條件為實現的關鍵。

二、基本的分析

讓我們先留意一下Windows環境下窗體移動的過程與效果。當使用鼠標移動窗體的時候,窗體本身並沒有立刻隨鼠標的移動而發生位置的改變;相反,鼠標正在拖動的是一個大小與窗體一致的透明區域(確切的說一個虛線邊框的矩形)。當鼠標釋放矩形後,窗體本身才會在矩形最後停留的地方出現,從而完成整個移動的過程。(注意:在Windows 2000及XP環境下,如果在顯示屬性中選中“拖動時顯示窗體內容”的顯示效果選項,則上述過程無法觀察。)

對QQ窗體,其移動過程與上述無異,但卻有一處不同。當我們把矩形移動到屏幕四邊且已有部分超出時,矩形就會自動地停留在超出位置上並完整顯示。此時不論我們怎樣試圖把矩形再向超出方向上移動,矩形也只保持在該位置。當釋放鼠標之後,窗體的隱藏效果也就出現了。

從上述過程可以推斷,觸發隱藏條件後,即使仍處於移動過程但矩形本身卻已經被鎖定,因此對窗體位置的判斷是發生在移動過程中,也就是說我們要攔截處理的Windows消息是WM_MOVING。其次,在移動過程中首先發生位置變化的是矩形而不是窗體本身,因此實現隱藏的關鍵是對矩形參數的判斷與設置。

我們可以先留意一下WM_MOVING消息的語法結構:

WM_MOVING

WPARAM wParam

LPARAM lParam,

其中,WPARAM不被使用,而LPARAM則是一個指針,所指向的是一個RECT結構。RECT結構中包含了Left、Top、Right、Bottom四個參數,分別用於描述矩形的左上角與右下角,“該RECT記錄了窗體相對於屏幕的當前位置;當要改變拖動矩形的位置時,程序本身必須改變RECT結構中各成員變量的相關值”。由此可知,我們要處理的矩形其實已經在WM_MOVING消息中被提到,我們要處理的也就是LPARAM所指向的RECT結構的有關參數。

接下來我們要設置一個由隱藏條件激活的計時器,目的是監控鼠標相對窗體的位置。因為窗體隱藏後的隱現是靠鼠標激活的,所以若檢測到鼠標位於窗體之上,則說明窗體在顯示狀態;反之,窗體在隱藏狀態。我們只需在相關的判斷下加入對窗體Top和Left屬性的賦值即可實現隱現效果。

至此,有關自動隱藏效果的實現分析就基本完成了。不過還要注意一點,因為我們是在WM_MOVING消息的攔截處理中判斷隱藏條件,而通過計時器的OnTimer事件處理隱現效果。在此隱藏條件是否滿足在兩個過程中的傳遞將成為關鍵。同時我們要知道的不僅是隱藏條件是否滿足,還必須知道窗體是在屏幕的那一邊上發生隱藏。為此,我們需要定義一個集合去描述窗體隱藏的位置,例如:

type

 HidePosKind = (hpTop,hpLeft,hPBottom,hpRight);

type

 THidePos = set of HidePosKind;

不過,類似的集合在Delphi本身就已經存在,譬如TAnchors集合。TAnchors集合原來是用於指明一個控件如何錨定於其父類控件的位置,我們在這裡則借用來描述窗體對屏幕的隱藏位置。

在TAnchors集合中也包含了四個值,其定義如下:

type TAnchorKind = (akTop, akLeft, akRight, akBottom);

type TAnchors = set of TAnchorKind;

在代碼的實現中,我們將定義一個TAnchors類型的全局變量FAnchors去描述窗體隱藏的位置。

三、初步的實現

首先我們定義一個過程對WM_MOVING消息進行攔截處理,代碼如下:

 

..
            private
             FAnchors: TAnchors;
            procedure WMMOVING(var Msg: TMessage); message WM_MOVING;
             ..
             uses Math,type;
            procedure TForm1.WMMOVING(var Msg: TMessage);
            begin
             inherited;
             with PRect(Msg.LParam)^ do
             begin
              Left := Min(Max(0, Left), Screen.Width - Width);
              Top := Min(Max(0, Top), Screen.Height - Height);
              Right := Min(Max(Width, Right), Screen.Width);
              Bottom := Min(Max(Height, Bottom), Screen.Height);
              FAnchors := [];
              if Left = 0 then Include(FAnchors, akLeft);
              if Right = Screen.Width then
               Include(FAnchors, akRight);
              if Top = 0 then Include(FAnchors, akTop);
              if Bottom = Screen.Height then
               Include(FAnchors, akBottom);
               Timer1.Enabled := FAnchors <> [];
              end;
            end;

在該過程中,我們通過對矩形參數Left、Top、Right、Bottom的判斷確定窗體所處位置是否符合隱藏條件,判斷結果存放在全局變量Fanchors之中。當觸發隱藏時,在Fanchors中將至少有一個值而不多於兩個值。(為什麼呢?)

判斷條件的設置似乎和我們一般的理解有點不同。以Left參數的判斷為例,在判斷了Max(0, Left)之後還為什麼一定要與Screen.Width-Width 的值再作比較呢?這其實是為了對一些較為極端的情況(例如窗體的寬度大於屏幕寬度)所作的偽處理,大家如果有興趣的可自己試驗一下這些極端的效果。當然,如果我們的窗體限制了寬、高的最大值,那麼判斷也就可以簡化為我們最初的理解。

最後需要注意的是,代碼中出現的Left、Top、Right、Bottom都是RECT的參數,而Width和Height才是窗體Form1的屬性。

接下來我們要處理TTimer的OnTimer事件了。在WMMOVING過程中,當Fanchors不為空時,TTimer啟動;反之,TTimer關閉。OnTimer事件的代碼如下:

 

procedure TForm1.Timer1Timer(Sender: TObject);
             const
              cOffset = 2;
             begin
              if WindowFromPoint(Mouse.CursorPos) = Handle then
              begin
               if akLeft in FAnchors then Left := 0;
               if akTop in FAnchors then Top := 0;
               if akRight in FAnchors then
                Left := Screen.Width - Width;
               if akBottom in FAnchors then
                Top := Screen.Height - Height;
               end else
               begin
                if akLeft in FAnchors then Left := -Width + cOffset;
                if akTop in FAnchors then Top := -Height + cOffset;
                if akRight in FAnchors then
                 Left := Screen.Width - cOffset;
                if akBottom in FAnchors then
                 Top := Screen.Height - cOffset;
              end;
            end;

在這裡,我們首先定義

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved