Can I change the colour of a CDialog and CFormView?

mwcmp
mwcmp used Ask the Experts™
on
Can I change the (bkgd) colour of a CDialog and CFormView? If so, how?
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Commented:
Hi!
You can handle WM_CTLCOLORDLG in the your dialog class
for example:

// m_BackBrush is the CBrush object member of the your class (NOTE it must be created in the construxtor or OnInitDialog methods)
HBRUSH CColoredDlg::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);
  if (nCtlColor == CTLCOLOR_DLG || CTLCOLOR_STATIC  == nCtlColor)
   return  (HBRUSH)m_BackBrush;

return hbr;
}

Author

Commented:
error C2065: 'CTLCOLOR_DLG' : undeclared identifier
warning C4018: '==' : signed/unsigned mismatch

Author

Commented:
BTW. I had created m_BackBrush as gobal as I do not get what you mean by creating it in the OnInitDialog.
What I mean is, I created it as:
CBrush m_BackBrush(RGB(255,0,0));

How then can I create it in OnInitDialog, but use it in OnCtlColor?
Learn Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

Commented:
You need to declare:

CBrush m_BackBrush;

in the class header, and then initialize it in OnInitDialog:

m_BackBrush.CreateSolidBrush( RGB(255,0,0) );

Commented:
Then it will be available in OnCtlColor

Commented:
 if (nCtlColor == (UINT) CTLCOLOR_DLG || (UINT) CTLCOLOR_STATIC  == nCtlColor)
   return  (HBRUSH)m_BackBrush;

Author

Commented:
Still the same error:
>error C2065: 'CTLCOLOR_DLG' : undeclared identifier

Do I need to include anything? BTW, I am using EVC.
Software Architect
Top Expert 2008
Commented:
in your dialog class declaration
   CBitmap m_bg;

in your dialog constructor:

    m_bg.CreateSolidBrush(RGB(255,127,127));        <---- red

Add OnCtrlColor handler:

HBRUSH CYourDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
      HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

      if (!m_bg.GetSafeHandle())
            return hbr;

      switch (nCtlColor) {
            //Edit controls need white background and black text
            //Note the 'return hbr' which is needed to draw the Edit
            //control's internal background (as opposed to text background)
            case CTLCOLOR_EDIT:
                  pDC->SetTextColor(RGB(0,0,0));
                  pDC->SetBkColor(RGB(255,255,255));
                  return hbr;
            //Static controls need black text and same background as m_brush
            case CTLCOLOR_STATIC:
                  LOGBRUSH logbrush;
                  fondo.GetLogBrush( &logbrush );
                  pDC->SetTextColor(RGB(0,0,0));
                  pDC->SetBkColor(logbrush.lbColor);
                  return m_bg;
                                // change background for some controls
            case CTLCOLOR_LISTBOX:
            case CTLCOLOR_SCROLLBAR:
            case CTLCOLOR_BTN:
            case CTLCOLOR_MSGBOX:
                                // change background for dialog itself
            case CTLCOLOR_DLG:
                  return m_bg;
            default:
                  return m_bg;
      }
}

Author

Commented:
>CBitmap m_bg;
Should this be CBrush? If so, I had changed it...

few errors>>
error C2065: 'fondo' : undeclared identifier
error C2228: left of '.GetLogBrush' must have class/struct/union type
error C2065: 'CTLCOLOR_SCROLLBAR' : undeclared identifier
error C2051: case expression not constant
error C2065: 'CTLCOLOR_DLG' : undeclared identifier
error C2051: case expression not constant

>fondo.GetLogBrush( &logbrush );
Should fondo be m_bg?
Jaime OlivaresSoftware Architect
Top Expert 2008

Commented:
Sorry, translating from my own code...
'fondo' must be m_bg.

Commented:
For a CFormview just handle the WM_ERASEBKGND message in the view class - OnEraseBkhgnd(CDC* pDC).
Here you get the DC of the view window.  You can then draw anything you want in this window.  For example - if you wanted to have a gradient background:

BOOL CMyView::OnEraseBkgnd(CDC* pDC)
{
   CView::OnEraseBkgnd(pDC);
   
   Brush pBrush[64];      // use 64 shades of cyan
   CRect rect,rectWnd;

   // Create brushes
   for( int i = 0; i < 64; i++ )
      pBrush[i].CreateSolidBrush( RGB( 0, 255 - (i * 4), 255 - (i * 4) ));
      
   CWnd* pWnd = pDC->GetWindow();
   pWnd->GetClientRect(&rectWnd);
   
   int nWidth = rectWnd.right;
   int nHeight = rectWnd.bottom;
      
   // Paint screen
   for( i=0; i < nHeight; i++ )
   {
      SetRect( &rect, 0, i, nWidth, i + 1);
      pDC->FillRect( &rect, &pBrush[ ( i * 63 ) / nHeight ] );
   }

   // release brushes to Windows
   for( i = 0; i < 64; i++ )
      DeleteObject( pBrush[i] );

   return TRUE;
}

Jim      

Author

Commented:
Hi Jim

>Brush pBrush[64];
This should be CBrush instead? As I get an error from it.

and also this error>>
>>error C2039: 'GetWindow' : is not a member of 'CDC'
        C:\Windows CE Tools\wce300\Pocket PC 2002\mfc\include\afxwin.h(590) : see declaration of 'CDC'
CWnd* pWnd = pDC->GetWindow();

Author

Commented:
Hi Jaime

