QQ 的截圖工具體驗極佳:全螢幕半透明遮罩、滑鼠拖曳選取區域、即時顯示座標與尺寸、支援鍵盤微調。本文完整拆解其核心架構,並提供 MFC 對話框為基礎的實作範例。
CopyScreenToBitmap),存在 CBitmap 中。OnEraseBkgnd 將該位圖繪製到對話框客戶區,使用者看到的彷彿就是真實桌面。CRectTracker 繪製「橡皮筋」選取框,並攔截滑鼠/鍵盤訊息實作拖曳、縮放、微調。CCatchScreenDlg::CCatchScreenDlg()
{
// 橡皮筋樣式:實線、可內部縮放
m_rectTracker.m_nStyle = CRectTracker::resizeInside | CRectTracker::solidLine;
m_rectTracker.m_rect.SetRect(-1, -1, -1, -1);
m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);
// 取得螢幕解析度
m_xScreen = GetSystemMetrics(SM_CXSCREEN);
m_yScreen = GetSystemMetrics(SM_CYSCREEN);
// 截取全螢幕到位圖
CRect rect(0, 0, m_xScreen, m_yScreen);
m_pBitmap = CBitmap::FromHandle(CopyScreenToBitmap(&rect));
// 區域更新用
m_rgn.CreateRectRgn(0, 0, 50, 50);
}
OnInitDialog:設定全螢幕置頂BOOL CCatchScreenDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetWindowPos(&wndTopMost, 0, 0, m_xScreen, m_yScreen, SWP_SHOWWINDOW);
// 將提示編輯框移至左上角
CRect rc; m_tipEdit.GetWindowRect(&rc);
m_tipEdit.MoveWindow(10, 10, rc.Width(), rc.Height());
DrawTip(); // 顯示操作提示
return TRUE;
}
OnEraseBkgnd:以桌面位圖填充背景BOOL CCatchScreenDlg::OnEraseBkgnd(CDC* pDC)
{
CDC dcMem; dcMem.CreateCompatibleDC(pDC);
CBitmap* pOld = dcMem.SelectObject(m_pBitmap);
pDC->BitBlt(0, 0, m_xScreen, m_yScreen, &dcMem, 0, 0, SRCCOPY);
dcMem.SelectObject(pOld);
return TRUE; // 已自行處理背景,阻止預設擦除
}
CTracker 消除虛線框閃爍繼承 CRectTracker,覆寫 DrawTrackerRect 直接 InvalidateRgn 更新區域,避免預設 XOR 繪圖造成的殘影。
CMyEdit:滑鼠移動時在左右上角切換位置void CMyEdit::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rc; GetWindowRect(&rc);
int xScreen = GetSystemMetrics(SM_CXSCREEN);
if (m_bMove) { MoveWindow(10, 10, rc.Width(), rc.Height()); m_bMove = FALSE; }
else { MoveWindow(xScreen - 180, 10, rc.Width(), rc.Height()); m_bMove = TRUE; }
CEdit::OnMouseMove(nFlags, point);
}
DrawMessage根據滑鼠位置動態計算文字區域,遇到螢幕邊緣自動翻轉,確保資訊框永遠可見。
PaintWindow:排除提示框避免閃爍void CCatchScreenDlg::PaintWindow()
{
CRect rcDlg, rcTip; GetWindowRect(&rcDlg); m_tipEdit.GetWindowRect(&rcTip);
CRgn rgnAll, rgnTip, rgnDiff;
rgnAll.CreateRectRgnIndirect(&rcDlg);
rgnTip.CreateRectRgnIndirect(&rcTip);
rgnDiff.CombineRgn(&rgnAll, &rgnTip, RGN_DIFF); // 差集 = 全螢幕 - 提示框
InvalidateRgn(&rgnDiff);
}
ProcessMessageFilter 攔截方向鍵在 CWinApp 衍生類別中覆寫 ProcessMessageFilter,檢查 WM_KEYDOWN 與 VK_SHIFT 組合,決定移動整個選框或單邊縮放,並呼叫 PaintWindow 重繪。
專案包含:CCatchScreenApp(訊息過濾)、CCatchScreenDlg(主邏輯)、CTracker(橡皮筋)、CMyEdit(提示框)、CopyScreenToBitmap(螢幕截圖工具函式)。所有繪圖均使用 GDI,無需 DirectX/OpenGL,相容性極佳。
掌握「全螢幕截圖當背景 + 區域更新 + Tracker 選取」這套模式,即可快速開發專業級截圖工具。完整原始碼請參考文章附件。