想知道螢幕上某個好看顏色的 RGB 值嗎?Windows GDI 提供極簡單的三步驟:取得螢幕 DC → 讀取游標位置像素 → 分解 RGB 分量。本文提供極精簡的 MFC 實作,可直接整合至專案或獨立執行。
void CScreenColorPicker::PickColor(COLORREF& rgbOut)
{
// 1. 取得全螢幕裝置內容
HDC hScreenDC = ::GetDC(NULL);
if (!hScreenDC) return;
// 2. 取得游標位置並讀取像素
CPoint pt;
::GetCursorPos(&pt);
COLORREF color = ::GetPixel(hScreenDC, pt.x, pt.y);
// 3. 釋放 DC 並分解 RGB
::ReleaseDC(NULL, hScreenDC);
rgbOut = color; // 呼叫端可用 GetRValue/GetGValue/GetBValue 取得分量
}
class CScreenColorPickerDlg : public CDialog
{
// 控制項:三個靜態文字顯示 R/G/B、一個顏色預覽矩形
CStatic m_stR, m_stG, m_stB, m_stPreview;
CButton m_btnStartStop;
BOOL m_bPicking = FALSE;
UINT m_nTimerID = 1;
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnBnClickedStartStop();
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CScreenColorPickerDlg, CDialog)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BTN_START_STOP, OnBnClickedStartStop)
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
void CScreenColorPickerDlg::OnTimer(UINT nIDEvent)
{
if (nIDEvent == m_nTimerID && m_bPicking)
{
COLORREF color;
PickColor(color);
// 更新介面
m_stR.SetWindowText(CString(_T("R: ")) + std::to_wstring(GetRValue(color)).c_str());
m_stG.SetWindowText(CString(_T("G: ")) + std::to_wstring(GetGValue(color)).c_str());
m_stB.SetWindowText(CString(_T("B: ")) + std::to_wstring(GetBValue(color)).c_str());
m_stPreview.Invalidate(); // 觸發 OnCtlColor 重繪預覽
}
CDialog::OnTimer(nIDEvent);
}
void CScreenColorPickerDlg::OnBnClickedStartStop()
{
m_bPicking = !m_bPicking;
if (m_bPicking)
{
SetTimer(m_nTimerID, 100, NULL); // 100ms 輪詢
m_btnStartStop.SetWindowText(_T("停止取色"));
}
else
{
KillTimer(m_nTimerID);
m_btnStartStop.SetWindowText(_T("開始取色"));
}
}
HBRUSH CScreenColorPickerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (pWnd->GetDlgCtrlID() == IDC_ST_PREVIEW)
{
pDC->SetBkMode(TRANSPARENT);
static CBrush brush;
brush.DeleteObject();
brush.CreateSolidBrush(m_lastColor); // 需保存上次取得的色彩
return brush;
}
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
| API | 用途 | 備註 |
|---|---|---|
GetDC(NULL) | 取得螢幕 DC | 對應 ReleaseDC(NULL, hDC) 釋放 |
GetCursorPos | 取得游標螢幕座標 | 以螢幕左上角為原點 |
GetPixel | 讀取指定座標像素色彩 | 回傳 COLORREF (0x00BBGGRR) |
GetRValue/G/BValue | 巨集分解 RGB 分量 | 定義於 windowsx.h |
OnPaint 以 StretchBlt 將游標周圍 20×20 區域放大 5 倍繪製於對話方塊。CString::Format(_T("#%02X%02X%02X"), R, G, B) 寫入剪貼簿。RegisterHotKey (如 Ctrl+Alt+P) 全域啟動/停止,無需切換視窗焦點。pt.x < GetSystemMetrics(SM_CXSCREEN) 等。三行核心 API 即可實作專業級螢幕取色器。理解 GetDC(NULL)、GetCursorPos、GetPixel 協作關係,不僅能快速開發取色工具,更是學習 GDI 底層繪圖管線的絕佳切入點。