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

C++Builder 繪圖於 Windows 開始按鈕技術解析

     編輯:關於C++

前言:探索任務列內部結構

Windows 任務列 是一個標準應用程式,由多個子視窗組成。本文示範如何在 C++Builder 中定位「開始」按鈕視窗,並利用 GDI 將滑鼠游標周圍的桌面畫面即時複製繪製至按鈕上,形成「透視」視覺效果。此技術屬於進階視窗操作範疇,僅供教學研究使用,實際部署需考慮系統相容性與使用者體驗。

任務列視窗階層架構

使用 Spy++ 可觀察到以下關鍵視窗結構:

  • 任務列主視窗:類別名 Shell_TrayWnd
  • 開始按鈕:類別名 Button,為 Shell_TrayWnd 的子視窗

核心 API 序列

  1. FindWindow("Shell_TrayWnd", NULL) → 取得任務列句柄
  2. FindWindowEx(hTray, 0, "Button", NULL) → 取得開始按鈕句柄
  3. GetDC(hStartBtn) → 取得按鈕裝置內容 (DC)
  4. GetDC(GetDesktopWindow()) → 取得桌面 DC
  5. GetCursorPos(&pt) → 取得滑鼠座標
  6. StretchBlt(hBtnDC, 0,0,60,25, hDeskDC, pt.x-30,pt.y-12,60,25, SRCCOPY) → 將滑鼠周圍 60x25 區域拉伸繪製至按鈕
  7. ReleaseDC → 釋放 DC

完整實作程式碼

表單建立:初始化 DC 與定時器


void __fastcall TForm1::FormCreate(TObject *Sender) {
    Application->MessageBox(
        "C++Builder 繪圖於開始按鈕示範程式", 
        "說明", MB_OK | MB_DEFBUTTON1);
    
    // 1. 取得任務列視窗
    HWND hTray = FindWindow("Shell_TrayWnd", NULL);
    // 2. 取得開始按鈕 (Shell_TrayWnd 的第一個 Button 子視窗)
    HWND hStart = FindWindowEx(hTray, 0, "Button", NULL);
    
    // 3. 取得並保存 DC (需在 FormDestroy 釋放)
    hdcButton = GetDC(hStart);
    hdcDesktop = GetDC(GetDesktopWindow());
    
    // 4. 設定高頻定時器 (1ms ≈ 1000 FPS,實際受 GDI 限制)
    Timer1->Enabled = false;
    Timer1->Interval = 1;
    BitBtn1->Tag = 0; // 0=停止, 1=執行
    BitBtn1->Caption = "開始繪圖";
}

按鈕控制:啟動/停止定時器


void __fastcall TForm1::BitBtn1Click(TObject *Sender) {
    if (BitBtn1->Tag == 0) {
        Timer1->Enabled = true;
        BitBtn1->Caption = "結束繪圖";
        BitBtn1->Tag = 1;
    } else {
        Close(); // 關閉表單將觸發 FormDestroy 釋放資源
    }
}

定時器事件:核心繪圖邏輯


void __fastcall TForm1::Timer1Timer(TObject *Sender) {
    TPoint pt;
    GetCursorPos(&pt); // 取得螢幕座標
    
    // 將桌面 (滑鼠中心 60x25) 複製到開始按鈕 (60x25)
    StretchBlt(
        hdcButton,           // 目標 DC
        0, 0, 60, 25,        // 目標矩形
        hdcDesktop,          // 來源 DC
        pt.x - 30, pt.y - 12, // 來源矩形左上角 (置中滑鼠)
        60, 25,              // 來源寬高
        SRCCOPY              // 光柵操作:直接複製
    );
}

資源清理:釋放 DC


void __fastcall TForm1::FormDestroy(TObject *Sender) {
    if (hdcButton) ReleaseDC(FindWindowEx(FindWindow("Shell_TrayWnd",NULL),0,"Button",NULL), hdcButton);
    if (hdcDesktop) ReleaseDC(GetDesktopWindow(), hdcDesktop);
}

關鍵技術細節解析

1. 座標系對應

  • GetCursorPos 回傳**螢幕座標**
  • GetDC(GetDesktopWindow()) 的座標原點也是螢幕左上角
  • GetDC(hStartBtn) 的座標原點是**按鈕客戶區左上角**
  • StretchBlt 同時指定目標與來源矩形,自動處理縮放與座標轉換

2. 視窗版本差異

3. 效能與閃爍

  • Interval = 1 極高頻率會佔用大量 CPU,實務建議 30-60ms (16-30 FPS)
  • 直接在按鈕 DC 繪圖會導致閃爍,雙緩衝技術難以套用於外部視窗
  • 現代系統啟用 DWM 合成後,GDI 繪圖可能被重導向至表面,效果不可預期

4. 安全性與權限

  • 需要目標進程 (explorer.exe) 相同或更高完整性等級
  • UAC 啟用時,非管理員進程無法取得系統進程 DC
  • Windows 10+ 可能阻擋跨進程 GetDC/StretchBlt

現代替代方案

若需自訂任務列外觀,建議採用官方支援途徑:

  • 應用程式使用者模型 ID (AppUserModelID):自訂跳躍清單、圖示覆疊
  • 任務列縮圖預覽 (Thumbnail Toolbars):ITaskbarList3 介面
  • 通知區域圖示:Shell_NotifyIcon (參考前文)
  • 桌面工具列:實作 IDeskBand 延伸任務列功能

結語

本文展示的技術屬於「非文件化、非支援」的系統程式設計手法,雖具教學價值但不適合生產環境。現代 Windows 開發應遵循官方 SDK 指引,利用任務列擴充介面實作豐富互動,確保跨版本相容性、安全性與使用者體驗一致性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
作業系統開始按鈕特徵備註
Windows 95/98/NT/2000單一 Button 子視窗本範例適用
Windows XP佈景主題化,可能非標準 Button需啟用視覺樣式或改用主題 API
Vista/7/8/10/11任務列重寫 (DWM 合成),開始按鈕為獨立視窗FindWindowEx 可能失效,需枚舉子視窗配合類別名/樣式過濾