I have a static control:
HWND hLabelControl=CreateWindowEx(WS_EX_CLIENTEDGE,"STATIC","",
WS_TABSTOP|WS_VISIBLE|WS_CHILD|SS_CENTER,0,0,24,24,
hwnd,(HMENU)hS1,GetModuleHandle(NULL),NULL);
I want when a button is pressed the color of the text in the static label to change to red for example.
How can I do this?
I know there is a
SetTextColor(
_In_ HDC hdc,
_In_ COLORREF crColor
);
function but I can't figure out how to get the HDC of the static control.
Thanks in advance.
EDIT:
This doesn't work:
HDC hDC=GetDC(hLabelControl);
SetTextColor(hDC,RGB(255,0,0));
Static controls send their parent a WM_CTLCOLORSTATIC message just before they paint themselves. You can alter the DC by handling this message.
case WM_CTLCOLORSTATIC:
if (the_button_was_clicked) {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, COLORREF(0xFF, 0x00, 0x00));
}
return ::GetSysColorBrush(COLOR_WINDOW); // example color, adjust for your circumstance
So the trick is to get the static control to repaint itself when the button is clicked. You can do this several different ways, but the simplest is probably to invalidate the window with InvalidateRect.
Related
I want to draw a simple square on a button.
I created a regular window and a regular button in it. Now, in the window procedure of my window, in the WM_PAINT message, I get the HDC of my button and draw a square:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_PAINT)
{
PAINTSTRUCT ps;
HDC my_hdc = BeginPaint(hWnd, &ps);
//---------------------------------------------
HDC my_button_HDC = GetDC(GetDlgItem(hWnd, 11)); //Get HDC my button
Rectangle(my_button_HDC, 5, 5, 30, 30);
//---------------------------------------------
EndPaint(hWnd, &ps);
}
WinMain()
{
//standart code create window and button...
}
When creating a window, a square does not appear on the button. It appears ONLY when I move my window down outside of the screen and lift it up.
But, as soon as I resize the window or click on the button, the square disappears again.
I don't understand why this is happening.
You are drawing on the button only when its parent window is being painted (also, you are leaking the button's HDC). Resizing the window does not always trigger a repaint.
But even when it does, when the button itself paints itself, it will draw over anything you have already drawn.
The correct way to draw on a standard Win32 button is to either:
give the button the BS_OWNERDRAW style, and then have its parent window handle the WM_DRAWITEM message.
if ComCtl32.dll v6 is being used (see Enabling Visual Styles), the parent window can instead handle the NM_CUSTOMDRAW message, BS_OWNERDRAW is not needed. See Custom Draw for more details.
Upon color change, i listen to WM_CTLCOLORSTATIC and act accordingly:
LRESULT ProcessWindowMessage(_In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
switch (uMsg)
{
case WM_CTLCOLORSTATIC:
LRESULT lBrush = ::DefWindowProc(hWnd, uMsg, wParam, lParam); // get default brush used so far
::SetBkMode((HDC)wParam, TRANSPARENT);
::SetTextColor((HDC)wParam, RGB(m_color.red, m_color.green, m_color.blue));
return lBrush;
}
}
This works well with regular static-texts: labels and so on, but has no effect on regular radio buttons.
During my debugging attempts, I've tried listening to:
WM_DRAWITEM - doesn't receive any events
WM_CTLCOLORBTN - receive events only for regular push buttons( OK / CANCEL)
WM_CTLCOLOREDIT - doesn't receive any events.
I'm subclassing to another window not generated / created by me, but constructed by my process.
#igal k said SetWindowTheme does not work. Since the comment is not enough for the sample code. I post it as an answer.
First the result.
Code:
OnInitDialog:
::SetWindowTheme(GetDlgItem(IDC_RADIO1)->GetSafeHwnd(), L"wstr", L"wstr");
HBRUSH CMFCApplication1Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
// Call the base class implementation first! Otherwise, it may
// undo what we're trying to accomplish here.
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// Are we painting the IDC_MYSTATIC control? We can use
// CWnd::GetDlgCtrlID() to perform the most efficient test.
if (pWnd->GetDlgCtrlID() == IDC_RADIO1)
{
// Set the text color to red
pDC->SetTextColor(RGB(255, 0, 0));
// Set the background mode for text to transparent
// so background will show thru.
pDC->SetBkMode(TRANSPARENT);
// Return handle to our CBrush object
hbr = m_brush;
}
return hbr;
}
If you are interested to draw the full radio button, what you have to do is set a custom window proc for the radio button.In that proc you get the WM_PAINT and WM_ERASEBKGND messages.
In the erase background you can just fill the background color for the control.
In WM_PAINT you do the drawing of the control , get the window text of the control and do a DrawText with color set to whatever you need using SetTextColor
Draw an image of radio (circle and a dot inside).You can get all the state variables of the control and draw according to it, like whether its selected it or not. Whenever you need a repaint, ie new text is set, just call invalidateRect to force a repaint..
i would like to copy entire client window size of some window to my HDC, but when the window is minimized the source of all color bits is always empty RGB(0,0,0);
How to do this without activating the window?
You can use this function:
BOOL PrintWindow(
HWND hwnd,
HDC hdcBlt,
UINT nFlags);
http://msdn.microsoft.com/en-us/library/dd162869%28v=vs.85%29.aspx
I have created a customized static window which displays a bitmap image, this window is the child window of some other window. Now I want to capture mouse events for this window, so that I can provide functionality to crop the image.
But the problem is Mouse events are not passed to this child window....
following is a code snippet of the WndProc of child window ..
WNDPROC origStatProc;
// Variable which stores the handle of BITMAP image
HBITMAP hBitmap=NULL;
LRESULT CALLBACK dispWndProc(HWND hwnd,UINT msg, WPARAM wParam, LPARAM lParam)
{
static HDC hdc;
static PAINTSTRUCT paintSt;
static RECT aRect;
switch(msg)
{
case WM_PAINT:
{
hdc = BeginPaint(hwnd,&paintSt);
GetClientRect(hwnd,&aRect);
if(hBitmap!=NULL)
{
HDC memDC = CreateCompatibleDC(hdc);
if(memDC!=NULL)
{
BITMAP bmp;
GetObject(hBitmap,sizeof(bmp),&bmp);
SelectObject(memDC,hBitmap);
SetStretchBltMode(hdc,HALFTONE);
StretchBlt(hdc,0,0,aRect.right,aRect.bottom,
memDC,0,0,bmp.bmWidth,bmp.bmHeight,
SRCCOPY);
DeleteObject(&bmp);
ReleaseDC(hwnd,memDC);
}
}
// the code for painting
EndPaint(hwnd,&paintSt);
}
break;
case STM_SETIMAGE:
{
InvalidateRect(hwnd,&aRect,true);
}
break;
case WM_LBUTTONDOWN:
{
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
char xstr[10];
_itoa(xPos,xstr,10);
MessageBox(NULL,xstr,"X Value ",MB_OK);
}
break;
default:
return origStatProc(hwnd,msg,wParam,lParam);
}
return 0;
}
Can anyone tell me what else I need to capture mouse events inside this Child window...
The window class that you use for the window will determine certain default behaviors for the window. The Static window class is particularly difficult to work with, because Windows makes assumptions that the window will never change its contents, and won't interact with the user in any way. You'll probably find that the WM_LBUTTONDOWN is being passed to the parent window.
If I remember correctly: static windows declare themselves to be 'invisible' to mouse clicks by returning HTTRANSPARENT in response to WM_NCHITTEST. Because of this, windows passes the mouse click on to the parent. If you want to process the mouse clicks in the statics, you'll need to also override this behavior to return HTCLIENT instead.
I have called DefWndProc() instead of origStatProc(hwnd,msg,wParam,lParam) and the problem is solved....
anyWays thanks to everyone....
Can you change the background of text in area of edit control that would stay static?
In the parent of the edit control, handle the WM_CTLCOLORSTATIC message, the wParam of this message is the HDC that the Edit control is about to draw with,
for most CTLCOLOR messages, if you set text and background colors into this DC, the control will use the colors you set.
You can also return an HBRUSH and the contol will use that for any brush painting that it wil do, but many controls don't use brushes much, so that will have limited effect for some
CTLCOLOR messages. Your best bet here is to return the DC brush, and set the DC Brush color to match the BkColor of the DC.
LRESULT lRet = 0; // return value for our WindowProc.
COLORREF crBk = RGB(255,0,0); // use RED for Background.
...
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)wParam;
HWND hwnd = (HWND)lParam;
// if multiple edits and only one should be colored, use
// the control id to tell them apart.
//
if (GetDlgCtrlId(hwnd) == IDC_EDIT_RECOLOR)
{
SetBkColor(hdc, crBk); // Set to red
SetDCBrushColor(hdc, crBk);
lRet = (LRESULT) GetStockObject(DC_BRUSH); // return a DC brush.
}
else
{
lRet = DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
break;
WM_CTLCOLORSTATIC is for static text control.
To be simple, you can do this in your winproc:
...
case WM_CTLCOLOREDIT:
{
HDC hdc = (HDC)wParam;
SetTextColor(hdc, yourColor); // yourColor is a WORD and it's format is 0x00BBGGRR
return (LRESULT) GetStockObject(DC_BRUSH); // return a DC brush.
}
...
If you have more than 1 edit control, you can use the item id and lParam to check which one need to be change.
WM_CTLCOLOREDIT allows you to set text and background color(+brush), if you want more control than that, you have to subclass and paint yourself
you could do something like this:
CBrush bkBrush;
RECT ctrlRect;
COLORREF crBk = RGB(255,0,0); // Red color
bkBrush.CreateSolidBrush(crBk);
CWnd* pDlg = CWnd::GetDlgItem(IDC_EDIT);
pDlg->GetClientRect(&ctrlRect);
pDlg->GetWindowDC()->FillRect(&ctrlRec, &bkBrush);
pDlg->GetWindowDC()->SetBkColor(crBk);
This should change the background color of the edit control
All you need is to set the required color in control's device context and pass an HBRUSH with same color in WM_CTLCOLOREDIT message. If you want to change both foreground & background colors, use SetTextColor t0 change the text color. But you must pass the background color HBRUSH. But if you want to change the text color only, then you must pass a DC_BRUSH with GetStockObject function.