首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

深度解析 QQ 視窗邊緣自動隱藏機制:WM_MOVING、WM_SIZING 與系統工具列協同處理

     編輯:Delphi

現象觀察

拖曳 QQ 主視窗至螢幕邊緣時,拖曳矩形(虛線框)會在超出瞬間被「吸附」鎖定,釋放滑鼠後視窗自動縮入僅露邊緣條;滑鼠移入條區視窗彈出,移出再隱藏。此行為涉及拖曳階段攔截、工作列避讓、角落閃爍修正、尺寸鎖定等多層邏輯。

關鍵消息與結構

  • WM_MOVING:拖曳矩形移動中,LPARAM 指向 RECT(矩形座標),可即時修改限制範圍。
  • WM_SIZING:縮放矩形中,同樣可攔截修正尺寸。
  • SHAppBarMessage:ABM_GETTASKBARPOS 取得工作列位置(ABE_TOP/LEFT/RIGHT/BOTTOM)與矩形,計算可用工作區高度/寬度。

核心邏輯流程

  1. WMMoving:
    • 限制 RECT 不超出螢幕邊界。
    • 判斷矩形是否貼邊(Left=0、Right=Screen.Width 等),記錄至 FAnchors: TAnchors。
    • 若同時貼左右或上下(角落),參考 QQ 策略:優先處理水平隱藏,強制延伸視窗高度至工作列邊界(SetBarHeight),鎖定垂直座標並 Exit 防止垂直邏輯介入導致閃爍。
    • 記錄隱藏前寬高(Lst_W, Lst_H),標記 Rec_Pos。
    • 啟用/停用 Timer。
  2. Timer (Interval=200):
    • WindowFromPoint(Mouse.CursorPos) = Handle 判斷滑鼠是否在視窗/觸發區上。
    • 在視窗上 → 還原至螢幕內座標(Left=0 或 Right=Screen.Width-Width),同步恢復高度。
    • 不在視窗上 → 移至隱藏座標(Left=-Width+Offset),保持高度鎖定。
  3. WMSizing:隱藏狀態下(FAnchors 含水平邊)強制 RECT 高度等於 Cur_Bottom - Cur_Top,寬度固定,防止使用者拖曳破壞觸發區。
  4. SetBarHeight:呼叫 SHAppBarMessage 取得工作列狀態與位置,計算 Cur_Top, Cur_Bottom 供隱藏/彈出時使用。

關鍵程式碼節錄

procedure TForm1.WMMoving(var Msg: TMessage);
var R: PRect;
begin
  inherited;
  R := Msg.LParam;
  // ... 限制座標、建立 FAnchors ...

  // 角落閃爍修正:水平隱藏優先
  if (akLeft in FAnchors) or (akRight in FAnchors) then
  begin
    if (R.Left > 0) and (R.Right < Screen.Width) then // 拖出
    begin
      if Rec_Pos then begin Width := Lst_W; Height := Lst_H; Rec_Pos := False; end;
    end
    else // 吸附隱藏
    begin
      if not Rec_Pos then begin Lst_W := Width; Lst_H := Height; Rec_Pos := True; end;
      SetBarHeight;
      R.Top := Cur_Top; R.Bottom := Cur_Bottom;
      Exit;
    end;
  end;
  Timer1.Enabled := FAnchors <> [];
end;

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

效果對照圖

拖曳矩形 吸附隱藏 彈出 延伸高度

工程啟示

  • 視窗邊緣隱藏屬於「非標準視窗行為」,需完整掌握 WM_MOVING/SIZING、SHAppBarMessage、計時器輪詢、狀態機設計。
  • 多螢幕、DPI 縮放、工作列自動隱藏/鎖定/垂直佈局等情境皆需實測調適。
  • 現代 Windows 建議使用 DWM 縮圖預覽、AppBar 官方 API 實現類似功能,相容性更佳。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved