MFC - change text color of a cstatic text control
Asked Answered
N

6

19

How do you change the text color of a CStatic text control? Is there a simple way other that using the CDC::SetTextColor?

Nerty answered 28/10, 2009 at 11:9 Comment(0)
S
35

You can implement ON_WM_CTLCOLOR in your dialog class, without having to create a new CStatic-derived class:

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    //{{AFX_MSG_MAP(CMyDialog)
    ON_WM_CTLCOLOR()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd *pWnd, UINT nCtlColor)
{
    switch (nCtlColor)
    {
    case CTLCOLOR_STATIC:
        pDC->SetTextColor(RGB(255, 0, 0));
        return (HBRUSH)GetStockObject(NULL_BRUSH);
    default:
        return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    }
}

Notice that the code above sets the text of all static controls in the dialog. But you can use the pWnd variable to filter the controls you want.

Selfconceit answered 29/10, 2009 at 13:21 Comment(6)
You are right. This is another way to do it. I just mentioned the way I think is better. In this second case you have to add the code to every dialog you want to display the labels in other color.Forlorn
Yes, I agree, in this case your way is the better way. My way could be used if someone wants to do a major revamping in the entire dialog (or application).Selfconceit
The return (HBRUSH)GetStockObject(NULL_BRUSH); will cause a painting issue (or a funky transparent background 'feature'). You probably want to return (HBRUSH)GetStockObject(WHITE_BRUSH);Deliberative
@Jack Bolding: Thanks for the comment. Can you share why WHITE_BRUSH would be preferred over NULL_BRUSH, or is it simply that any non-NULL brush is preferred? Thanks again.Emblazon
@Emblazon -- No, white isn't special. Any non-NULL brush would be fine.Deliberative
Following these instructions plus @JackBolding 's suggestion gave me a white background behind the control. I solved this as follows: First, call the base class version of OnCtlColor() (no matter what) and store the returned HBRUSH in a variable. Next, if appropriate, call pDC->SetTextColor(). Finally, return the brush from the first step.Shelled
F
8

unfortunately you won't find a SetTextColor method in the CStatic class. If you want to change the text color of a CStatic you will have to code a bit more.

In my opinion the best way is creating your own CStatic-derived class (CMyStatic) and there cacth the ON_WM_CTLCOLOR_REFLECT notification message.

BEGIN_MESSAGE_MAP(CMyStatic, CStatic)
    //{{AFX_MSG_MAP(CMyStatic)
    ON_WM_CTLCOLOR_REFLECT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

HBRUSH CColorStatic::CtlColor(CDC* pDC, UINT nCtlColor) 
{
    pDC->SetTextColor(RGB(255,0,0)); 

    return (HBRUSH)GetStockObject(NULL_BRUSH);  
}

Obviously you can use a member variable and a setter method to replace the red color (RGB(255,0,0)).

Regards.

Forlorn answered 28/10, 2009 at 13:46 Comment(1)
Thanks for your solution. It works with some unexpected side effect. Now my static control has different control background colour from my main view, also, text background is white.Cheshire
H
8

Just a follow up to the painting issue (a transparent background), which caused by *return (HBRUSH)GetStockObject(NULL_BRUSH);*

Easy change as below:

HBRUSH hBrush = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

if (nCtlColor == CTLCOLOR_STATIC &&
    pWnd->GetSafeHwnd() == GetDlgItem(XXX)->GetSafeHwnd()
) pDC->SetTextColor(RGB(255, 0, 0));    

return hBrush;

Hope this helps.

Hispid answered 1/7, 2013 at 5:57 Comment(1)
CDialog::OnCtlColor yields error C2248: 'CWnd::OnCtlColor': cannot access protected member declared in class 'CWnd'.Millican
C
5

From the Answers given here and other places, it was not obvious how to create a derived class to be used instead of CStatic that handles coloring itself.

So following is what works for me, using MSVS 2013 Version 12.0.40629.00 Update 5. I can place a "Static Text"-control in the resource editor, then replace the type of the member variable with TColorText.

In the .h-file:

