Introduction
This program gets the color of pixels from the desktop, displays them in a window, and has a 4 - 1 magnifier. They can be later copied to the clipboard.
Background
This version is user friendly. The selected colors fill the five boxes. The associated button copies its color to the copy window in the format selected by the Select Format option. The buttons are initially disabled else the background color of the dialog window would be copied. Press Copy to sent this value to the clipboard.
I know, you will think this has been done before, even on this web site, but this is why I present this article: I subscribe to Lockergnome - a Windows Fanatics newsletter. Last week, they had a program for download, TakeColor. I wanted to see if I could pseudo reverse engineer it. Turned out to be somewhat challenging: TakeColor - flaxie.com.
Using the code
The elements:
- A menu.
- A window to display the color of the pixel.
- A zoom window (4 - 1 magnifier).
- Display HEX, HTML, or RGB.
- Mouse coordinates.
- List of selected colors.
- Five boxes to show the last five selected colors.
- Copy to clipboard.
Explanation
- The Menu, no biggy, used the resource editor. The first challenge was that the
ON_UPDATE_COMMAND_UI
does not work for non-system menus. This function toggles menu items. we can call it with ToggleMenuItem(0, 1)
. I hand coded the menu items and sub items, this call sets a check mark on the Options menu, Stay on Top. void CColorTakeDlg::ToggleMenuItem(int nMenu, int nPos)
{
CMenu *pMenu = GetMenu();
CMenu *pSubMenu = pMenu->GetSubMenu(nMenu);
UINT nID = pSubMenu->GetMenuItemID(nPos);
UINT nState = pSubMenu->GetMenuState(nID, MF_BYCOMMAND);
ASSERT(nState != 0xFFFFFFFF);
if(nState & MF_CHECKED)
pSubMenu->CheckMenuItem(nID, MF_UNCHECKED | MF_BYCOMMAND);
else
pSubMenu->CheckMenuItem(nID, MF_CHECKED | MF_BYCOMMAND);
}
- Display current color.
CDC *pSDC = m_current.GetDC();
CRect sRect;
m_current.GetClientRect(&sRect);
pSDC->FillSolidRect(&sRect, m_colCurrent);
ReleaseDC(pSDC);
- Zoom window.
if (bEnableZoom)
{
CDC *pDC = m_zoom.GetDC();
CRect m_rect;
m_zoom.GetClientRect(&m_rect);
InflateRect(&m_rect, -1, 0);
pDC->SetStretchBltMode(COLORONCOLOR);
pDC->StretchBlt(m_rect.left, m_rect.top,
m_rect.Width(), m_rect.Height(), pDesktopDC,
pt.x - m_nOffset, pt.y - m_nOffset,
m_nWidth, m_nWidth, SRCCOPY);
pen.DeleteObject();
pen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
CPen *pOldPen = pDC->SelectObject(&pen);
CPoint point;
point.x = m_rect.Width()/2;
point.y = m_rect.top;
pDC->MoveTo(point);
point.y = m_rect.bottom;
pDC->LineTo(point);
point.x = m_rect.left;
point.y = m_rect.Height()/2;
pDC->MoveTo(point);
point.x = m_rect.right;
pDC->LineTo(point);
pDC->SelectObject(pOldPen);
ReleaseDC(pDC);
}
- Display HEX, HTML, or RGB.
switch (m_nSelect)
{
case 0:
str.Format("%02X, %02X, %02X", rVal, gVal, bVal);
m_color.SetWindowText((LPCTSTR)str);
break;
case 1:
str.Format("#%02X%02X%02X", rVal, gVal, bVal);
m_color.SetWindowText((LPCTSTR)str);
break;
case 2:
str.Format("%d, %d, %d", rVal, gVal, bVal);
m_color.SetWindowText((LPCTSTR)str);
break;
}
- Mouse coordinates: this was quite a challenge, I used
SetCapture()
to get the cursor from the desktop. In the previous version, that was an error. void CColorTakeDlg::OnTimer(UINT nIDEvent)
{
HWND m_hwnd = ::GetDesktopWindow();
CString str;
POINT pt;
pt.x = pt.y = 0;
GetCursorPos(&pt);
str.Format("X: %d, Y: %d", pt.x, pt.y);
m_mouse.SetWindowText((LPCTSTR)str);
...
...
- List of selected colors.
CString str;
m_color.GetWindowText(str);
m_list1.InsertString(0, str);
UpdateData(FALSE);
- Five boxes to show the last five selected colors.
void CColorTakeDlg::CopyColor()
{
m_nColor[4] = m_nColor[3];
m_nColor[3] = m_nColor[2];
m_nColor[2] = m_nColor[1];
m_nColor[1] = m_nColor[0];
m_nColor[0] = m_colCurrent;
DrawColorBoxes();
}
- Copy to clipboard.
void CColorTakeDlg::OnCopy()
{
m_edit1.SetSel(0, -1);
m_edit1.Copy();
}
Points of Interest
This program uses the CHotKeyCtrl
class to copy the selected color to the list and the first box. The function void GetHotKey( WORD &wVirtualKeyCode, WORD &wModifiers ) const;
is used to get the hot key from the control. wVirtualKeyCode
is the keyboard key (A - Z) pressed and wModifiers
are the control keys (Shift, Ctrl, Alt, and the Windows key). The modifier flags defined in CommCtrl.h can be a combination of the following values:
#define HOTKEYF_SHIFT 0x01
#define HOTKEYF_CONTROL 0x02
#define HOTKEYF_ALT 0x04
#define HOTKEYF_EXT 0x08
Then the hot key has to be registered using:
BOOL RegisterHotKey(
HWND hWnd,
int id,
UINT fsModifiers,
UINT vk
);
The values for fsModifiers
are defined in WinUser.h.
#define MOD_ALT 0x0001
#define MOD_CONTROL 0x0002
#define MOD_SHIFT 0x0004
#define MOD_WIN 0x0008
As you can see, the values are not the same, so I have:
void CColorTakeDlg::OnNewHotkey()
{
UnregisterHotKey(m_hWnd, HOTKEYID);
m_hotkey1.GetHotKey(wVirtualKeyCode, wModifiers);
switch(wModifiers)
{
case HOTKEYF_SHIFT:
fsModifiers = MOD_SHIFT;
break;
case HOTKEYF_CONTROL:
fsModifiers = MOD_CONTROL;
break;
case HOTKEYF_ALT:
fsModifiers = MOD_ALT;
break;
case HOTKEYF_EXT:
fsModifiers = MOD_WIN;
break;
}
RegisterHotKey(m_hWnd, HOTKEYID, fsModifiers, wVirtualKeyCode);
}
These are only four combinations, I didn't want to allow all 16, so I used SetRules()
.
m_hotkey1.SetHotKey(0x43, HOTKEYF_ALT);
m_hotkey1.SetRules(HKCOMB_CA | HKCOMB_SA | HKCOMB_SC |
HKCOMB_SCA | HKCOMB_NONE, HOTKEYF_ALT);
RegisterHotKey(m_hWnd, HOTKEYID, MOD_ALT, 0x43);
wVirtualKeyCode = 0x43;
wModifiers = HOTKEYF_ALT;
fsModifiers = MOD_ALT;
You want it zany, then position the cursor in the magnifier window. When you get close to the cross-hairs which are 1 pixel wide, you will see in the window they are 4 pixels wide. If you get closer, then 16 pixels wide. About the time they get 64 pixels wide, the window will turn red.
Warning
If you use this program on older versions of Windows, Win95/Win98, and the zoom window fails to function, then you have a problem. The GDI resource causes StretchBlt(...)
to return FALSE
: see the MSDN Knowledge base article.
History
- 19 March 2005 - Version 1.0.
- 25 March 2005 - Version 1.1 - New thread method.
- 31 March 2005 - Version 1.2 - Fixed error, added marker for Selected.
- 22 November 2005 - Version 1.3 - New method for zoom.
- 04 December 2005 - Version 1.4 - The final version, user friendly.