error C2065: 'CTLCOLOR_SCROLLBAR' : undeclared identifier
error C2051: case expression not constant
 error C2065: 'CTLCOLOR_DLG' : undeclared identifier
error C2051: case expression not constant

Wat's the problem? Why  I keep having the same error...

Commented:
Yes, Brush should be CBrush.
When I look up the help for CDC, GetWindow() is a member function - at least in non-Windows CE land.  Is this your platform?
Jim

Author

Commented:
Win CE

Commented:
ok, well, then get the window from the view itself.
the this pointer is the pointer to the CWnd* of the view

CWnd* pWnd = (CWnd *) this;

Jim

Author

Commented:
my formView remains white..

Author

Commented:
Jim

Do you have any idea what went wrong?

Commented:
Try just calling GetClientRect() - you're already in the view class.  Remove the call to get the CWnd * - it's not necessary.
Can you step thru the code?  I don't have a WinCE setup so I don't know what it entails for debugging.
Jim

Author

Commented:
Ok. There is no error, but the view is still white.
Any more suggestion?

Commented:
Comment out the call to CView::OnEraseBkgnd(pDC) - although I don't know what affect that will have.
Jim

Author

Commented:
Haha. Still the same results.
Jaime OlivaresSoftware Architect
Top Expert 2008

Commented:
I think OnCtlColor is the proper way.

Author

Commented:
But the problem is I have all these errors

error C2065: 'CTLCOLOR_SCROLLBAR' : undeclared identifier
error C2051: case expression not constant
 error C2065: 'CTLCOLOR_DLG' : undeclared identifier
error C2051: case expression not constant
Jaime OlivaresSoftware Architect
Top Expert 2008
Commented:
don't know why is not defined but try with:
#define CTLCOLOR_DLG            4
#define CTLCOLOR_SCROLLBAR      5

Author

Commented:
Jaime
Ok. Thanks. It works now.
Can that piece of code work for CFormView too?
Jaime OlivaresSoftware Architect
Top Expert 2008

Commented:
Not tried, just do it.

Commented:
It must be a WinCE thing - because the code I gave you works on a Windows PC - Win2K.
Jim

Author

Commented:
It can't seems to work for view.
If that of a dialog is CTLCOLOR_DLG, what's the value for that o a view?

Author

Commented:
What is the equivlent of OnInitDialog for a view?

Commented:
OnInitialUpdate()

Commented:
Does WinCE send a WM_ERASEBKGND message?

Author

Commented:
>Does WinCE send a WM_ERASEBKGND message?
I suppose not.


OnCtlColor don't seems to work for view

Commented:
Can you debug your app in WinCE?
OnCtlColor is used for windows controls that are child controls of a window - doesn't get called when a view has no controls.

What if you try setting the the brush color to one color RGB(0,0,255) instead of multiple brushes...
Jim

Author

Commented:
Hmm.. Can't seems to work either

Author

Commented:
How abotu RedrawWindow or using a CStatic?
I read about people using them to change their view colour. But I tried and it still remains white. How should I use them?

Author

Commented:
void CGuiderView::OnDraw(CDC* pDC)
{
      CGuiderDoc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);
      
            CStatic myStatic;
      CRect rect;
      GetClientRect(&rect);
            int nX = rect.left;
            int nY = rect.top;
      myStatic.Create(NULL, WS_CHILD|WS_VISIBLE|SS_CENTER,
            CRect(0,0,nX,nY), this);

      CBrush bb(RGB(255,127,127));
      pDC->FillRect( &rect, &bb);
      myStatic.Invalidate() ;
}

And I manage to change the background colour of my view. But the problem is, the background of my button and static control did not change.
What should I do?
Commented:
mwcmp,

The pDC is the DC of your view - the controls are not affected.
To change the color of a static you need to handle the WM_CTLCOLOR message.  You return an HBRUSH from the call.  But in there you can check the id of the control and change its background.  Here is some code:

HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
   HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   switch (nCtlColor)      
   {
      case CTLCOLOR_STATIC:
         switch (pWnd->GetDlgCtrlID())
         {
            case IDC_WELCOMETEXT:
      SetStaticFont( pWnd, 6 );
                pDC->SetTextColor(RGB(0, 0, 255));
      break;
           
            default:
               break;
         }
      break;

      default:
         break;
    }

   // TODO: Return a different brush if the default is not desired
   return hbr;
}

This should do the trick.
Jim

Author

Commented:
What if I had used the code that you had posted, but only that it is in the OnDraw()

void CGuiderView::OnDraw(CDC* pDC)
{
      //CGuiderDoc* pDoc = GetDocument();
      //ASSERT_VALID(pDoc);
      
      CBrush pBrush[64];     // use 64 shades of cyan
      
      for( int i = 0; i < 64; i++ )
                     pBrush[i].CreateSolidBrush( RGB( 0, 255 - (i * 4), 255 - (i * 4) ));

      CRect rect,rectWnd;
      int nWidth, nHeight;

      GetClientRect(&rectWnd);

      nWidth = rectWnd.right;
      nHeight = rectWnd.bottom;

      for( i=0; i < nHeight; i++ )
      {
            SetRect( &rect, 0, i, nWidth, i + 1);
            pDC->FillRect( &rect, &pBrush[ ( i * 63 ) / nHeight ] );
      }

      for( i = 0; i < 64; i++ )
            DeleteObject( pBrush[i] );
}

for this, I cannot set them to gradient colour too, am I right?
the method that you had suggeted only change the colour of the controls into a single colour. Am I right?

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial