Delphi下QQ窗體自動隱藏探索--2(轉帖)

導讀:
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; 在這裏,我們首先定義一個常量cOffset去表示窗體隱藏後顯露部分的大小。然後我們利用WindowFromPoint這個Windows API函數檢測鼠標是否位於窗體之上。接下來的判斷就是處理在顯示和隱藏狀態下窗體Left 和Top 屬性值的設置。注意,針對Fanchors中存在不同值的情況,窗體Left和Top的設置是各不相同的,但是這些設置只有順序上的差異而並沒有優先級別的差異。(爲什麼要提到這一點呢?) 最後需要注意的是:在本事件中Top、Left、Width和Height都是窗體Form1的屬性值。 好了,有關窗體隱藏的核心代碼已經介紹完畢了,不過要達到預期效果,窗體Form1在創建時還必須做一些準備工作,代碼如下: procedure TForm1.FormCreate(Sender: TObject);
begin
Timer1.Enabled := False;
Timer1.Interval := 200;
FormStyle := fsStayOnTop;
end; 這裏的代碼相對簡單,不過值得指出的是對Form1的FormStyle 屬性的設置。FormStyle 爲fsStayOnTop時可保證Form1始終位於最前顯示。從效果角度看,當系統工具欄爲“總在最前顯示”時是最爲明顯的,因爲若窗體移動到系統工具欄上時也不會被其所遮蓋。 四、進一步完善 上面的代碼已經基本實現了窗體的自動隱藏效果,但是我在介紹代碼的時候有兩個問題是被提出但沒有被解答的。 首先是爲什麼觸發隱藏時Fanchors中將至少有一個值而不多於兩個值呢?注意代碼中對Fanchors的賦值是通過四個判斷進行的, 那麼如果觸發隱藏的話,Fanchors中將毫無疑問會有一個值存在,但這種情況是針對隱藏發生在屏幕的四邊而言。當窗體被推入到屏幕的四角時,那麼Fanchors中便將會有兩個值存在。那此時窗體會隱藏到什麼地方呢? 實際的效果告訴我們,窗體會被隱藏到屏幕的四角上。此時若我們試圖讓窗體重新顯示,你便會發現窗體在不斷的閃爍。爲什麼呢?這就是第二個問題提出的原因了。因爲對窗體顯示或隱藏的處理是根據Fanchors中的值作出的。當Fanchors中有兩個值的時候,就將會引發對窗體屬性的兩次設置。而因爲設置語句只有順序差異而沒有優先級差異,那麼OnTimer事件中每次都會對窗體進行兩次的屬性值設置,從而導致我們看到閃爍的顯示效果。 怎麼去解決這個問題呢?我們再觀察一下QQ的處理。在2003 II版的QQ裏面,窗體的隱藏效果作了一定的調整:當窗體在屏幕左右兩邊隱藏時,它會自動充滿屏幕的左右兩邊且高度不可改變;當窗體脫離屏幕兩邊的隱藏區域後,窗體的大小會恢復爲隱藏前的大小,如圖五所示。(注意:窗體並非是完全充滿屏幕的兩邊。QQ在處理這個效果時可能只注意了系統工具欄總在最前顯示且位於屏幕下方的情況,所以其充滿的區域也只是屏幕頂端到系統工具欄上方的一段空間,如圖六所示。)這樣的處理可以令窗體即使被推入到屏幕四角,也可以保證只會對其中的一個隱藏方向進行處理,從而避免了前面出現的閃爍現象。
200572194132712.gif
        圖五 Q Q 窗體自動充滿屏幕兩邊
200572194134163.gif
        圖六 Q Q 窗體自動充滿屏幕兩邊的漏洞 結合前面的分析,要實現如上的效果還是從攔截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 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,AppBar
        本文轉自
http://www.cnsoft.cn/Exploiture/Programme/Delphi/200507/4335_2.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章