class TColorText : public CStatic
{
protected:
  DECLARE_MESSAGE_MAP( )

public:
  // make the background transparent (or if ATransparent == true, restore the previous background color)
  void setTransparent( bool ATransparent = true );
  // set background color and make the background opaque
  void SetBackgroundColor( COLORREF );
  void SetTextColor( COLORREF );

protected:
  HBRUSH CtlColor( CDC* pDC, UINT nCtlColor );

private:
  bool MTransparent = true;
  COLORREF MBackgroundColor = RGB( 255, 255, 255 );  // default is white (in case someone sets opaque without setting a color)
  COLORREF MTextColor = RGB( 0, 0, 0 );  // default is black. it would be more clean 
                                         // to not use the color before set with SetTextColor(..), but whatever...
};

in the .cpp-file:

void TColorText::setTransparent( bool ATransparent )
{
  MTransparent = ATransparent;
  Invalidate( );
}

void TColorText::SetBackgroundColor( COLORREF AColor )
{
  MBackgroundColor = AColor;
  MTransparent = false;
  Invalidate( );
}

void TColorText::SetTextColor( COLORREF AColor )
{
  MTextColor = AColor;
  Invalidate( );
}

BEGIN_MESSAGE_MAP( TColorText, CStatic )
  ON_WM_CTLCOLOR_REFLECT( )
END_MESSAGE_MAP( )

HBRUSH TColorText::CtlColor( CDC* pDC, UINT nCtlColor )
{
  pDC->SetTextColor( MTextColor );
  pDC->SetBkMode( TRANSPARENT );  // we do not want to draw background when drawing text. 
                                  // background color comes from drawing the control background.
  if( MTransparent )
    return nullptr;  // return nullptr to indicate that the parent object 
                     // should supply the brush. it has the appropriate background color.
  else
    return (HBRUSH) CreateSolidBrush( MBackgroundColor );  // color for the empty area of the control
}
Chiffchaff answered 31/8, 2015 at 9:28 Comment(0)
W
3

Very helpful.

https://msdn.microsoft.com/de-de/library/0wwk06hc.aspx

Alike to

HBRUSH hBrush = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if (nCtlColor == CTLCOLOR_STATIC &&
    pWnd->GetSafeHwnd() == GetDlgItem(XXX)->GetSafeHwnd()
) pDC->SetTextColor(RGB(255, 0, 0));    
return hBrush;
Wahkuna answered 12/7, 2016 at 10:12 Comment(0)
D
-2

I believe you can't return nullptr for a HBRUSH rather (HBRUSH)GetStockObject(NULL_BRUSH);

Diadem answered 26/8, 2022 at 23:30 Comment(6)
Is this meant to be a comment on https://mcmap.net/q/629396/-mfc-change-text-color-of-a-cstatic-text-control or on what did you try to comment?Jerad
Hi Gary Gray. Could you clarify on what you are trying to comment in this way? On one of the existing answers? On the question? Also, could you explain a little more about what you mean by this? Is there an error in an answer? Does it prevent that answer from working? Do you propose a fix for that problem? Can you maybe solve the problem described in the question?Jerad
seems I learnt something here... for years I've been returning the NULL_BRUSH for painting transparent backgrounds... this is not what you want here as any attempt to change the text won't be erased correctly. Returning NULL IS the correct thing. To get around my error I've been hiding it first ... changing the text and then showing again to get the parent to paint the background. Seems returning NULL does that for you. Again ... I leaned something :-)Diadem
Gary Gray. Please. Please turn this post into an answer. Do not insist that it is a comment. Please edit and answer according as much as possible to How to Answer. Please edit instead of putting what is a comment into the answer post and what finally seems an answer into a comment. Or if you still think that all of this is a comment and not an answer, please delete it.Jerad
. originally I wanted to comment on the previous answer, but the system wouldn't let me.... now I am responding to a question directed at me and my comment... not the original question. I was going to give more information of dealing with non plain backgrounds (bitmaps etc) but I really don't need to deal with this trivia. I won't post again.Diadem
If you do not think that your post is an answer to the question on this page then please delete it. Is there anything keeping you from deleting it? Is there anything keeping you from editing it into an answer? Or could you confirm that the edit which somebody else meanwhile did for you is Ok with you and reflects your intention?Jerad

© 2022 - 2024 — McMap. All rights reserved.